package com.android.testbtspp2_1;

import java.util.Vector;

import com.android.Algorithm.*;
//import com.android.testbtspp2_1.*;
import com.android.MathClass.*;
import com.android.application.*;
import com.android.main.*;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Toast;
import android.widget.ViewFlipper;

public class CCADomainActivity extends Activity{
	private String TAG = "CCADomainActivity";
	private CCADomainView cdv;
	protected void onCreate(Bundle bb) {
		super.onCreate(bb);
		cdv = new CCADomainView(this); 
		setContentView(cdv);
	}
    @Override
    public void onStop() {
         super.onStop();
         Log.e(TAG, "-- ON STOP --");
         cdv.dccathread.setStopTag(true);
         finish();
    }
	class CCADomainView extends View implements View.OnTouchListener, View.OnLongClickListener{
		private Paint paint;
		private int sampleRate;
		private boolean DEBUG = true;
		private final int secondForCCA = 4;
		private String TAG = "CCADomainView";
		private float oriDistanceOfFingers;
		private int selectionForNextDisplay;
		private float oriXAxis,oriYAxis;//for one finger, swipe screen
		private Buffer buffer;
		private String msgToDisplay = "";
		private double []ch1Buffer,ch2Buffer,ch3Buffer,ch4Buffer;
		private double []CCAResultBuffer;
		protected DrawCCAThread dccathread;
		private int indexForDataBuffer;
		private CanonicalCorrelationAnalysis cca;
		//frames to display CCA result
		private int frameWidth, frameHeight;
		private final int topGap = 50,bottomGap=50, leftSideGap=40,rightSideGap=40;
		private int []XAxis;
		private int MaxIndex = 0;//Max index after CCA.
		private final int MIN_SLIDE_DISTANCE = 200;
		private FIRFilterImplementation firCH1,firCH2,firCH3,firCH4;
		private boolean filterTag;
		private Toast popMsg;
		private final int displayFrom = 32,displayTo = 44;//from 9Hz->12Hz
		private final int barThickLevel = 22;
		private QuickSort qsort;
		private double [] info;//display the CCAResultBuffer value on the right-side screen.
		public CCADomainView(Context context){
			super(context);
			setTitle("CCA Domain Display(4 seconds window)");
			sampleRate = Buffer.sRate;
			buffer = new Buffer();
			paint = new Paint();
			paint.setStyle(Paint.Style.STROKE);
			paint.setStrokeWidth(1);
			setOnTouchListener(this);
			setLongClickable(true);
			setOnLongClickListener(this);
			oriDistanceOfFingers = 0;
			selectionForNextDisplay = -1;//initial, should be set by longClick
			oriXAxis = 0;
			oriYAxis = 0;
			ch1Buffer = new double [secondForCCA*sampleRate];
			ch2Buffer = new double [secondForCCA*sampleRate];
			ch3Buffer = new double [secondForCCA*sampleRate];
			ch4Buffer = new double [secondForCCA*sampleRate];
			CCAResultBuffer = new double[sampleRate];
			dccathread = new DrawCCAThread(mHandler,"4sec");
			dccathread.start();
			indexForDataBuffer = 0;//0,1,2,...,secondForCCA-1
			cca = new CanonicalCorrelationAnalysis();
			frameWidth = 800-leftSideGap-rightSideGap;// 800/2
			frameHeight = 400-bottomGap-topGap; // 450/2
			XAxis = new int [sampleRate];//initial in modifyScale()
			firCH1 = new FIRFilterImplementation();
			firCH2 = new FIRFilterImplementation();
			firCH3 = new FIRFilterImplementation();
			firCH4 = new FIRFilterImplementation();
			filterTag = false;
			popMsg = new Toast(getContext());
			qsort = new QuickSort();
			info = new double[displayTo-displayFrom+2];//[0]=value1, [1]=value2...[last]=MaxFreqIndex
		}
		
		private void setData(Vector v){
			if(DEBUG)Log.e(TAG, "In setData()");
			//put data into dataBuffer, and filter
			if(v==null ||v.size()<4)
				Log.e(TAG, "Data wrong in Vector");
			else{
				if(putDataIntoDataBuffer(v)==(secondForCCA-1)){
					CCA();//CCA
					modifyScale();//modify scale
					invalidate();//paint
				}
			}	
		}
		private int putDataIntoDataBuffer(Vector v){
			double []a,b,c,d;
			if(filterTag){
				a = firCH1.filter((double[])v.elementAt(0));
				b = firCH2.filter((double[])v.elementAt(1));
				c = firCH3.filter((double[])v.elementAt(2));
				d = firCH4.filter((double[])v.elementAt(3));
			}
			else{
				a = (double[])v.elementAt(0);
				b = (double[])v.elementAt(1);
				c = (double[])v.elementAt(2);
				d = (double[])v.elementAt(3);
			}
			if(indexForDataBuffer==(secondForCCA-1)){
				//move data to previous one sec.
				for (int i = 0; i < (secondForCCA-1); i++) {
                    for (int j = 0; j < sampleRate; j++) {
                    	ch1Buffer[i * sampleRate +j] = ch1Buffer[i * sampleRate + j + sampleRate];
                    	ch2Buffer[i * sampleRate +j] = ch2Buffer[i * sampleRate + j + sampleRate];
                    	ch3Buffer[i * sampleRate +j] = ch3Buffer[i * sampleRate + j + sampleRate];
                    	ch4Buffer[i * sampleRate +j] = ch4Buffer[i * sampleRate + j + sampleRate];
                    }
                }
				/*System.arraycopy(ch1Buffer, sampleRate, ch1Buffer, 0, (secondForCCA-1)*sampleRate);
				System.arraycopy(ch2Buffer, sampleRate, ch2Buffer, 0, (secondForCCA-1)*sampleRate);
				System.arraycopy(ch3Buffer, sampleRate, ch3Buffer, 0, (secondForCCA-1)*sampleRate);
				System.arraycopy(ch4Buffer, sampleRate, ch4Buffer, 0, (secondForCCA-1)*sampleRate);*/
				//insert data to last sec.
				System.arraycopy(a, 0, ch1Buffer, indexForDataBuffer*sampleRate, sampleRate);
				System.arraycopy(b, 0, ch2Buffer, indexForDataBuffer*sampleRate, sampleRate);
				System.arraycopy(c, 0, ch3Buffer, indexForDataBuffer*sampleRate, sampleRate);
				System.arraycopy(d, 0, ch4Buffer, indexForDataBuffer*sampleRate, sampleRate);
			}
			else{
				System.arraycopy(a, 0, ch1Buffer, indexForDataBuffer*sampleRate, sampleRate);
				System.arraycopy(b, 0, ch2Buffer, indexForDataBuffer*sampleRate, sampleRate);
				System.arraycopy(c, 0, ch3Buffer, indexForDataBuffer*sampleRate, sampleRate);
				System.arraycopy(d, 0, ch4Buffer, indexForDataBuffer*sampleRate, sampleRate);
			}
			indexForDataBuffer++;
			if(indexForDataBuffer==secondForCCA)
				indexForDataBuffer--;
			//msgToDisplay = Integer.toString(indexForDataBuffer);
			return indexForDataBuffer;
		}
		private void CCA(){
			if(DEBUG)Log.e(TAG, "In CCA()");
			CCAResultBuffer = cca.CCA(ch1Buffer, ch2Buffer, ch3Buffer, ch4Buffer, secondForCCA*sampleRate);
		}
		private void modifyScale(){
			if(DEBUG)Log.e(TAG, "In modifyScale()");
			//seek the maximum
			double AmaxValue = 0.0;
	        double Atemp = 0;
	        for (int i = displayFrom; i <= displayTo; i++) {
	            AmaxValue = Math.max(AmaxValue, (CCAResultBuffer[i]));
	            if (AmaxValue != Atemp) {
	            	MaxIndex = i;
	                Atemp = AmaxValue;
	            }
	        }
	        for(int i=0;i<(displayTo - displayFrom+1);i++){
	        	info[i] = CCAResultBuffer[displayFrom+i];
	        	//msgToDisplay+="\n";
	        }
	        info[info.length-1]=MaxIndex;
	        //msgToDisplay = MaxIndex+"/"+Atemp+"/";
	        //ch1FFTResultBuffer[i] = ch1FFTResultBuffer[i]*(frameHeight/AmaxValue)*(-1)+frameHeight;
	        //modify scale and shift
	        XAxis[displayFrom-2] =0;
	        for(int i=0;i<=displayTo;i++)	{
	        	XAxis[i] = i*barThickLevel+leftSideGap-XAxis[displayFrom-2];//22= thick level
	        	CCAResultBuffer[i] = CCAResultBuffer[i]*(frameHeight/AmaxValue)*(-1)+frameHeight;
	        }
	        //msgToDisplay +=XAxis[42]+"/";
		}
		protected void onDraw(Canvas canvas){
			super.onDraw(canvas);
			if(DEBUG)Log.e(TAG, "onDraw!");
			canvas.drawColor(Color.BLACK);//clear old canvas
			paint.setStyle(Paint.Style.FILL);
			paint.setTextSize(20);
			//paint new graphic
			paint.setColor(Color.WHITE);
	        for (int i = displayFrom; i < displayTo; i++) {
	        	paint.setColor(Color.WHITE);
	            if (i % 4 == 0) {
	                canvas.drawText(Integer.toString(i / 4 + 1),
	                             XAxis[i],frameHeight+20,paint);
	                if ((i + 0.5) < displayTo)
	                    canvas.drawText(Double.toString(i / 4 + 1.5),
	                                 XAxis[i+2],frameHeight+20,paint);
	                }
	            //canvas.drawLine(XAxis[i], 0, XAxis[i],frameHeight,paint);
	            //paint.setStyle(Paint.Style.FILL);
	            paint.setColor(Color.YELLOW);
	            canvas.drawRect((float)XAxis[i],(float)(CCAResultBuffer[i]),(float)XAxis[i]+barThickLevel, (float)frameHeight,paint);
	        }
	        paint.setColor(Color.WHITE);
	         //set color as black
	        canvas.drawLine(leftSideGap, topGap, leftSideGap, frameHeight,paint); //Cor. of Y
	        canvas.drawLine(leftSideGap, frameHeight, XAxis[displayTo]+1,frameHeight,paint); //Cor. of X
	        paint.setTextSize(20);
	        canvas.drawText("Cor.", leftSideGap-30, topGap, paint);
	        canvas.drawText("(%)", leftSideGap-30, topGap+15,paint);
	        canvas.drawText("Hz", XAxis[displayTo],frameHeight+10, paint);
	        //canvas.drawText(msgToDisplay, frameWidth/2, topGap, paint);
	        for(float index=9,interval=20,i=0;index<=11.75;index+=0.25,i++){
	        	canvas.drawText(index+"Hz, "+Double.toString(info[(int)i]*100)+"%", frameWidth/2, topGap+interval*i, paint);
	        }

		}
		protected void onDraw1(Canvas canvas) {
			super.onDraw(canvas);
			if(DEBUG)Log.e(TAG, "onDraw!");
			//clear old canvas
			canvas.drawColor(Color.BLACK);
			paint.setStyle(Paint.Style.STROKE);
			paint.setTextSize(1);
			//paint new graphic
			paint.setColor(Color.YELLOW);
			for (int i=displayFrom;i<=displayTo;i++){	
				canvas.drawLine((int)XAxis[i],(int)CCAResultBuffer[i],(int)XAxis[i+1],(int)CCAResultBuffer[i+1],paint);
			}
			paint.setStyle(Style.FILL);	
			paint.setColor(Color.GRAY);
			paint.setTextSize(15);
			//ch1 and ch2 x axis symbol
			canvas.drawText("8", XAxis[28], frameHeight, paint);
			canvas.drawText("9", XAxis[32], frameHeight, paint);
			canvas.drawText("9.25", XAxis[33], frameHeight, paint);
			canvas.drawText("9.5", XAxis[34], frameHeight, paint);
			canvas.drawText("9.75", XAxis[35], frameHeight, paint);
			canvas.drawText("10", XAxis[36], frameHeight, paint);
			canvas.drawText("10.25", XAxis[37], frameHeight, paint);
			canvas.drawText("10.5", XAxis[38], frameHeight, paint);
			canvas.drawText("10.75", XAxis[39], frameHeight, paint);
			canvas.drawText("11", XAxis[40], frameHeight, paint);
			canvas.drawText("11.25", XAxis[41], frameHeight, paint);
			canvas.drawText("11.5", XAxis[42], frameHeight, paint);
			canvas.drawText("11.75", XAxis[44], frameHeight, paint);
			canvas.drawText("Hz", XAxis[44]+40, frameHeight, paint);
			canvas.drawText(msgToDisplay, 100, 100, paint);
			//canvas.drawText(Double.toString(CCAResultBuffer[10])+"/"+Double.toString(CCAResultBuffer[36])+"/"+Double.toString(CCAResultBuffer[36])+"/"+Double.toString(CCAResultBuffer[36]), 0, 250, paint);
			//canvas.drawText(Integer.toString(frameHeight)+"/"+Double.toString(frameWidth), 250,300, paint);
			//Log.e("onDraw", "******************"+Integer.toString(getHeight())+"**"+Integer.toString(getWidth()));			
		}
		private final Handler mHandler = new Handler() {
	        public void handleMessage(Message msg) {
	            switch (msg.what) {
	            case 0://repaint            	
	            	invalidate();
	           	 break;
	            case 1://fill in data
	            	//msgToDisplay = Integer.toString((Integer)msg.obj);
	            	//invalidate();
	            	setData((Vector)msg.obj);
	           	 break;
	            case 2:
	           	 break;
	            }
	        }
	    };
		public boolean onTouch(View v, MotionEvent e) {
			handleTwoFingers(e);
			handleOneFingerSwipe(e);
			return false;//if return true, the onLongClick can't work.
		}
		public boolean onLongClick(View v) {
			//msgToDisplay = "11111111111";
			new AlertDialog.Builder(this.getContext())
	        //.setIcon(R.drawable.alert_dialog_icon)
	        .setTitle(R.string.app_name)
	        .setSingleChoiceItems(R.array.select_dialog_items2, 0, new DialogInterface.OnClickListener() {
	            public void onClick(DialogInterface dialog, int whichButton) {
	            	switch(whichButton){
	            	case 0:
	            		selectionForNextDisplay = 0;//button 1 pressed, Time mode display
	            		break;
	            	case 1:
	            		selectionForNextDisplay = 1;//button 2 pressed, Frequency mode display
	            		break;
	            	case 2:
	            		selectionForNextDisplay = 2;//button 3 pressed, CCA display
	            		break;
	            	case 3:
	            		selectionForNextDisplay = 3;//button 4 pressed, Debug mode
	            		break;
	            	}
	            }
	        })
	        .setPositiveButton(R.string.timeDomainDialog_button_ok, new DialogInterface.OnClickListener() {
	            public void onClick(DialogInterface dialog, int whichButton) {
	            	if(selectionForNextDisplay !=-1){
	            		msgToDisplay = "selectionForNextDisplay"+"/pressed";
	            	}
	            	selectionForNextDisplay =-1;//in case user didn't press any of mode to display, and press OK/CANCEL only.
	            }
	        })
	        .setNegativeButton(R.string.timeDomainDialog_button_cancel, new DialogInterface.OnClickListener() {
	            public void onClick(DialogInterface dialog, int whichButton) {
	            	msgToDisplay += "3/";	
	                // User clicked No so do some stuff 
	            }
	        })
	       .show();
			if(DEBUG)Log.e(TAG, "onLongClick!\n");
			return true;
		}
		private void handleOneFingerSwipe(MotionEvent event){
			
			int action = event.getAction();
			int actionCode = action & MotionEvent.ACTION_MASK;
			if(actionCode == MotionEvent.ACTION_DOWN && event.getPointerCount()==1){
				oriXAxis = event.getX();
				oriYAxis = event.getY();
				if(DEBUG)Log.e(TAG, "oriXAxis= "+oriXAxis+"\n");
			}
			if(actionCode == MotionEvent.ACTION_MOVE &&event.getPointerCount()==1){
				if(event.getX()>oriXAxis && (event.getX()-oriXAxis >MIN_SLIDE_DISTANCE)){//swipe to right, to FFTDomain
					finish();
					startActivity(new Intent(CCADomainActivity.this, FrequencyDomainActivity.class));
					if(DEBUG)Log.e(TAG, "SWIPE TO RIGHT! /oriXAxis= "+oriXAxis+" / "+event.getX()+"\n");
				}
				else if(event.getX()<oriXAxis && (oriXAxis-event.getX() >MIN_SLIDE_DISTANCE)){//swipe to left, to CCA2sec
					finish();
					startActivity(new Intent(CCADomainActivity.this, CCADomainActivity2.class));
					if(DEBUG)Log.e(TAG, "SWIPE TO LEFT! /oriXAxis= "+oriXAxis+" / "+event.getX()+"\n");
				}
				//swipe up, turn the Filter
				else if(event.getY()<oriYAxis &&(oriYAxis-event.getY()>MIN_SLIDE_DISTANCE)){
					filterTag = true;
					popMsg.makeText( this.getContext(), R.string.Enable_Band_Pass_Filter,popMsg.LENGTH_SHORT).show();
				}
				//swipe down, turn off the filter
				else if(event.getY()>oriYAxis &&(event.getY()-oriYAxis>MIN_SLIDE_DISTANCE)){
					filterTag = false;
					popMsg.makeText( this.getContext(), R.string.Disable_Band_Pass_Filter,popMsg.LENGTH_SHORT).show();
				}
			}
		}
		private void handleTwoFingers(MotionEvent event) {
			float newDistanceOfFingers;
			int action = event.getAction();
			int actionCode = action & MotionEvent.ACTION_MASK;
			if(actionCode == MotionEvent.ACTION_POINTER_DOWN && event.getPointerCount()==2){
				oriDistanceOfFingers = FloatMath.sqrt((event.getX(0)-event.getX(1)) * (event.getX(0)-event.getX(1)) + 
						(event.getY(0)-event.getY(1)) * (event.getY(0)-event.getY(1)));
				//Log.e("******","ori= "+oriDistanceOfFingers);
			}
			if(actionCode == MotionEvent.ACTION_MOVE &&event.getPointerCount()==2){
				newDistanceOfFingers = FloatMath.sqrt((event.getX(0)-event.getX(1)) * (event.getX(0)-event.getX(1)) + 
						(event.getY(0)-event.getY(1)) * (event.getY(0)-event.getY(1)));
				//Log.e("******","new= "+newDistanceOfFingers);
				if(newDistanceOfFingers < oriDistanceOfFingers){
					msgToDisplay = "Zoom Out";	
					//popMsg.makeText( this.getContext(), R.string.ZoomOut_text,popMsg.LENGTH_SHORT).show();
					//Log.e("******","CCCCCCCCCc");
				}
				else{
					msgToDisplay = "Zoom In";
					//popMsg.makeText(getContext(), R.string.ZoomIn_text,popMsg.LENGTH_SHORT).show();
					//Log.e("******","DDDDDDDDDD");
				}
			}
		}
	}
}
