package com.penpower.apparch.keyboard.handwrite;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.penpower.ime.hwr.JNISDK_HWR_Client;

import java.lang.reflect.Array;
import java.util.ArrayList;

public class HandWritingView extends View {

	static final boolean DEBUG = false;
	static final String TAG = "HandwritingView";
	 private static final short MAX_STROKE = 2048; // 1024點(包含結束符號(-1,0))
	 private static final short MAX_CANDIDATE = 1200;
	 private static final short BORDERSIZE = 8;
	 private static final int MAX_POSITION = 65535; // 最大座標
	 private static final int RECT_OFFSET = 10;
	 private static final int SWITCH_OFFSET = 5;
	 private static final short THRESHOLD = 10;
	 private short mRecogMode = RECOG_UNKNOW; // 辨識模式:全部字集/英文/數符 辨識
	   private static final short RECOG_UNKNOW = 0;
	    private static final short RECOG_ALL = 1; // 全部字集
	    private static final short RECOG_ABC = 2; // 英文字集
	    private static final short RECOG_123 = 3; // 數符字集
	 
	 private WritingTimer mTimer = new WritingTimer();
	private short mInputStrokeIndex = 0;
    private short mInputStrokeNum = 0;
    public short  mInputStrokeTotalNum=0;
    private short mInputStroke1[] = new short[MAX_STROKE];
    private short mInputStroke2[] = new short[MAX_STROKE];
    private short[] mInputStroke = mInputStroke1;
    private short[] mInputStrokePtr = mInputStroke1;
    private char mResult[]=new char[1024];
    private char mBoxStr[] = new char[21];
    private short mDelayTime = 500;
    private char mCandidates[] = new char[MAX_CANDIDATE];
    private int mCandidates32[] = new int[MAX_CANDIDATE];

    private final ArrayList<Float> mXs = new ArrayList<Float>();
    private final ArrayList<Float> mYs = new ArrayList<Float>();
    public final ArrayList<Short[]> mAllStroke = new ArrayList<Short[]>();
    public final ArrayList<Short> mAllStrokeNum = new ArrayList<Short>();
    public short msStorkeCount = 0;
    private float mLastX = 0.0f, mLastY = 0.0f;
    private int mStartRectX = MAX_POSITION, mStartRectY = MAX_POSITION, mEndRectX = 0, mEndRectY = 0;
    private int mMaxTop = MAX_POSITION, mMaxLeft = MAX_POSITION, mMaxBottom = 0, mMaxRight = 0;
    private int mLeft = MAX_POSITION, mTop = MAX_POSITION, mRight = 0, mBottom = 0;
    
    private PP_HW_Demo mManActivity=null;
    private Context mContext;
    
    public HandWritingView(Context context, AttributeSet attrs) {
    	super(context, attrs);
		// TODO Auto-generated constructor stub
		
		 // 設定筆跡畫筆屬性
        mPenPaint.setColor(0xFFFF0000);
        mPenPaint.setStyle(Paint.Style.STROKE);
        mPenPaint.setStrokeJoin(Paint.Join.ROUND);
        mPenPaint.setStrokeCap(Paint.Cap.ROUND);
        mPenPaint.setStrokeWidth(4);        
        mInputStrokePtr = mInputStroke;
	    mInputStrokeIndex = 0;
	    mContext = context;
	}
    public void setManActivity(PP_HW_Demo activity)
    {
    	mManActivity = activity;
    }
    @Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		canvas.drawColor(0xFFD8D8D8);
		if(mInputStrokeIndex < MAX_STROKE)
    	{
            final int N = mXs.size();
            float x = 0.0f, y = 0.0f;

        	for(int i=0; i < N; i++)
            {
                x = mXs.get(i);
                y = mYs.get(i);

                if(i == 0)
                {
        			mLastX = x;
        			mLastY = y;
                }
                else if((i > 0 && x > 0 && y > 0))
                {
                    canvas.drawLine(mLastX, mLastY, x, y, mPenPaint);
                    mLastX = x;
                    mLastY = y;
                }
                else if(i > 0 && i < (N-1) && (x < 0 && y < 0))
                {
                	i++;
                	mLastX = mXs.get(i);
                	mLastY = mYs.get(i);
                }
            }
           	mStartRectX = (int)mLastX;
           	mStartRectY = (int)mLastY;
    	}

	}

    private void AddHistoryPoint(MotionEvent event, boolean bTwoFrame)
    {
        final int N = event.getHistorySize();
    	float xdiff = 0.0f, ydiff = 0.0f;

    	// 過濾軌跡,將符合條件軌跡繪出和儲存至軌跡buffer
        for(int i = 0; i < N; i++)
        {
            float xpos = event.getHistoricalX(i);
            float ypos = event.getHistoricalY(i);

    		int x = (int)xpos;
    		int y = (int)ypos;

       		if(x < mLeft)
       		{
       			mLeft = x;
       		}
       		if(y < mTop)
       		{
       			mTop = y;
       		}

       		if(x > mRight)
       		{
       			mRight = x;
       		}
       		if(y > mBottom)
       		{
       			mBottom = y;
       		}

       		if(mXs.size() > 0 && mYs.size() > 0)
       		{
	        	int xlocation = mXs.size() - 1;
	        	int ylocation = mYs.size() - 1;
	        	xdiff = Math.abs(mXs.get(xlocation) - xpos);
	        	ydiff = Math.abs(mYs.get(ylocation) - ypos);
	        	if((xdiff+ydiff) > THRESHOLD || mXs.size() < THRESHOLD)
	        	{
	                if(mInputStrokeIndex < (MAX_STROKE-2))
	                {
	                	
	                	
	                	mInputStroke[mInputStrokeIndex++] = (short)xpos;
	                    mInputStroke[mInputStrokeIndex++] = (short)ypos;
	                    mInputStrokeNum++;
	                	
	                }
	        	}
       		}
        }
    }
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		
		 float x = event.getX();
	     float y = event.getY();
	     
	     mEndRectX = (int)x;
	     mEndRectY = (int)y;
	     mTop = MAX_POSITION; 
	     mLeft = MAX_POSITION;
	     mBottom = 0;
	     mRight = 0;
	     switch(event.getAction())
	     {
	     case MotionEvent.ACTION_DOWN:
	    	 mTimer.removeTimer();

	         mStartRectX = (int)x;
	         mStartRectY = (int)y;
	         if(mInputStrokeIndex < (MAX_STROKE-2))
	           	{
	           		touch_start(x, y);	           		
		            invalidateDownRect();
		            
	           	}
	    	 break;
	     case MotionEvent.ACTION_MOVE:
	    	 AddHistoryPoint(event, false);
	    	
	    	 if(mInputStrokeIndex < (MAX_STROKE-2))
	           	{
	    		
	                float xdiff = 0.0f;
	                float ydiff = 0.0f;
	                if(mXs.size() > 0)
	                {
	                	xdiff = Math.abs(x - mXs.get(mXs.size()-1));
	                }

	                if(mYs.size() > 0)
	                {
	                	ydiff = Math.abs(y - mYs.get(mYs.size()-1));
	                }

	            	if(mXs.size() < THRESHOLD || (xdiff+ydiff) > THRESHOLD)
	            	{
	            		mInputStroke[mInputStrokeIndex++] = (short)x;
	                    mInputStroke[mInputStrokeIndex++] = (short)y;
	                    mInputStrokeNum++;
		            	MaxRect((int)x, (int)y);
		            	mXs.add(x);
		            	mYs.add(y);
	            	}		            
		            invalidateRect();
		            
	           	}
	    	 break;
	     case MotionEvent.ACTION_UP:
	    		if(mInputStrokeIndex < (MAX_STROKE-2))
	           	{
	    			
	                touch_up();
		            mXs.add(x);
		            mYs.add(y);
		            MaxRect((int)x, (int)y);
		            invalidateRect();
	           	}

	           	// 筆跡結束符號
            	mXs.add(-1.0f);
            	mYs.add(-1.0f);
            	mInputStrokePtr = mInputStroke;
            	msStorkeCount+=1;
            	
            	
            	
		        mTimer.startTimer(mDelayTime);
	    	 break;
	     }
		//return super.onTouchEvent(event);
	     return true;
	}

	private void touch_start(float x, float y)
    {
    	

    	mInputStroke[mInputStrokeIndex++] = (short)x;
        mInputStroke[mInputStrokeIndex++] = (short)y;
        mInputStrokeNum++;
        MaxRect((int)x, (int)y);

        mXs.add(x);
        mYs.add(y);
    }
	public void InputStrokeClear()
    {
        if(DEBUG)
        {
        	Log.d(TAG, "InputStrokeClear");
        }

        mTimer.removeTimer();

        // 清除筆跡
        mXs.clear();
        mYs.clear();
        
        mAllStroke.clear();
        mInputStrokeTotalNum =0;
        msStorkeCount = 0;
        mAllStrokeNum.clear();

        for(int i=0;i<Array.getLength(mResult);i++)
        	mResult[i]= 0;
        if(mMaxLeft!=MAX_POSITION || mMaxTop!=MAX_POSITION || mMaxRight!=0 || mMaxBottom!=0) {
        	invalidate(mMaxLeft, mMaxTop, mMaxRight, mMaxBottom);

            mMaxLeft = MAX_POSITION;
            mMaxTop = MAX_POSITION;
            mMaxRight = 0;
            mMaxBottom = 0;

        	mTop = MAX_POSITION; 
        	mLeft = MAX_POSITION;
        	mBottom = 0;
        	mRight = 0;
        }

		mStartRectX = MAX_POSITION;
		mStartRectY = MAX_POSITION;
		mEndRectX = 0;
		mEndRectY = 0;

        mRecogMode = RECOG_UNKNOW;
    	for(int i=0; i <= mInputStrokeIndex; i++)
    	{
    		mInputStrokePtr[i] = 0;
    	}
    	mInputStrokeIndex = 0;
    }
	 private void MaxRect(int x, int y)
	    {
	        if(x < mMaxLeft)
	        {
	        	mMaxLeft = x - 2*RECT_OFFSET;
	        	if(mMaxLeft < 0)
	        	{
	        		mMaxLeft = 0;
	        	}
	        }

	        if(y < mMaxTop)
	        {
	        	mMaxTop = y - 2*RECT_OFFSET;
	        	if(mMaxTop < 0)
	        	{
	        		mMaxTop = 0;
	        	}
	        }

	        if(x > mMaxRight)
	        {
	        	mMaxRight = x + 2*RECT_OFFSET;
	        	if(mMaxRight > getRight())
	        	{
	        		mMaxRight = getRight();
	        	}
	        }

	        if(y > mMaxBottom)
	        {
	        	mMaxBottom = y + 2*RECT_OFFSET;
	        	if(mMaxBottom > getBottom())
	        	{
	        		mMaxBottom = getBottom();
	        	}
	        }
	    }
    private void touch_up()
    {
    	if(mInputStroke == null)
    	{
    		return;
    	}

       	if(mInputStrokeIndex > 0)
       	{
	    	if(mInputStrokeNum == 1)
	    	{
	            // 當只有1點,額外補1點
	    		short mX = mInputStroke[mInputStrokeIndex-2];
	    		short mY = (short)(mInputStroke[mInputStrokeIndex-1] + 2);
	            mInputStroke[mInputStrokeIndex++] = mX;
	            mInputStroke[mInputStrokeIndex++] = mY;
	          
	    	}

	    	// 提筆時,此筆劃加上(-1,0)作為此筆劃結束符號
	    	// 提筆時,此筆劃加上(-1,-1)作為此筆劃結束符號,隔一段時間才一起送筆跡
	    	// 所以中間的筆跡結尾改成-1,-1
	    	if(mInputStroke[mInputStrokeIndex-2]!=-1)
	    	{
	    		
	            mInputStroke[mInputStrokeIndex++] = -1;
	            mInputStroke[mInputStrokeIndex++] = -1;
	          
	    	}
	    	
       	}
    }

    private void invalidateDownRect()
    {
    	int nTop = 0, nLeft = 0, nBottom = 0, nRight = 0;
    	nLeft = mStartRectX - RECT_OFFSET;
    	nTop = mStartRectY - RECT_OFFSET;
    	nRight = mEndRectX + RECT_OFFSET;
    	nBottom = mEndRectY + RECT_OFFSET;

    	if(nLeft < 0)
    	{
    		nLeft = 0;
    	}
    	if(nTop < 0)
    	{
    		nTop = 0;
    	}
    	if(nRight > getRight())
    	{
    		nRight = getRight();
    	}
    	if(nBottom > getBottom())
    	{
    		nBottom = getBottom();
    	}

    	if(mMaxTop > nTop)
    	{
    		mMaxTop = nTop;
    	}
    	if(mMaxLeft > nLeft)
    	{
    		mMaxLeft = nLeft;
    	}
    	if(mMaxBottom < nBottom)
    	{
    		mMaxBottom = nBottom;
    	}
    	if(mMaxRight < nRight)
    	{
    		mMaxRight = nRight;
    	}

    	invalidate(nLeft, nTop, nRight, nBottom);
    }

    private void invalidateRect()
    {
    	int nTop = 0, nLeft = 0, nBottom = 0, nRight = 0;
		if(mStartRectX < mLeft)
		{
			mLeft = mStartRectX;
		}
		if(mStartRectY < mTop)
		{
			mTop = mStartRectY;
		}

		if(mStartRectX > mRight)
		{
			mRight = mStartRectX;
		}
		if(mStartRectY > mBottom)
		{
			mBottom = mStartRectY;
		}

		if(mEndRectX < mLeft)
		{
			mLeft = mEndRectX;
		}
		if(mEndRectY < mTop)
		{
			mTop = mEndRectY;
		}

		if(mEndRectX > mRight)
		{
			mRight = mEndRectX;
		}
		if(mEndRectY > mBottom)
		{
			mBottom = mEndRectY;
		}

    	nLeft = mLeft - RECT_OFFSET;
    	nTop = mTop - RECT_OFFSET;
    	nRight = mRight + RECT_OFFSET;
    	nBottom = mBottom + RECT_OFFSET;

    	if(nLeft < 0)
    	{
    		nLeft = 0;
    	}
    	if(nTop < 0)
    	{
    		nTop = 0;
    	}
    	if(nRight > getRight())
    	{
    		nRight = getRight();
    	}
    	if(nBottom > getBottom())
    	{
    		nBottom = getBottom();
    	}

    	if(mMaxTop > nTop)
    	{
    		mMaxTop = nTop;
    	}
    	if(mMaxLeft > nLeft)
    	{
    		mMaxLeft = nLeft;
    	}
    	if(mMaxBottom < nBottom)
    	{
    		mMaxBottom = nBottom;
    	}
    	if(mMaxRight < nRight)
    	{
    		mMaxRight = nRight;
    	}

    	invalidate(nLeft, nTop, nRight, nBottom);
    }

	private final Paint mPenPaint = new Paint();
	
	
	private class WritingTimer extends Handler implements Runnable
    {
        private int mIndex = 0;
        private int mInputAreaRun = 1;
        public boolean mTimerPending = false;

        public WritingTimer()
        {
            super();
        }

        public void startTimer(long afterMillis)
        {
            removeTimer();
            mTimerPending = true;
            postDelayed(this, afterMillis);
        }

        public boolean removeTimer()
        {
            if(mTimerPending)
            {
                mTimerPending = false;
                removeCallbacks(this);
                return true;
            }

            return false;
        }

        public void run()
        {
        	//String gSignature = "0123456789";
        	mIndex = mInputStrokeIndex;
        	mInputStrokePtr = mInputStroke;
            // 開始辨識
        	mInputStroke[mInputStrokeIndex-1] = 0;
         	int num = JNISDK_HWR_Client.PPHWRRecognize(mInputStrokePtr, mCandidates);
         	Log.d(TAG, "returned candidate count = " + num);
         	if(num > 0){
         	  int i;
         	  
         	  short Candidates[] = new short[MAX_CANDIDATE];
         	  for(i=0; i < num; i++){
         		Candidates[i] = (short)mCandidates[i*2];
         	  }
         	  Candidates[i] =0;
				JNISDK_HWR_Client.PPHWRConvertUTF16_2_UTF32(Candidates, mCandidates32, num);
         	  mCandidates32[num]=0;
         	  
         	  for(i = 0; i < num ; i++ ) {
         	    Log.d( TAG, "mCandidates32["+i+"] = "+"0x"+Integer.toHexString(mCandidates32[i]));
         	  }
         	}
         	for(int i=0; i <= mInputStrokeIndex; i++)
         	{
         		mInputStrokePtr[i] = 0;
         	}
        	
        	mManActivity.setCandidateList32(mCandidates32);

        	mInputStrokeTotalNum = (short) (mInputStrokeIndex/2);
        	mInputStrokeNum = 0;
        	mInputStrokeIndex = 0;
            mTimerPending = false;
           }
    }

}
