package com.wowza.wms.plugin.livestreamrecord;
import java.io.*;
import java.util.*;
import com.wowza.wms.application.IApplicationInstance;
import com.wowza.wms.http.*;
import com.wowza.wms.logging.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.stream.mediacaster.MediaStreamMediaCasterUtils;
import com.wowza.wms.vhost.IVHost;
import com.wowza.wms.vhost.StreamItem;
import com.wowza.wms.vhost.StreamList;
import com.wowza.wms.plugin.integration.liverecord.*;

public class HTTPLiveStreamRecord extends HTTProvider2Base {
	
	public static final int FORMAT_UNKNOWN = 0;
	public static final int FORMAT_FLV = 1;
	public static final int FORMAT_MP4 = 2;
	
	private Map<String, ILiveStreamRecord> recorders = new HashMap<String, ILiveStreamRecord>();
	private IApplicationInstance appInstance = null;


	public void onHTTPRequest(IVHost vhost, IHTTPRequest req, IHTTPResponse resp) {
		if (!doHTTPAuthentication(vhost, req, resp))
			return;
		
		WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord HTTPRequest");
		
		Map<String, List<String>> params = req.getParameterMap();
		
		boolean append = false;
		String outputPath = null;
		int format = 1;
		boolean versionFile = true;
		boolean startOnKeyFrame = false;
		boolean recordData = true;
		
		String action = "";
		String app = "";
		String streamName = "";
		String report = "";
		
		if (req.getMethod().equalsIgnoreCase("get") || req.getMethod().equalsIgnoreCase("post")) {
			req.parseBodyForParams(true);
			
			try
			{
			if (params.containsKey("action"))
			{
				action = params.get("action").get(0);
			}else
			{
				report +="<BR>" + "action is required";
			}
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord action: " + action);
			
			if (params.containsKey("app"))
			{
				app = params.get("app").get(0);
			}else
			{
				report +="<BR>" + "app is required";
			}
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord app: " + app);
			
			if (params.containsKey("streamname"))
			{
				streamName = params.get("streamname").get(0);
			}else
			{
				report +="<BR>" + "streamname is required";
			}	
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord streamName: " + streamName);
			
			if (params.containsKey("output"))
				outputPath = params.get("output").get(0);
			
			if (outputPath != null)
				outputPath = (outputPath.equalsIgnoreCase("")?null:outputPath);
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord outputPath: " + outputPath);
			
			if (params.containsKey("append"))
				append = Boolean.parseBoolean(params.get("append").get(0));
	
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord append: " + append);
			
			if (params.containsKey("version"))
				versionFile = Boolean.parseBoolean(params.get("version").get(0));
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord version: " + versionFile);
			
			if (params.containsKey("startonkeyframe"))
				startOnKeyFrame = Boolean.parseBoolean(params.get("startonkeyframe").get(0));
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord startOnKeyFrame: " + startOnKeyFrame);
			
			if (params.containsKey("recorddata"))
				recordData = Boolean.parseBoolean(params.get("recorddata").get(0));
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord recordData: " + recordData);
			
			if (params.containsKey("format"))
				format = Integer.parseInt(params.get("format").get(0));
			
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord format (1=flv, 2=mp4): " + format);
			
			}
			catch(Exception ex)
			{
				report = "Error: " + ex.getMessage();
			}
		}
		else
		{
			report = "Nothing to do.";
		}
		
		try
		{
		IApplicationInstance appInstance = vhost.getApplication(app).getAppInstance("_definst_");
		
		if (!appInstance.getPublishStreamNames().contains(streamName))
		{
			report = "Stream " + streamName + " is not live ";
		}
		
		if (action.equalsIgnoreCase("startRecording") && report.equalsIgnoreCase(""))
		{		
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord.startRecording");
			
			String streamTypeStr = appInstance.getStreamType();
						
			boolean isLiveRepeaterEdge = false;
			while(true)
			{
				StreamList streamDefs = appInstance.getVHost().getStreamTypes();
				StreamItem streamDef = streamDefs.getStreamDef(streamTypeStr);
				if (streamDef == null)
					break;			
				isLiveRepeaterEdge = streamDef.getProperties().getPropertyBoolean("isLiveRepeaterEdge", isLiveRepeaterEdge);
				break;
			}
			
			if (isLiveRepeaterEdge)
				streamName = MediaStreamMediaCasterUtils.mapMediaCasterName(appInstance, null, streamName);
			
			IMediaStream stream = appInstance.getStreams().getStream(streamName);
			if (stream != null)
			{
				recordStream(stream, format, append, outputPath, versionFile, startOnKeyFrame, recordData);
				report = action + " " + streamName;
			}
			else
			{
				WMSLoggerFactory.getLogger(null).warn("ModuleStreamRecord.startRecording: stream not found: "+streamName);
				report = "Stream Not Found: " + streamName;
			}

		} 
		else if (action.equalsIgnoreCase("stopRecording") & report.equalsIgnoreCase(""))
		{
			WMSLoggerFactory.getLogger(null).info("ModuleStreamRecord.stopRecording: "+streamName);
			
			ILiveStreamRecord recorder = null;
			synchronized (recorders)
			{
				recorder = recorders.remove(streamName);
			}
			
			if (recorder != null)
			{
				// grab the current path to the recorded file
				outputPath = recorder.getFilePath();
				
				// stop recording
				recorder.stopRecording();
				report = action + " " + streamName;
			}
			else
			{
				WMSLoggerFactory.getLogger(null).warn("ModuleStreamRecord.stopRecording: stream recorder not found: "+streamName);
				report = "Stream Recorder Not Found: " + streamName;
			}
		}
		}
		catch(Exception e)
		{
			report = "Error: " + e.getMessage();
		}
		
		String retStr = "<html><head><title>HTTProvider LiveRecord</title></head><body><h1>" + report + "</h1></body></html>";

		try {
			OutputStream out = resp.getOutputStream();
			byte[] outBytes = retStr.getBytes();
			out.write(outBytes);
		} catch (Exception e) {
			WMSLoggerFactory.getLogger(null).error(
					"HTTPLiveStreamRecord: " + e.toString());
		}

	}
	
	public void recordStream(String streamName, int format, boolean append, String outputPath, boolean versionFile, boolean startOnKeyFrame, boolean recordData)
	{
		IMediaStream stream = appInstance.getStreams().getStream(streamName);
		if (stream != null)
			recordStream(stream, format, append, outputPath, versionFile, startOnKeyFrame, recordData);
		 else
			 WMSLoggerFactory.getLogger(null).warn("ModuleLiveStreamRecord.recordStream: Stream not found: "+streamName);
	}
	
	private void recordStream(IMediaStream stream, int format, boolean append, String outputPath, boolean versionFile, boolean startOnKeyFrame, boolean recordData)
	{

		String streamName = stream.getName();
		
		// if a format was not specified then check the stream prefix and choose accordingly
		if (format == FORMAT_UNKNOWN)
		{
			format = FORMAT_FLV;
			String extStr = stream.getExt();
			if (extStr.equals("mp4"))
				format = FORMAT_MP4;
		}
		
		String params = "stream:"+streamName;
		params += " format:"+(format==FORMAT_MP4?"mp4":"flv");
		params += " append:"+append;
		if (outputPath != null)
			params += " outputPath:"+outputPath;
		else
		{
			File writeFile = stream.getStreamFileForWrite(stream.getName(), (format==FORMAT_MP4?MediaStream.MP4_STREAM_EXT:MediaStream.BASE_STREAM_EXT), stream.getQueryStr());
			params += " outputPath:"+writeFile.getAbsolutePath();
		}
		params += " versionFile:"+versionFile;
		params += " startOnKeyFrame:"+startOnKeyFrame;
		params += " recordData:"+recordData;
		
		// getLogger().info("ModuleStreamRecord.startRecording: "+params);
		
		// create a stream recorder and save it in a map of recorders
		ILiveStreamRecord recorder = null;
		
		// create the correct recorder based on format
		if (format == FORMAT_MP4)
			recorder = new LiveStreamRecorderMP4();
		else
			recorder = new LiveStreamRecorderFLV();
		
		// add it to the recorders list
		synchronized (recorders)
		{
			ILiveStreamRecord prevRecorder = recorders.get(streamName);
			if (prevRecorder != null)
				prevRecorder.stopRecording();
			recorders.put(streamName, recorder);
		}
		
		// if you want to record data packets as well as video/audio
		recorder.setRecordData(recordData);
		
		// Set to true if you want to version the previous file rather than overwrite it
		recorder.setVersionFile(versionFile);
		
		// If recording only audio set this to false so the recording starts immediately
		recorder.setStartOnKeyFrame(startOnKeyFrame);
		
		// start recording
		recorder.startRecording(stream, outputPath, append);
	}

	public String stopRecording(String streamName)
	{
		ILiveStreamRecord recorder = null;
		synchronized (recorders)
		{
			recorder = recorders.remove(streamName);
		}
		
		String outputPath  = null;
		if (recorder != null)
		{
			// grab the current path to the recorded file
			outputPath = recorder.getFilePath();
			
			// stop recording
			recorder.stopRecording();
		}
		else
			WMSLoggerFactory.getLogger(null).warn("ModuleStreamRecord.stopRecording: stream recorder not found: "+streamName);
		
		return outputPath;
	}
}