package com.app4.autoselfie;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Map.Entry;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.objdetect.Objdetect;

import com.app4.autoselfi.R;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.Toast;

public class AutoSelfie extends Activity implements CvCameraViewListener2 {

	private static final String    TAG                 = "App4::AutoSelfieActivity";
	private Mat                    mRgba;
	private Mat                    mGray;
	private CamView mOpenCvCameraView;
	private File                   cascadeFile;
	private CascadeClassifier      cascadeClassifier;
	private int                    mAbsoluteFaceSize   = 0;
	private float                  mRelativeFaceSize   = 0.2f;
	private static final Scalar    HAND_RECT_COLOR     = new Scalar(255, 0, 0, 255);
	private static final Scalar    CUE_RECT_COLOR     = new Scalar(0, 255, 0, 255);
	private Hashtable<Integer,Integer> rectBuckts=new Hashtable<Integer, Integer>();
	private Hashtable<Integer,Rect> rectCue=new Hashtable<Integer, Rect>();
	private final Handler handler = new Handler() {
	        public void handleMessage(Message msg) {
	              if(msg.arg1 == 1)
	                    Toast.makeText(getApplicationContext(),msg.getData().getString("msg"), Toast.LENGTH_LONG).show();
	        }
	    };
	
	private BaseLoaderCallback  mLoaderCallback = new BaseLoaderCallback(this) {
		@Override
		public void onManagerConnected(int status) {
			switch (status) {
			case LoaderCallbackInterface.SUCCESS:
			{
				Log.i(TAG, "OpenCV loaded successfully");
				try {
					// load cascade file from application resources
					InputStream is = getResources().openRawResource(R.raw.haarhand);
					File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
					cascadeFile = new File(cascadeDir, "haarhand.xml");
					FileOutputStream os = new FileOutputStream(cascadeFile);

					byte[] buffer = new byte[4096];
					int bytesRead;
					while ((bytesRead = is.read(buffer)) != -1) {
						os.write(buffer, 0, bytesRead);
					}
					is.close();
					os.close();

					cascadeClassifier = new CascadeClassifier(cascadeFile.getAbsolutePath());
					if (cascadeClassifier.empty()) {
						Log.e(TAG, "Failed to load cascade classifier");
						cascadeClassifier = null;
					} else
						Log.i(TAG, "Loaded cascade classifier from " + cascadeFile.getAbsolutePath());
					cascadeDir.delete();

				} catch (IOException e) {
					e.printStackTrace();
					Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
				}
				mOpenCvCameraView.enableView();
			} break;
			default:
			{
				super.onManagerConnected(status);
			} break;
			}
		}
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
		setContentView(R.layout.activity_auto_selfie);
		
		mOpenCvCameraView = (CamView) findViewById(R.id.auto_selfie_activity_surface_view);
		mOpenCvCameraView.setCameraIndex(1);
		mOpenCvCameraView.setCvCameraViewListener(this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.auto_selfie, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
	public void onCameraViewStarted(int width, int height) {
		mGray = new Mat();
		mRgba = new Mat();
	}

	public void onCameraViewStopped() {
		mGray.release();
		mRgba.release();
	}

	public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
		//Flip around the Y axis
		Core.flip(inputFrame.rgba(), mRgba, 1);
		Core.flip(inputFrame.gray(),mGray,1);

		if (mAbsoluteFaceSize == 0) {
			int height = mGray.rows();
			if (Math.round(height * mRelativeFaceSize) > 0) {
				mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
			}
		}

		MatOfRect closedHands = new MatOfRect();
	if (cascadeClassifier != null)
		cascadeClassifier.detectMultiScale(mGray, closedHands, 1.1, 2, Objdetect.CASCADE_SCALE_IMAGE,
						new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
	
		Rect[] facesArray = closedHands.toArray();
		for (int i = 0; i < facesArray.length; i++)
		{
			Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), HAND_RECT_COLOR, 3);
			Point quatnizedTL=new Point(((int)(facesArray[i].tl().x/100))*100,((int)(facesArray[i].tl().y/100))*100);
			Point quatnizedBR=new Point(((int)(facesArray[i].br().x/100))*100,((int)(facesArray[i].br().y/100))*100);
			int bucktID=quatnizedTL.hashCode()+quatnizedBR.hashCode()*2;
			Log.e(TAG, "bucktID="+bucktID);
			Log.e(TAG, "quatnizedTL="+quatnizedTL.toString());
			Log.e(TAG, "quatnizedBR="+quatnizedBR.toString());
			if(rectBuckts.containsKey(bucktID))
			{
				rectBuckts.put(bucktID, rectBuckts.get(bucktID)+1);
				rectCue.put(bucktID, new Rect(quatnizedTL,quatnizedBR));
			}
			else
			{
				rectBuckts.put(bucktID, 1);
			}
		}
		int maxDetections=0;
		int maxDetectionsKey=0;
		for(Entry<Integer,Integer> e : rectBuckts.entrySet())
		{
			if(e.getValue()>maxDetections)
			{
				maxDetections=e.getValue();
				maxDetectionsKey=e.getKey();
			}
		}
		if(maxDetections>5)
		{
			Core.rectangle(mRgba, rectCue.get(maxDetectionsKey).tl(), rectCue.get(maxDetectionsKey).br(), CUE_RECT_COLOR, 3);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
			String currentDateandTime = sdf.format(new Date());
			String fileName = Environment.getExternalStorageDirectory().getPath() +"/sample_picture_" + currentDateandTime + ".jpg";
			mOpenCvCameraView.takePicture(fileName);
			Message msg = handler.obtainMessage();
			msg.arg1 = 1;
			Bundle b=new Bundle();
			b.putString("msg", fileName + " saved");
			msg.setData(b);
			handler.sendMessage(msg);
			rectBuckts.clear();
		}
		return mRgba;
	}
	@Override
	public void onResume()
	{
		super.onResume();
		OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_8, this, mLoaderCallback);
	}
	@Override
	public void onPause()
	{
		super.onPause();
		if (mOpenCvCameraView != null)
			mOpenCvCameraView.disableView();
	}
	public void onDestroy() {
		super.onDestroy();
		mOpenCvCameraView.disableView();
	}

}
