package fsenablers.android.activity;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;
import android.support.v4.content.FileProvider;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.Toast;

import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;

import fsenablers.android.BuildConfig;

import fsenablers.android.http.HttpUploadRequest;
import fsenablers.android.http.HttpUploadTask;

public class MyWebInterface implements TextToSpeech.OnInitListener {

	
	private static final String TAG = "MyWebInterface";

	private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 101;
	private static final int VOICE_COMMAND_REQUEST_CODE = 102;	
	
	private static final String CURRENT_SCAN_TX = "currentScanTxId";
	private static final String CURRENT_VOICE_COMMAND_TX = "currentVoiceCommandTxId";
	private static final String CURRENT_TAKE_PICTURE_TX = "currentTakePictureTxId";
	private static final String CURRENT_TAKE_PICTURE_FILE = "currentTakePictureFile";
	
	private static final String CURRENT_TAKE_PICTURE_UPLOAD_URL = "currentTakePictureUploadURL";
	private static final String CURRENT_TAKE_PICTURE_UPLOAD_ADDFIELDS = "currentTakePictureUploadAddFields";
	private static final String CURRENT_TAKE_PICTURE_UPLOAD_FIELD = "currentTakePictureUploadFields";
	
	private static final String CURRENT_TAKE_PICTURE_UPLOAD_SCALE_WIDTH = "currentTakePictureUploadScaleWidth";
	private static final String CURRENT_TAKE_PICTURE_UPLOAD_SCALE_HEIGHT = "currentTakePictureUploadScaleHeight";
	
	
	private static final int MEDIA_TYPE_IMAGE = 1;
	private static final int MEDIA_TYPE_VIDEO = 2;	
	
	private WebAppActivity mMainActivity;
	
	private TextToSpeech tts;
	private boolean ttsReady = false;

	// String currentScanTxId;
	// String currentVoiceCommandTxId;

	private Bundle currentState;

	MyWebInterface( WebAppActivity mainActivity ) {
        mMainActivity = mainActivity;
        currentState = new Bundle();
        tts = new TextToSpeech(mainActivity, this);	
    }

	@JavascriptInterface
	public Bundle getCurrentState() {
		return currentState;
	}

	@JavascriptInterface
	public void setCurrentState( Bundle b ) {
		currentState = b;
	}

	@JavascriptInterface
	public void onDestroy() {
		if( ttsReady ) {
			
			Log.d("MyApp", "Tts Shutdown" );
			tts.shutdown();
			ttsReady = false;
			tts = null;
		}
	}
	@JavascriptInterface
	public void getVoiceCommand( String sTxId ){
   	 
		currentState.putString( CURRENT_VOICE_COMMAND_TX, sTxId );
		//currentVoiceCommandTxId = sTxId;
		
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Voice recognition Demo...");
        mMainActivity.startActivityForResult(intent, VOICE_COMMAND_REQUEST_CODE );
    }

	@JavascriptInterface
	public void onInit( int status ) {

   	 if (status == TextToSpeech.SUCCESS) {

		 int result;

		 // Try setting the Locale.US, this caused a bug to occur in certain Samsung Galaxy Devices
		 try {
			 result = tts.setLanguage(Locale.US);
		 }
		 catch( Exception exp ) {
			 Locale defaultLanguage = Locale.getDefault();
			 result = tts.isLanguageAvailable(defaultLanguage);
			 Log.e( "TTS" , "setLocation Locale.US Failed!");
		 }

		 if (result == TextToSpeech.LANG_MISSING_DATA
				 || result == TextToSpeech.LANG_NOT_SUPPORTED){
                Log.e("TTS", "This Language is not supported");
		 } else {
         	ttsReady = true;
         }

        } else {
            Log.e( "MyApp" , "Initilization Failed!");
        }
   }

	@JavascriptInterface
	public void takePictureAndUpload( String sTxId, String partnerId, String partnerType, String uploadUrl ) {
		

		File f = getOutputMediaFile( MEDIA_TYPE_IMAGE );
		currentState.putString( CURRENT_TAKE_PICTURE_TX, sTxId );
		currentState.putSerializable(CURRENT_TAKE_PICTURE_FILE, f);
		currentState.putString(CURRENT_TAKE_PICTURE_UPLOAD_FIELD, "photo" );
		currentState.putString(CURRENT_TAKE_PICTURE_UPLOAD_URL, uploadUrl );
		currentState.putInt( CURRENT_TAKE_PICTURE_UPLOAD_SCALE_WIDTH, 800 );
		currentState.putInt( CURRENT_TAKE_PICTURE_UPLOAD_SCALE_HEIGHT, 600 );
		
		Log.i( TAG, "takePictureAndUpload( " + sTxId + ", " + partnerId + partnerType + ", " + uploadUrl + ")" );
		
		HashMap<String,String> addFields = new HashMap<String,String>();
		addFields.put( "partnerId", partnerId );
		addFields.put( "partnerType", partnerType );
	
		
		currentState.putSerializable(CURRENT_TAKE_PICTURE_UPLOAD_ADDFIELDS, addFields );


		Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
		Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
		cameraIntent.putExtra( MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(mMainActivity, "com.fsenablers.fileprovider", f));
		cameraIntent.putExtra("return-data", true);
		cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

		Intent chooser = new Intent(Intent.ACTION_CHOOSER);
		chooser.putExtra(Intent.EXTRA_INTENT, galleryIntent);
		chooser.putExtra(Intent.EXTRA_TITLE, "choose one");
		Intent[] intentArray = {cameraIntent};
		chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
		mMainActivity.startActivityForResult(chooser, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);

		// intent = Intent.createChooser( captureIntent, "Capture Image" );

		//Intent intent = new Intent( MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA );
        //intent.putExtra( MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(mMainActivity, "com.fsenablers.fileprovider", f));
        //intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

		//mMainActivity.startActivityForResult( intent , CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE );
	}

	@JavascriptInterface
	public void takePicture( String sTxId )	{
		
		File f = getOutputMediaFile( MEDIA_TYPE_IMAGE );
		currentState.putString( CURRENT_TAKE_PICTURE_TX, sTxId );
		currentState.putSerializable(CURRENT_TAKE_PICTURE_FILE, f);
		
		currentState.putString(CURRENT_TAKE_PICTURE_UPLOAD_FIELD, "uploadedfile" );
		currentState.putString(CURRENT_TAKE_PICTURE_UPLOAD_URL, "http://godzilla-7:8500/testing/act_upload.cfm" );
		currentState.putSerializable( CURRENT_TAKE_PICTURE_UPLOAD_ADDFIELDS, new HashMap<String,String> () );
		
		currentState.putInt( CURRENT_TAKE_PICTURE_UPLOAD_SCALE_WIDTH, 800 );
		currentState.putInt( CURRENT_TAKE_PICTURE_UPLOAD_SCALE_HEIGHT, 600 );
		
		Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
		intent.putExtra( MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(mMainActivity, "com.fsenablers.fileprovider", f));
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

		mMainActivity.startActivityForResult( intent , CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE );
	  	
	}

	/** Create a File for saving an image or video */
	private static File getOutputMediaFile(int type){
	    // To be safe, you should check that the SDCard is mounted
	    // using Environment.getExternalStorageState() before doing this.

	    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
	              Environment.DIRECTORY_PICTURES), "MyCameraApp");
	    // This location works best if you want the created images to be shared
	    // between applications and persist after your app has been uninstalled.

	    // Create the storage directory if it does not exist
	    if (! mediaStorageDir.exists()){
	        if (! mediaStorageDir.mkdirs()){
	            Log.d("MyCameraApp", "failed to create directory");
	            return null;
	        }
	    }

	    // Create a media file name
	    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
	    File mediaFile;
	    if (type == MEDIA_TYPE_IMAGE){
	        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
	        "IMG_"+ timeStamp + ".jpg");
	    } else if(type == MEDIA_TYPE_VIDEO) {
	        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
	        "VID_"+ timeStamp + ".mp4");
	    } else {
	        return null;
	    }

	    return mediaFile;
	}

	@JavascriptInterface
	public void speak( String sTxId, String sMessage ) {
		
		Log.i( TAG, "Speak: "  + sMessage );
    	if( ttsReady ) {
    		tts.speak( sMessage, TextToSpeech.QUEUE_FLUSH, null);
    		sendResultToWebView( sTxId, true, sMessage );
    	} else {
    		Toast.makeText( mMainActivity, sMessage, Toast.LENGTH_LONG ).show();
    		sendResultToWebView( sTxId, false, sMessage );
    	}
	}

	@JavascriptInterface
	public void leave() {
		
		
		new AlertDialog.Builder(mMainActivity)
        .setTitle("Really Exit?")
        .setMessage("Are you sure you want to exit?")
        .setNegativeButton(android.R.string.no, null)
        .setPositiveButton(android.R.string.yes, new OnClickListener() {

            public void onClick(DialogInterface arg0, int arg1) {
            	mMainActivity.finish();
            }
        }).create().show();
		
	}

	@JavascriptInterface
	public void scan( String sTxId ) {
		
    	currentState.putString( CURRENT_SCAN_TX, sTxId );
    	
    	IntentIntegrator integrator = new IntentIntegrator( mMainActivity );
    	integrator.initiateScan();
  
	}

	@JavascriptInterface
	public void sendResultToWebView( String sTxId, boolean bSuccess, String sResult ) {
	    	
		WebViewResult wvr = new WebViewResult( sTxId, bSuccess, sResult );
		mMainActivity.runOnUiThread( wvr );
		   	
	}

	private class WebViewResult implements Runnable {
		
		
		private String sResultURL;
		
		WebViewResult( String sTxId, boolean bSuccess, String sResult ) {
			sResultURL = "javascript:onAndroidResult('" + sTxId + "'," + bSuccess + ",'" + sResult + "')";
			if( BuildConfig.DEBUG ) { Log.d("MyApp", sResultURL ); }
		}
		
		public void run() {
			WebView aWebView = (WebView) mMainActivity.getWebView();
			aWebView.loadUrl( sResultURL );
		}
		
	}


	@JavascriptInterface
	public void onActivityResult (int requestCode, int resultCode, Intent data)	{
		
		
		switch ( requestCode ) {

			case VOICE_COMMAND_REQUEST_CODE :
				
				String currentVoiceCommandTxId = currentState.getString( CURRENT_VOICE_COMMAND_TX );
				if ( resultCode == Activity.RESULT_OK) {
		            // Populate the wordsList with the String values the recognition engine thought it heard
		            ArrayList<String> matches = data.getStringArrayListExtra(
		                    RecognizerIntent.EXTRA_RESULTS);
		            Iterator<String> i = matches.iterator();
		            String commandSentence = null;
		            while( i.hasNext() ) {
		            	String sentence = i.next().toString();
		            	if( commandSentence == null ) {
		            		commandSentence = sentence;
		            	}
		            	if( BuildConfig.DEBUG ) { Log.d("MyApp", "Match: " + sentence ); }
		            }
		            
		            if( commandSentence != null ) {
		            	sendResultToWebView( currentVoiceCommandTxId, true, commandSentence );
		            }
		            if( BuildConfig.DEBUG ) { Log.d( "MyApp", "Speech Ok" ); }
		        } else if ( resultCode == Activity.RESULT_CANCELED ) {
		        	// nothing to client
		        	if( BuildConfig.DEBUG ) { Log.d("MyApp", "Speech Cancelled" ); }
		        } else {
		        	sendResultToWebView( currentVoiceCommandTxId, false, "error" );
		        	if( BuildConfig.DEBUG ) { Log.d("MyApp", "resultCode = " + resultCode ); }
		        }
				break;

			case CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE :
	
				if( BuildConfig.DEBUG ) { Log.d("MyApp", "Result from Camera" ); }

				Log.i( TAG, "camera response " + resultCode  );
				if( resultCode == Activity.RESULT_OK ) {

					File f = (File) currentState.getSerializable(CURRENT_TAKE_PICTURE_FILE);
					String currentTakePictureTx = currentState.getString(CURRENT_TAKE_PICTURE_TX);

					if ( data != null ) {
						if (data.getData() != null) { // image chosen from gallery
							try {
								Bitmap bitmap = MediaStore.Images.Media.getBitmap(mMainActivity.getApplicationContext().getContentResolver(), data.getData());
								File file = new File("path");
								OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
								bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
								os.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
					}

					String uploadUrl = currentState.getString(CURRENT_TAKE_PICTURE_UPLOAD_URL);
					Map<String, String> addFields = (Map<String, String>) currentState.getSerializable(CURRENT_TAKE_PICTURE_UPLOAD_ADDFIELDS);
					String uploadField = currentState.getString(CURRENT_TAKE_PICTURE_UPLOAD_FIELD);

					if (BuildConfig.DEBUG) {
						Log.d(TAG, "File = " + f.toString());
					}
					if (BuildConfig.DEBUG) {
						Log.d(TAG, "Tx = " + currentTakePictureTx);
					}
					try {


						Toast.makeText(mMainActivity, "Starting upload...", Toast.LENGTH_SHORT).show();

						InputStream strm;

						boolean bScaleImage = true;

						if (bScaleImage) {

							final BitmapFactory.Options options = new BitmapFactory.Options();
							options.inJustDecodeBounds = true;

							BitmapFactory.decodeFile(f.toString(), options);

							// Raw height and width of image
							final int height = options.outHeight;
							final int width = options.outWidth;
							options.inSampleSize = 1;

							final int reqWidth = currentState.getInt(CURRENT_TAKE_PICTURE_UPLOAD_SCALE_WIDTH);
							final int reqHeight = currentState.getInt(CURRENT_TAKE_PICTURE_UPLOAD_SCALE_HEIGHT);

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

								// Calculate ratios of height and width to requested height and width
								final int heightRatio = Math.round((float) height / (float) reqHeight);
								final int widthRatio = Math.round((float) width / (float) reqWidth);

								// 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.
								options.inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
							}

							if (BuildConfig.DEBUG) {
								Log.d("ScaleBitmap", "options.inSampleSize = " + options.inSampleSize);
								Log.d("ScaleBitmap", "options.outHeight = " + options.outHeight);
								Log.d("ScaleBitmap", "options.outWidth = " + options.outWidth);
							}

							options.inJustDecodeBounds = false;
							Bitmap scaledBitmap = BitmapFactory.decodeFile(f.toString(), options);

							if (BuildConfig.DEBUG) {
								Log.d("ScaleBitmap", "scaled.height = " + scaledBitmap.getHeight());
								Log.d("ScaleBitmap", "scaled.width = " + scaledBitmap.getWidth());
							}

							ByteArrayOutputStream baos = new ByteArrayOutputStream();

							scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);

							baos.close();

							strm = new ByteArrayInputStream(baos.toByteArray());

						} else {

							strm = new FileInputStream(f);

						}

					/*
					Bitmap bitMap = BitmapFactory.decodeFile( f.toString() );

					float sourceWidth = bitMap.getWidth();
					float sourceHeight = bitMap.getHeight();

					// float sourceRatio = sourceWidth / sourceHeight;

					float targetWidth = currentState.getInt( CURRENT_TAKE_PICTURE_UPLOAD_SCALE_WIDTH );

					float scaleRatio = targetWidth / sourceWidth;

					float targetHeight = Math.round( sourceHeight * scaleRatio );
					Log.d( "MyApp", "Ratio is " + scaleRatio );
					Log.d( "MyApp", "Scaling from " + sourceWidth + "x" + sourceHeight + " to " + targetWidth + "x" + targetHeight );

					Bitmap scaledBitmap = Bitmap.createScaledBitmap( bitMap, Math.round(targetWidth ), Math.round( targetHeight ), true  );

					ByteArrayOutputStream baos = new ByteArrayOutputStream();

					scaledBitmap.compress( Bitmap.CompressFormat.JPEG, 50, baos );

					baos.close();

					InputStream strm = new ByteArrayInputStream( baos.toByteArray() );
					*/

						// Set your file path here
						//FileInputStream strm = new FileInputStream( f );

						if (BuildConfig.DEBUG) {
							Log.i(TAG, "uploadUrl = " + uploadUrl);
						}
						HttpUploadRequest uploadRequest = new HttpUploadRequest(mMainActivity, currentTakePictureTx, uploadUrl, uploadField, addFields, strm, "myfile.jpg", "my title", "my description");

						HttpUploadTask uploadTask = new HttpUploadTask(mMainActivity);


						uploadTask.execute(uploadRequest);


					} catch (IOException iox) {
						Log.e("MyApp", "IOException");
						Log.e("MyApp", iox.toString());
					}

				}
				
				break;		
		
			default:
				IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data );
				  if (scanResult != null) {
					  
					  if( BuildConfig.DEBUG ) { Log.d( "MyApp", "ScanResult" );}
					  String currentScanTxId = currentState.getString( CURRENT_SCAN_TX );
					  if( BuildConfig.DEBUG ) { Log.d( "MyApp", "Scan TX = " + currentScanTxId );}
					  if( resultCode == Activity.RESULT_OK ) {
						  if( BuildConfig.DEBUG ) { Log.d( "MyApp", "SCAN OK: " + scanResult.toString() );}
						  sendResultToWebView( currentScanTxId, true, scanResult.getContents() );
						  
					  } else if ( resultCode == Activity.RESULT_CANCELED ) {
						  if( BuildConfig.DEBUG ) { Log.d("MyApp", "SCAN CANCELED" );}
						  sendResultToWebView( currentScanTxId, false, "CANCELED" );

					  } else {
						  if( BuildConfig.DEBUG ) { Log.d("MyApp", "SCAN FAILED" );}
						  sendResultToWebView( currentScanTxId, false, "ERROR" );
					  }
					  if( BuildConfig.DEBUG ) { Log.d("MyApp", "scanResult" );}
				    
				  } 				
				break;
		}
		
			  		
	}
	
}


