package sliz.elektromery;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.imgproc.Imgproc;
import org.opencv.ml.CvANN_MLP;

import sliz.elektromery.R;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class PicActivity extends Activity 
{
	private static final String TAG = "PicActivity";
	
	private static final int CHOOSE_IMAGE_REQUEST = 1;
    private static final int SELECT_PICTURE = 1;

    Mat	matImg, matPatt;
    
    // Image scaling variables
    TouchImageView imgView;
    
    // Handling twice opening image gallery
    static public String selectedImagePath;
    
    static public boolean bFromMenu;
    
    // ANN 
    CvANN_MLP cANN;
    private File   mANNFile;    
    boolean bANNLoaded = false;
    
    private BaseLoaderCallback  mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                {
                    // Load native library after(!) OpenCV initialization
                    System.loadLibrary("native_part");
                    
                    loadANN();
                    
                } break;
                default:
                {
                    super.onManagerConnected(status);
                } break;
            }
        }
    };
	
	public void onCreate(Bundle savedInstanceState) 
    {
    	super.onCreate(savedInstanceState);		
    	
    	if(selectedImagePath == null)
		{
	    	// first open picture
	    	if (Build.VERSION.SDK_INT <19)
	    	{
		    	Intent intent = new Intent();
				intent.setType("image/*");
				intent.setAction(Intent.ACTION_GET_CONTENT); 
				startActivityForResult(Intent.createChooser(intent,
				"Select Picture"), 1);
	    	}
	    	else
	    	{
    			Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    			startActivityForResult(i, CHOOSE_IMAGE_REQUEST);
    		}
    	}
    	else loadImage();
    }
	
	private void loadANN()
	{
		// Load ANN trained classifier
		try {
            // load cascade file from application resources
            InputStream is = getResources().openRawResource(R.raw.ann_trained2);
            File ANNDir = getDir("ANN", Context.MODE_PRIVATE);
            mANNFile = new File(ANNDir, "ann_trained.xml");
            FileOutputStream os = new FileOutputStream(mANNFile);

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

            cANN = new CvANN_MLP();
            cANN.load(mANNFile.getAbsolutePath());
            
            bANNLoaded = true;
            
            ANNDir.delete();

        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "Failed to load ANN. Exception thrown: " + e);
        }
	}
	
	protected void onDestroy() 
	{

//		selectedImagePath = null;

	    super.onDestroy();
	}
	
	@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) 
    {
	    if(keyCode == KeyEvent.KEYCODE_BACK) 
	    {
	    	backToMenu();
	    }
	    	
    	//Pass other events along their way up the chain
	    return super.onKeyDown(keyCode, event);
    }
	
	@Override
    public void onResume()
    {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
    }
	
	private void backToMenu()
	{
		Intent intnscnd = new Intent(PicActivity.this, MenuActivity.class);
        startActivity(intnscnd);
        PicActivity.this.finish();

        selectedImagePath = null;
	}
	
	private void createEvents()
	{
		Button btnBack = (Button)findViewById(R.id.btn_pic_back);
		btnBack.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {	
				backToMenu();
			}
		});
		
		Button btnLoad = (Button)findViewById(R.id.btn_pic_load);
		btnLoad.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {	
				// Save values to actual file
				appSettings appSet = new appSettings();
				
				// Format:
				// <dateTime> <;> <value> <;endl>
				
				// get image file date
				File file = new File(selectedImagePath);
				long time = file.lastModified();
				
				EditText et = (EditText)findViewById(R.id.editText1);
				
				String data = String.valueOf(time) + ";" + file.getName() + ";" + et.getText() + ";";
				
				appSet.writeToFile(data);
				
				// Save image if permitted
				
				// Show file list
				
				Toast.makeText(getBaseContext(), getString(R.string.strSaved), Toast.LENGTH_SHORT).show();
			}
		});
	}
	
	@SuppressLint("InlinedApi")
	private void loadImage()
	{
		//NOW WE HAVE OUR WANTED STRING
//        if(selectedImagePath!=null)
        {
        	matImg = new Mat();
        	// create pic_view
//        	setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
        	//Remove title bar
//        	if (Build.VERSION.SDK_INT >= 19)this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    		//Remove notification bar
    		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        	setContentView(R.layout.pic_view);
        	
        	createEvents();
        	
        	Drawable d = Drawable.createFromPath(selectedImagePath);
        	// Convert Drawable to Mat
        	Bitmap bitmapImg = ((BitmapDrawable) d).getBitmap();
            Utils.bitmapToMat(bitmapImg, matImg);
            
            // Load pattern pictures
            Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.feature_patterns_b);
            matPatt = new Mat();
            Utils.bitmapToMat(bm, matPatt);
            Imgproc.cvtColor(matPatt, matPatt, Imgproc.COLOR_BGR2GRAY);
            
            // Mat for ANN input
            Mat annTest = new Mat();
            
            if(bFromMenu)
            {
	            // Segment frame
	            MatOfRect frames = new MatOfRect();
	            FindFrame(matImg.getNativeObjAddr(), frames.getNativeObjAddr());
            }
            // Process image here:
            SegmentDigits(matImg.getNativeObjAddr(), matPatt.getNativeObjAddr(), annTest.getNativeObjAddr());
            
            if(!bANNLoaded)loadANN();            	
            
            // ANN recognation
            if(bANNLoaded && !annTest.empty())
            {
            	List<Float> listNumbers = new ArrayList<Float>();
            	for(int i = 0 ; i < annTest.rows() ; i++)
            	{
            		// Get actual row (digit)
            		Mat row = annTest.row(i);
            		
            		// Predict
            		Mat outputs = new Mat();
            		cANN.predict(row, outputs);
            		
            		// Evaluate actual number
            		int maxIndx = 0;
            		double max = 0;
            		float act[] = new float[(int) ((outputs.total()) * outputs.channels())]; 
					outputs.get(0, 0, act);
            		for(int j = 0 ; j < outputs.cols() ; j ++)
            		{            			
            			if(max < act[j])
	    				{
            				max = act[j];
            				maxIndx = j;
	    				}
            		}
            		float val = 0;
            	    // Decode number
            	    if(maxIndx < 10)val = (float)maxIndx;
            	    else val = (float)(maxIndx-10)+0.5f;
            		listNumbers.add(val);
            	}
            	// corect numbers
            	
            	int listRes[] = new int[listNumbers.size()];
            	float numericRes = 0;
            	for(int i = 0 ; i < listNumbers.size() - 1 ; i++)
            	{
            		int res = 0;
            		float act = listNumbers.get(i);
            		if(act - (int)act > 0.0f)
            		{
            			float next = listNumbers.get(i + 1);
            			if(next > 5.0f)res = (int)(act + 0.5f);
            			else res = (int)(act - 0.5f);
            		}
            		else res = (int)act;
            		listRes[i] = res;
            		numericRes += res * (int)Math.pow(10, listNumbers.size() - 2 - i);
            	}
            	float act = listNumbers.get(listNumbers.size() - 1);
            	numericRes += act/10;
            	
            	// Show number
            	EditText te = (EditText) findViewById(R.id.editText1);
            	String strNum = Float.toString(numericRes);
            	te.setText(strNum);
            	

            }
            else
            {
            	Toast.makeText(this, R.string.text_recognation_failed, Toast.LENGTH_SHORT).show();
            }
            
            // Convert Mat to Bitmap and show in imageView
            Bitmap bitmapImg2 = Bitmap.createBitmap(matImg.cols(), matImg.rows(), Bitmap.Config.ARGB_8888);
            Utils.matToBitmap(matImg, bitmapImg2);
             
         // Initialize image view and scaling variables
        	imgView = (TouchImageView)findViewById(R.id.imageView1);
            imgView.setImageBitmap(bitmapImg2);   
        }
	}
	
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            if (requestCode == SELECT_PICTURE) {
                Uri selectedImageUri = data.getData();
                               
                
                //MEDIA GALLERY  
                if(selectedImagePath == null)
                	selectedImagePath = getPath(selectedImageUri);

                //OI FILE Manager    
                if(selectedImagePath == null)
                	selectedImagePath = selectedImageUri.getPath();

                loadImage();
                }
                else
                {
                    System.out.println("Path is NULL");
                    backToMenu();
                }
            }
    }
	
	public String getPath(Uri uri) {
	    String selectedImagePath;
	    //1:MEDIA GALLERY --- query from MediaStore.Images.Media.DATA
	    String[] projection = { MediaStore.Images.Media.DATA };
	    @SuppressWarnings("deprecation")
		Cursor cursor = managedQuery(uri, projection, null, null, null);
	    if(cursor != null){
	        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
	        cursor.moveToFirst();
	        selectedImagePath = cursor.getString(column_index);
	    }else{
	        selectedImagePath = null;
	    }

	    if(selectedImagePath == null){
	        //2:OI FILE Manager --- call method: uri.getPath()
	        selectedImagePath = uri.getPath();
	    }
	    return selectedImagePath;
	}

    // Native methods declaration
    public native void SegmentDigits(long matAddrRgba, long matAddrFeaturePattern, long matAddrANNTest);
    public native void FindFrame(long matAddrRgba, long rectAddr);
}
