package fanch.multijeu.numbers.widget;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.ArrayList;

import fanch.multijeu.common.exceptions.BadChildClass;
import fanch.multijeu.numbers.data.Expression;
import fanch.multijeu.numbers.data.ExpressionSet;
import fanch.multijeu.numbers.data.OperationExpr;

public class AssistedCalcWidget extends CalcWidget {

    protected ArrayList<CalcButton> mExpression = new ArrayList<CalcButton>();
    protected ArrayList<State> mHistory = new ArrayList<>();


    protected static final CalcButton.Type SHOW_IDLE[] = {
            CalcButton.Type.CLEAR, CalcButton.Type.NUMBER, CalcButton.Type.UNDO,
            CalcButton.Type.RESULT, CalcButton.Type.VALID
    };

    protected static final CalcButton.Type SHOW_ON_NUMBER[] = {
            CalcButton.Type.OPERATION, CalcButton.Type.CLEAR,  CalcButton.Type.VALID, CalcButton.Type.UNDO
    };

    protected static final CalcButton.Type SHOW_ON_OPERATION[] = {
            CalcButton.Type.CLEAR, CalcButton.Type.NUMBER, CalcButton.Type.VALID,
            CalcButton.Type.UNDO, CalcButton.Type.RESULT
    };

    protected static final CalcButton.Type SHOW_RESULT[] = {
            CalcButton.Type.CLEAR, CalcButton.Type.NUMBER, CalcButton.Type.UNDO,
            CalcButton.Type.RESULT, CalcButton.Type.VALID, CalcButton.Type.OPERATION
    };


    public AssistedCalcWidget(Context context) {
        super(context);
        initControlButton();
    }

    public AssistedCalcWidget(Context context, AttributeSet attrs) {
        super(context, attrs);
        initControlButton();
    }



    private void pushHistory()
    {
        State s = new State();
        s.expression= (ArrayList<CalcButton>) mExpression.clone();
        s.state=mState;
        s.states=new ArrayList<CalcButton.CalcButtonState>();
        for(int i=0; i<mNumbers.size(); i++)
        {
            s.states.add(mNumbers.get(i).getState());
        }
        mHistory.add(s);
    }

    private void restoreState(State s)
    {
        mExpression= (ArrayList<CalcButton>) s.expression.clone();
        mState=s.state;
        for(int i=0; i<mNumbers.size(); i++) {
            mNumbers.get(i).setState(s.states.get(i));
        }
    }

    private void pushExpression(CalcButton c)
    {
        mExpression.add(c);
    }

    protected void clearExpression()
    {
        mExpression.clear();
        mState=TypeState.IDLE;

        mScreen.setText("");

        if(mListener!=null)
            mListener.onClear();
    }

    protected void updateShow()
    {
        CalcButton.Type[] btns = null;
        switch (mState)
        {
            case IDLE:
                btns= SHOW_IDLE;
                /*for(int i=0; i<mNumbers.size(); i++)
                    mNumbers.get(i).markDisabled(false);*/
                break;
            case ON_NUMBER:
                btns=SHOW_ON_NUMBER; break;
            case ON_OP:
                btns=SHOW_ON_OPERATION; break;
            case RESULT:
                btns=SHOW_RESULT; break;
        }
        final int count = getChildCount(); //-1 for mScreen
        for(int i=0; i<count; i++)
        {
            final View c = getChildAt(i);
            if( (c instanceof CalcButton) ){
                CalcButton btn  = (CalcButton)c;
                btn.setEnableIf(btns);
            }

        }
    }

    @Override
    public Expression getResult() {
        return null;
    }

    public void undo()
    {
        if(mHistory.size()>1) {
            clearExpression();
            restoreState(mHistory.get(mHistory.size() - 2));
            if (mHistory.size() > 1) mHistory.remove(mHistory.size() - 1);
            updateShow();
            requestLayout();

            if (mListener == null)
                mListener.onUndo();
        }

    }

    public void clear()
    {
        if(mHistory.size()<=0) return;
        clearExpression();
        restoreState(mHistory.get(0));
        mHistory.clear();
        pushHistory();

        updateShow();
        if(mListener==null)
            mListener.onClear();
    }

    public void valid()
    {
        if(mExpression.size()==0) {
            mState = TypeState.IDLE;
            clearExpression();
            updateShow();
        }
        if(mListener!=null)
            mListener.onValid();
    }

    public void replace(CalcButton old, Expression newExpr)
    {
        CalcButton.CalcButtonState ca = old.getState();
        ca.isDisabled=false;
        ca.text=newExpr.compute()+"";
        ca.exp.value=newExpr;
        ca.exp.type=CalcButton.Type.RESULT;
        old.setState(ca);
        updateShow();
    }

    private void removeNumber(CalcButton cb)
    {
        mNumbers.remove(cb);
        removeView(cb);
    }

    public void setNumbers(int x[])
    {
        clearExpression();
        clearNumbers();
        mState=TypeState.IDLE;
        mHistory.clear();
        super.setNumbers(x);
        pushHistory();
        updateShow();
        showNumber(0);
    }

    public void setNumbers(Expression x[])
    {
        clearExpression();
        clearNumbers();
        mState=TypeState.IDLE;
        mHistory.clear();
        super.setNumbers(x);
        pushHistory();
        mScreen.setText("");
        updateShow();
        showNumber(0);

    }

    public void setNumbers(ExpressionSet x)
    {
        setNumbers(x.allowedNumber);
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        final CalcButton.CalcButtonContent cb = ((CalcButton)v).getContent();
        switch(cb.type)
        {
            case UNDO:
                onUndo();
                break;
            case RESULT:
                onNumber(((CalcButton)v));
                break;
        }
    }


    protected void onUndo() {
        undo();
    }

    public void setExpression(Expression expr) {
        if(expr!=null)
        {
            int res = expr.compute();
            String x = expr+"";

            if( expr instanceof OperationExpr)
                x+=" = "+res;

            mScreen.setText(x);
        }
        else mScreen.setText("");
    }


    protected void number(CalcButton v) {
        if(mState==TypeState.RESULT){
            clearExpression();
        }

        if(mState==TypeState.ON_OP)
        {
            mState=TypeState.RESULT;
            if(mExpression.size()!=2)
                throw new IllegalStateException("Ne devrait pas etre possible");
            pushExpression(v);
            OperationExpr op = (OperationExpr) mExpression.get(1).getExpression().clone();
            op.setFirst(mExpression.get(0).getExpression().clone());
            op.setSecond(v.getExpression().clone());
            onOperationDone(op);
            setExpression(op);
            if(mListener!=null) {
                mListener.onExpressionDone(op);
            }
            updateShow();
        }else
        {
            mState=TypeState.ON_NUMBER;
            v.markDisabled(true);
            pushExpression(v);
            updateShow();
            setExpression(v.getExpression());

        }
    }

    private void onOperationDone(OperationExpr op) {
        mExpression.get(2).markDisabled(true);
        replace(mExpression.get(0), op);
        mExpression.get(0).markDisabled(false);
        mExpression.remove(2);
        mExpression.remove(1);
        pushHistory();
        requestLayout();
    }

    protected void operation(CalcButton v) {
        mState=TypeState.ON_OP;
        pushExpression(v);
        updateShow();


        OperationExpr e = (OperationExpr) mExpression.get(1).getExpression().clone();
        e.setFirst(mExpression.get(0).getExpression().clone());
        setExpression(e);
    }


    protected void initControlButton()
    {
        mMinGridHeight=3;

        super.initControlButton();
        mOperandes = new CalcButton[]{mAdd, mSub, mMult/*, mDiv*/};

        updateShow();
    }
}
