package com.cwbuyer.lib;

import java.math.BigDecimal;

import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.pwbuyer.main.R;

public class Calculator {
	
	View mView = null;
	Context mCnt = null;
	TextView mInput = null;
	TextView mPreview = null;
	StringBuffer mBuf = new StringBuffer();
	StringBuffer mPrevBuf = new StringBuffer();
	double mPreNumber = 0;
	int mPreOpreate = 0;
	boolean mbPrint = false;
	boolean mbOpreate = false;
	
	interface OpreateMode{
		int PLUS = 1;
		int MINUS = 2;
		int MULTIPLE = 3;
		int DIVISION = 4;
	}
	
	public Calculator(Context cnt, View root){
		mCnt = cnt;
		mView = root;
		mInput = (TextView) mView.findViewById(R.id.text_print);
		mPreview = (TextView) mView.findViewById(R.id.text_preview);
		try{
			((Button)mView.findViewById(R.id.btn_number_0)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_1)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_2)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_3)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_4)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_5)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_6)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_7)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_8)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_9)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_00)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_number_spot)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_opreate_1)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_opreate_2)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_opreate_3)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_opreate_4)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_backspace)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_clean_number)).setOnClickListener(new ProcessKeypadInput());
			((Button)mView.findViewById(R.id.btn_result)).setOnClickListener(new ProcessKeypadInput());
			
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	// 特殊使用 直接存取數值
	public void setBuffer(String strValue){
		mBuf.append(strValue);
	}
	
	public void clear(){
		mCnt = null;
		mView = null;
		mPreview = null;
		mBuf = null;
		mPrevBuf = null;
	}
	
	public void processNumber(String number){
		if(mbOpreate == true || mbPrint == true){
			mBuf.delete(0, mBuf.length());
			mbPrint = false;
		}
		if(mBuf.length() >= 1){
			if(mBuf.charAt(0) == '0' && mBuf.indexOf(".") < 0){
				int len = mBuf.length();
				if(len > 0){
					mBuf.delete(0, len);
				}
			}
		}
		if(number.equalsIgnoreCase(".")){
			if(mBuf.length() <= 0){
				mBuf.append("0");
			}else{
				if(mBuf.indexOf(number) >= 0){
					mbOpreate = false;
					return;
				}
			}
		}
		
		mBuf.append(number);
		mInput.setText(mBuf.toString());
		mbOpreate = false;
	}
	
	public void processOpreate(String opreate){
		mbPrint = false;
		if(mbOpreate == false){ // 第一次按下加減乘除
			if(mPrevBuf.length() > 0){
				// 就先計算結果
				double curNumber = Utilis.toDouble(mInput.getText().toString());
				switch(mPreOpreate){
					case OpreateMode.PLUS:
//						mPreNumber = mPreNumber + curNumber;
						mPreNumber = Arith.round(Arith.add(mPreNumber, curNumber), 4);
						break;
					case OpreateMode.MINUS:
//						mPreNumber = mPreNumber - curNumber;
						mPreNumber = Arith.round(Arith.sub(mPreNumber, curNumber), 4);
						break;
					case OpreateMode.MULTIPLE:
//						mPreNumber = mPreNumber * curNumber;
						mPreNumber = Arith.round(Arith.mul(mPreNumber, curNumber), 4);
						break;
					case OpreateMode.DIVISION:
//						mPreNumber = mPreNumber / curNumber;
						mPreNumber = Arith.round(Arith.div(mPreNumber, curNumber), 4);
						break;
				}
				if(mPreNumber % 1 > 0){
					mInput.setText("" + mPreNumber);
				}else{
					mInput.setText("" + ((int)mPreNumber));
				}
			}else{
				mPreNumber = Utilis.toDouble(mInput.getText().toString());
			}
			mPrevBuf.append(mBuf.toString()).append(" ").append(opreate);
			mPreview.setText(mPrevBuf.toString());
			mbOpreate = true;
		}else{
//			mPrevBuf.delete(mPrevBuf.length() - 1, mPrevBuf.length());
			mPrevBuf.deleteCharAt(mPrevBuf.length() - 1);
			mPrevBuf.append(opreate);
			mPreview.setText(mPrevBuf.toString());
		}
		
		if(opreate.equalsIgnoreCase("+")){
			mPreOpreate = OpreateMode.PLUS;
		}else if(opreate.equalsIgnoreCase("-")){
			mPreOpreate = OpreateMode.MINUS;
		}else if(opreate.equalsIgnoreCase("×")){
			mPreOpreate = OpreateMode.MULTIPLE;
		}else if(opreate.equalsIgnoreCase("÷")){
			mPreOpreate = OpreateMode.DIVISION;
		}
//		mBuf.append(opreate);
//		mInput.setText(mBuf.toString());
	}
	
	public void cleanNumber(){
		int len = mBuf.length();
		if(len > 0){
			mBuf.delete(0, len);
		}
		int len2 = mPrevBuf.length();
		if(len2 > 0){
			mPrevBuf.delete(0, len2);
		}
//		mBuf.append("0");
		mPreNumber = 0;
		mbOpreate = false;
		mPreOpreate = 0;
		mPreview.setText("");
		mInput.setText("0");
	}
	
	public void resultNumber(){
		if(mPrevBuf.length() > 0){
			double curNumber = Utilis.toDouble(mInput.getText().toString());
			switch(mPreOpreate){
				case OpreateMode.PLUS:
	//				mPreNumber = mPreNumber + curNumber;
					mPreNumber = Arith.round(Arith.add(mPreNumber, curNumber), 4);
					break;
				case OpreateMode.MINUS:
	//				mPreNumber = mPreNumber - curNumber;
					mPreNumber = Arith.round(Arith.sub(mPreNumber, curNumber), 4);
					break;
				case OpreateMode.MULTIPLE:
	//				mPreNumber = mPreNumber * curNumber;
					mPreNumber = Arith.round(Arith.mul(mPreNumber, curNumber), 4);
					break;
				case OpreateMode.DIVISION:
	//				mPreNumber = mPreNumber / curNumber;
					mPreNumber = Arith.round(Arith.div(mPreNumber, curNumber), 4);
					break;
			}
			
			mbOpreate = false;
			mPreOpreate = 0;
			mPreview.setText("");
			if(mPreNumber % 1 > 0){
				mInput.setText("" + mPreNumber);
			}else{
				mInput.setText("" + ((int)mPreNumber));
			}
			int len = mBuf.length();
			if(len > 0){
				mBuf.delete(0, len);
			}
			int len2 = mPrevBuf.length();
			if(len2 > 0){
				mPrevBuf.delete(0, len2);
			}
			mBuf.append(mInput.getText().toString());
		}
		mbPrint = true;
	}
	
	public void backNumber(){
		int len = mBuf.length();
		if(len > 0){
			mBuf.deleteCharAt(len -1 );
			mInput.setText(mBuf.toString());
		}
	}	
	
	class ProcessKeypadInput implements OnClickListener{
		@Override
		public void onClick(View v) {
			Utilis.runVibrate(mCnt);
			int id = v.getId();
			switch(id){
				case R.id.btn_number_0:
					processNumber("0");
					break;
				case R.id.btn_number_00:
					processNumber("00");
					break;
				case R.id.btn_number_1:
					processNumber("1");
					break;
				case R.id.btn_number_2:
					processNumber("2");
					break;
				case R.id.btn_number_3:
					processNumber("3");
					break;
				case R.id.btn_number_4:
					processNumber("4");
					break;
				case R.id.btn_number_5:
					processNumber("5");
					break;
				case R.id.btn_number_6:
					processNumber("6");
					break;
				case R.id.btn_number_7:
					processNumber("7");
					break;
				case R.id.btn_number_8:
					processNumber("8");
					break;
				case R.id.btn_number_9:
					processNumber("9");
					break;
				case R.id.btn_number_spot:
					processNumber(".");
					break;
				case R.id.btn_opreate_1:
					processOpreate("+");
					break;
				case R.id.btn_opreate_2:
					processOpreate("-");
					break;
				case R.id.btn_opreate_3:
					processOpreate("×");
					break;
				case R.id.btn_opreate_4:
					processOpreate("÷");
					break;
				case R.id.btn_backspace:
					backNumber();
					break;
				case R.id.btn_clean_number:
					cleanNumber();
					break;
				case R.id.btn_result:
				{
//					mbPrint =true;
					resultNumber();
					break;
				}
			}
		}
	}
	
	public static class Arith{
		 
	    //默認除法運算精度
	    private static final int DEF_DIV_SCALE = 10;
	 
	    //這個類不能實例化
	    private Arith(){
	    }
	 
	    /**
	     * 提供精確的加法運算。
	     * @param v1 被加數
	     * @param v2 加數
	     * @return 兩個參數的和
	     */
	    public static double add(double v1,double v2){
	        BigDecimal b1 = new BigDecimal(Double.toString(v1));
	        BigDecimal b2 = new BigDecimal(Double.toString(v2));
	        return b1.add(b2).doubleValue();
	    }
	 
	    /**
	     * 提供精確的減法運算。
	     * @param v1 被減數
	     * @param v2 減數
	     * @return 兩個參數的差
	     */
	    public static double sub(double v1,double v2){
	        BigDecimal b1 = new BigDecimal(Double.toString(v1));
	        BigDecimal b2 = new BigDecimal(Double.toString(v2));
	        return b1.subtract(b2).doubleValue();
	    }
	 
	    /**
	     * 提供精確的乘法運算。
	     * @param v1 被乘數
	     * @param v2 乘數
	     * @return 兩個參數的積
	     */
	    public static double mul(double v1,double v2){
	        BigDecimal b1 = new BigDecimal(Double.toString(v1));
	        BigDecimal b2 = new BigDecimal(Double.toString(v2));
	        return b1.multiply(b2).doubleValue();
	    }
	 
	    /**
	     * 提供（相對）精確的除法運算，當發生除不盡的情況時，精確到
	     * 小數點以後10位元，以後的數字四捨五入。
	     * @param v1 被除數
	     * @param v2 除數
	     * @return 兩個參數的商
	     */
	    public static double div(double v1,double v2){
	        return div(v1,v2,DEF_DIV_SCALE);
	    }
	 
	    /**
	     * 提供（相對）精確的除法運算。當發生除不盡的情況時，由scale參數指
	     * 定精度，以後的數字四捨五入。
	     * @param v1 被除數
	     * @param v2 除數
	     * @param scale 表示表示需要精確到小數點以後幾位。
	     * @return 兩個參數的商
	     */
	    public static double div(double v1,double v2,int scale){
	        if(scale<0){
	            throw new IllegalArgumentException(
	                "The scale must be a positive integer or zero");
	        }
	        BigDecimal b1 = new BigDecimal(Double.toString(v1));
	        BigDecimal b2 = new BigDecimal(Double.toString(v2));
	        return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
	    }
	 
	    /**
	     * 提供精確的小數位四捨五入處理。
	     * @param v 需要四捨五入的數位
	     * @param scale 小數點後保留幾位
	     * @return 四捨五入後的結果
	     */
	    public static double round(double v,int scale){
	        if(scale<0){
	            throw new IllegalArgumentException(
	                "The scale must be a positive integer or zero");
	        }
	        BigDecimal b = new BigDecimal(Double.toString(v));
	        BigDecimal one = new BigDecimal("1");
	        return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
	    }
	}
}
