package com.app2.softscanner;

import java.io.IOException;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import com.app2.softscanner.R;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;

public class SoftScanner extends Activity {

	private static final String  TAG = "Example::SoftScanner::Activity";
	private String selectedImagePath;
	Mat sampledImage=null;
	Mat originalImage=null;
	private static final int SELECT_PICTURE = 1;
	private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
		@Override
		public void onManagerConnected(int status) {
			switch (status) {
			case LoaderCallbackInterface.SUCCESS:
			{
				Log.i(TAG, "OpenCV loaded successfully");
			} break;
			default:
			{
				super.onManagerConnected(status);
			} break;
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_soft_scanner);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.soft_scanner, menu);
		return true;
	}
	@Override
	public void onResume()
	{
		super.onResume();
		OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_8, this, mLoaderCallback);
	}
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (resultCode == RESULT_OK) {
			if (requestCode == SELECT_PICTURE) {
				Uri selectedImageUri = data.getData();
				selectedImagePath = getPath(selectedImageUri);
				Log.i(TAG, "selectedImagePath: " + selectedImagePath);
				loadImage(selectedImagePath);
				displayImage(sampledImage);
			}
		}
	}
	/**
	 * helper to retrieve the path of an image URI
	 */
	private String getPath(Uri uri) {
		// just some safety built in 
		if( uri == null ) {
			return null;
		}
		// try to retrieve the image from the media store first
		// this will only work for images selected from gallery
		String[] projection = { MediaStore.Images.Media.DATA };
		Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
		if( cursor != null ){
			int column_index = cursor
					.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
			cursor.moveToFirst();
			return cursor.getString(column_index);
		}
		return uri.getPath();
	}
	private static double calculateSubSampleSize(Mat srcImage,int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = srcImage.height();
		final int width = srcImage.width();
		double inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			// Calculate ratios of height and width to requested height and width
			final double heightRatio = (double) reqHeight / (double) height;
			final double widthRatio = (double) reqWidth / (double) width;

			// Choose the smallest ratio as inSampleSize value, this will guarantee
			// a final image with both dimensions larger than or equal to the
			// requested height and width.
			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
		}

		return inSampleSize;
	}
	private void displayImage(Mat image)
	{
		// convert to bitmap:
		Bitmap bitMap = Bitmap.createBitmap(image.cols(), image.rows(),Bitmap.Config.RGB_565);
		Utils.matToBitmap(image, bitMap);

		// find the imageview and draw it!
		ImageView iv = (ImageView) findViewById(R.id.SSImageView);
		iv.setImageBitmap(bitMap);
	}
	private void loadImage(String path)
	{
		originalImage = Highgui.imread(path);
		Mat rgbImage=new Mat();
		sampledImage=new Mat();

		Imgproc.cvtColor(originalImage, rgbImage, Imgproc.COLOR_BGR2RGB);

		Display display = getWindowManager().getDefaultDisplay();
		Point size = new Point();
		display.getSize(size);

		int width = size.x;
		int height = size.y;

		double downSampleRatio=calculateSubSampleSize(rgbImage,width,height);

		Imgproc.resize(rgbImage, sampledImage, new Size(),downSampleRatio,downSampleRatio,Imgproc.INTER_AREA);

		try {
			ExifInterface exif = new ExifInterface(selectedImagePath);
			int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

			switch (orientation )
			{
			case ExifInterface.ORIENTATION_ROTATE_90:
				//get the mirrored image
				sampledImage=sampledImage.t();
				//flip on the y-axis
				Core.flip(sampledImage, sampledImage, 1);
				break;
			case ExifInterface.ORIENTATION_ROTATE_270:
				//get up side down image
				sampledImage=sampledImage.t();
				//Flip on the x-axis
				Core.flip(sampledImage, sampledImage, 0);
				break;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	@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_openGallary) {
			Intent intent = new Intent();
			intent.setType("image/*");
			intent.setAction(Intent.ACTION_GET_CONTENT);
			startActivityForResult(Intent.createChooser(intent,
					"Select Picture"), SELECT_PICTURE);
			return true;
		}
		else if(id==R.id.action_HTL)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat binaryImage=new Mat();
			Imgproc.cvtColor(sampledImage, binaryImage, Imgproc.COLOR_RGB2GRAY);
			Imgproc.Canny(binaryImage, binaryImage, 80, 100);

			Mat lines = new Mat();
			int threshold = 180;
			Imgproc.HoughLinesP(binaryImage, lines, 1, Math.PI/180, threshold);
			
			Imgproc.cvtColor(binaryImage, binaryImage, Imgproc.COLOR_GRAY2RGB);
			for (int i = 0; i < lines.cols(); i++) 
			{
				double[] line = lines.get(0, i);
				double xStart = line[0], 
						yStart = line[1],
						xEnd = line[2],
						yEnd = line[3];
				org.opencv.core.Point lineStart = new org.opencv.core.Point(xStart, yStart);
				org.opencv.core.Point lineEnd = new org.opencv.core.Point(xEnd, yEnd);

				Core.line(binaryImage, lineStart, lineEnd, new Scalar(0,0,255), 3);
			}
			displayImage(binaryImage);

			return true;	
		}
		else if(id==R.id.action_CHT)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat grayImage=new Mat();
			Imgproc.cvtColor(sampledImage, grayImage, Imgproc.COLOR_RGB2GRAY);
			
			double minDist=50;
			int thickness=5;
			double cannyHighThreshold=200;
			double accumlatorThreshold=100;
			Mat circles = new Mat();
			Imgproc.HoughCircles(grayImage, circles, Imgproc.CV_HOUGH_GRADIENT, 1, minDist,cannyHighThreshold,accumlatorThreshold,0,0);
			
			Imgproc.cvtColor(grayImage, grayImage, Imgproc.COLOR_GRAY2RGB);
			for (int i = 0; i < circles.cols(); i++) 
			{
				double[] circle = circles.get(0, i);
				double centerX = circle[0], 
						centerY = circle[1],
						radius = circle[2];
				org.opencv.core.Point center = new org.opencv.core.Point(centerX, centerY);
				Core.circle(grayImage, center, (int) radius, new Scalar(0,0,255),thickness);
			}
			displayImage(grayImage);
			return true;	
		}
		else if(id==R.id.action_average)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat blurredImage=new Mat();
			Size size=new Size(7,7);
			Imgproc.blur(sampledImage, blurredImage, size);
			
			displayImage(blurredImage);
			return true;	
		}
		else if(id==R.id.action_gaussian)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat blurredImage=new Mat();
			Size size=new Size(35,35);
			Imgproc.GaussianBlur(sampledImage, blurredImage, size, 0,0);
			
			displayImage(blurredImage);
			return true;	
		}
		else if(id==R.id.action_median)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat blurredImage=new Mat();
			int kernelDim=5;
			Imgproc.medianBlur(sampledImage,blurredImage , kernelDim);
			
			displayImage(blurredImage);
			return true;	
		}
		else if(id==R.id.action_bilateral)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat blurredImage=new Mat();
			int kernelDim=41;
			Imgproc.bilateralFilter(sampledImage, blurredImage, kernelDim, 150, 450);
			
			displayImage(blurredImage);
			return true;	
		}
		else if(id==R.id.action_sobel)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat blurredImage=new Mat();
			Size size=new Size(7,7);
			Imgproc.GaussianBlur(sampledImage, blurredImage, size, 0,0);
			
			Mat gray = new Mat();
			Imgproc.cvtColor(blurredImage, gray, Imgproc.COLOR_RGB2GRAY);
			
			Mat xD =new Mat(),yD=new Mat();
			Mat absXD=new Mat(),absYD=new Mat();
			int ddepth=CvType.CV_16S;
			Imgproc.Sobel(gray, xD,ddepth , 1,0);
			Imgproc.Sobel(gray, yD,ddepth , 0,1);
			
			Core.convertScaleAbs(xD, absXD);
			Core.convertScaleAbs(yD, absYD);
			
			Mat edgeImage=new Mat();
			Core.addWeighted(absXD, 0.5, absYD, 0.5, 0, edgeImage);
			
			displayImage(edgeImage);
			return true;	
		}
		else if(id==R.id.action_canny)
		{
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			Mat gray = new Mat();
			Imgproc.cvtColor(sampledImage, gray, Imgproc.COLOR_RGB2GRAY);
			
			Mat edgeImage=new Mat();
			Imgproc.Canny(gray, edgeImage, 100, 200);
			
			displayImage(edgeImage);
			return true;	
		}
		else if (id == R.id.action_revert) {
			if(sampledImage==null)
			{
				Context context = getApplicationContext();
				CharSequence text = "You need to load an image first!";
				int duration = Toast.LENGTH_SHORT;

				Toast toast = Toast.makeText(context, text, duration);
				toast.show();
				return true;
			}
			displayImage(sampledImage);
			return true;	
		}
		return super.onOptionsItemSelected(item);
	}
}
