package fanch.multijeu.numbers.widget;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;

import fanch.multijeu.numbers.data.Expression;
import fanch.multijeu.numbers.data.ExpressionParser;
import fanch.multijeu.numbers.data.NumberExpr;
import fanch.multijeu.numbers.data.OperationExpr;
import fanch.multijeu.numbers.data.ParentheseExpr;

public class CalcButton extends android.support.v7.widget.AppCompatButton {

    protected static final int COLOR_VALID=0xff00ff00;
    protected static final int COLOR_UNDO=0xffaf0000;
    protected static final int COLOR_CLEAR=0xffff0000;
    protected static final int COLOR_NUMBER=0xff00afaf;
    protected static final int COLOR_RESULT=0xff00af55;
    protected static final int COLOR_OPERATION=0xffffffff;

    public static enum Type {
        CLEAR,
        OPERATION,
        OTHER,
        RESULT,
        VALID,
        UNDO,
        NUMBER
    }

    public static class CalcButtonContent {
        public Type type;
        public Expression value;
    }

    public static class CalcButtonState {
        CalcButtonContent exp=new CalcButtonContent();
        String text;
        boolean isDisabled;

    }

    protected CalcButtonContent mContent;
    protected boolean           mIsMarkedDisabled=false;

    public CalcButton(Context context) {
        super(context);
        setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            setTextAlignment(TEXT_ALIGNMENT_GRAVITY);
        }
        setPadding(0,0,0,0);
    }

    public CalcButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        setGravity(Gravity.LEFT|Gravity.CENTER_VERTICAL);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            setTextAlignment(TEXT_ALIGNMENT_GRAVITY);
        }
        setPadding(0,0,0,0);

    }

    public CalcButtonContent getContent() {
        return mContent;
    }

    protected void setText(String c)
    {
        super.setText(c);
    }

    public void setContent(Expression x)
    {
        mContent = new CalcButtonContent();
        if(x instanceof NumberExpr)
        {
            mContent.type=Type.NUMBER;
            mContent.value=x;
        }else if(x instanceof OperationExpr){
            if( ((OperationExpr)x).isEmpty() )
                mContent.type=Type.OPERATION;
            else
                mContent.type=Type.RESULT;
            mContent.value=x;
        }else if(x instanceof ParentheseExpr){
            mContent.type=Type.OTHER;
            mContent.value=x;
        }
        setColor();
    }

    public void setContent(OperationExpr.Operation op)
    {
        mContent = new CalcButtonContent();
        mContent.type=Type.OPERATION;
        mContent.value=new OperationExpr(op);
        setColor();
    }

    public void setParenthese(boolean open)
    {
        mContent = new CalcButtonContent();
        mContent.type=Type.OTHER;
        mContent.value=(open)? ParentheseExpr.open():ParentheseExpr.close();
        setColor();
    }

    public void setContent(Type t)
    {
        mContent = new CalcButtonContent();
        mContent.type=t;
        setColor();
    }

    protected void setColor()
    {
        switch(mContent.type)
        {
            case UNDO: setBackgroundColor(COLOR_UNDO); break;
            case VALID: setBackgroundColor(COLOR_VALID); break;
            case CLEAR: setBackgroundColor(COLOR_CLEAR); break;
            case OTHER:
            case OPERATION: setBackgroundColor(COLOR_OPERATION); break;
            case NUMBER:setBackgroundColor(COLOR_NUMBER); break;
            case RESULT:
            default:
                setBackgroundColor(COLOR_RESULT); break;
        }
    }

    public void setAdd()
    {
        setContent(OperationExpr.Operation.ADD);
        setText("+");
    }
    public void setMult()
    {
        setContent(OperationExpr.Operation.MULT);
        setText("*");
    }
    public void setDiv() {
        setContent(OperationExpr.Operation.DIV);
        setText("/");
    }
    public void setSub() {
        setContent(OperationExpr.Operation.SUB);
        setText("-");
    }
    public void setClear()
    {
        setContent(Type.CLEAR);
        setText("C");
    }

    public void setOpen()
    {
        setParenthese(true);
        setText("(");
    }
    public void setClose()
    {
        setParenthese(false);
        setText(")");
    }

    public void setUndo()
    {
        setContent(Type.UNDO);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            setBackground(getResources().getDrawable(android.R.drawable.ic_menu_revert));
        }else{
            setBackgroundDrawable(getResources().getDrawable(android.R.drawable.ic_menu_revert));
        }
    }
    public void setValid()
    {
        setContent(Type.VALID);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            setBackground(getResources().getDrawable(android.R.drawable.ic_menu_send));
        }else{
            setBackgroundDrawable(getResources().getDrawable(android.R.drawable.ic_menu_send));
        }
    }

    public void setNumber(Expression ex)
    {
        setContent(ex);
        setText(ex.compute()+"");
    }

    public boolean isOperation() { return mContent.type==Type.OPERATION; }
    public boolean isNumber() { return mContent.type==Type.NUMBER; }
    public boolean isControl() { return mContent.type==Type.CLEAR
                                        || mContent.type==Type.UNDO
                                        || mContent.type==Type.VALID; }


    public void setEnableIf(Type t[])
    {
        boolean show = false;
        for(int i=0; i<t.length; i++)
            if(t[i]==mContent.type) {
                show=true;
                break;
            }
        if(mIsMarkedDisabled) show=false;
        setEnabled(show);
        if(show)
        {
            setAnimAlpha(1);
        }
        else
        {
            setAnimAlpha((float) 0.3);
        }
    }

    public void setEnable(boolean show)
    {
        super.setEnabled(show);
        markDisabled(!show);
        if(show)
        {
            setAnimAlpha(1);
        }
        else
        {
            setAnimAlpha((float) 0.3);
        }
    }

    public Expression getExpression()
    {
        switch (mContent.type)
        {
            case OTHER:
            case RESULT:
            case OPERATION:
            case NUMBER:
                return mContent.value.clone();
            default:
                return null;
        }
    }

    public void markDisabled(boolean dis)
    {
        mIsMarkedDisabled=dis;
    }

    public CalcButtonState getState()
    {
        CalcButtonState state = new CalcButtonState();
        state.exp.type=mContent.type;
        state.exp.value=mContent.value.clone();
        state.text= (String) getText();
        state.isDisabled=mIsMarkedDisabled;
        return state;
    }

    public void setState(CalcButtonState cb)
    {
        mContent=new CalcButtonContent();
        setContent(cb.exp.value.clone());
        setText(cb.text);
        mIsMarkedDisabled=cb.isDisabled;
    }

    public void setAnimAlpha(float f)
    {
        ObjectAnimator animation = ObjectAnimator.ofFloat(this, "alpha", f);
        animation.setDuration(500);
        animation.start();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

        final int W = right-left;
        final int H =bottom-top;



        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        final int x = text.length();
        final int t = TypedValue.COMPLEX_UNIT_SP;
        if(x==1) setTextSize(t, 26);
        else if(x==2) setTextSize(t,26);
        else if(x==3) setTextSize(t, 24);
        else setTextSize(t,22);
        setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);

        super.setText(text, type);
    }

    public void show()
    {
        setVisibility(VISIBLE);
        PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", getAlpha(),  0);
    }

    public void hide()
    {
        setVisibility(GONE);
    }
}
