package com.redspr.redquerybuilder.core.client.expression;

import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.redspr.redquerybuilder.core.BaseSqlWidget;
import com.redspr.redquerybuilder.core.client.engine.DirtyEvent;
import com.redspr.redquerybuilder.core.client.engine.Session;
import com.redspr.redquerybuilder.core.client.table.TableFilter;
import com.redspr.redquerybuilder.core.client.util.ListBox2;
import com.redspr.redquerybuilder.core.client.util.XWidget;
import com.redspr.redquerybuilder.core.shared.meta.Cardinality;
import com.redspr.redquerybuilder.core.shared.meta.Column;
import com.redspr.redquerybuilder.core.shared.meta.Operator;
import com.redspr.redquerybuilder.core.shared.meta.Type;

/**
 * Example comparison expressions are ID=1, NAME=NAME, NAME IS NULL.
 */
public class Comparison extends Condition {

    private String compareType;
    private final XWidget<Expression> xleft = new XWidget<Expression>();
    private final XWidget<Expression> xright = new XWidget<Expression>();

    private final ListBox2<Operator> op = new ListBox2<Operator>();

    private final Button remove = new Button("-");

    public Comparison(Session session2) {
        super(session2);

        // XXX why do this defaulting here? Not just do it in ExpressionColumn?
        TableFilter tf = getSession().getFilters().get(0);
        Column col = null;
        for (Column col2 : tf.getTable().getColumns()) {
            if (!col2.isHidden()) {
                col = col2;
                break;
            }
        }
        if (col == null) {
            throw new RuntimeException("No visible column");
        }

        setLeft(new ExpressionColumn(getSession(), null, tf.getAlias(),
                col.getName()));
        setRight(new Parameter(getSession()));
        compareType = col.getType().getOperators()[0].getName();
        init();
    }

    public Comparison(Session session2, String compareType2,
            final Expression left2, final Expression right2) {
        super(session2);
        setLeft(left2);
        setRight(right2);
        compareType = compareType2;
        init();
    }

    private void init() {
        HorizontalPanel v = new HorizontalPanel();
        v.addStyleName("rqbComparison");
        v.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);

        v.add(xleft);

        v.add(op);
        op.addValueChangeHandler(new ValueChangeHandler<Operator>() {
            @Override
            public void onValueChange(ValueChangeEvent<Operator> event) {
                setOperator(op.getValue());
                getSession().getMsgBus().fireEvent(new DirtyEvent());
            }
        });

        v.add(xright);

        v.add(remove);
        remove.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                remove();
                getSession().getMsgBus().fireEvent(new DirtyEvent());
            }
        });

        Button add = new Button("+");

        v.add(add);
        add.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                add();
                getSession().getMsgBus().fireEvent(new DirtyEvent());
            }
        });

        initWidget(v);
    }

    public void setOperator(Operator p) {
        this.compareType = p.getName();

        Cardinality c = p.getCardinality();
        if (c == Cardinality.ZERO) {
            if (getRight() != null) {
                setRight(null);
            }
        } else {
            if (getRight() == null) {
                setRight(new Parameter(getSession()));
            }
        }
    }

    public String getOperatorName() {
        return compareType;
    }

    public Operator getOperator() {
        ExpressionColumn leftec = ((ExpressionColumn) getLeft());
        Column lc = leftec.getColumn();
        if (lc == null) {
            leftec.getColumn();
        }
        Type lt = lc.getType();
        Operator o = lt.getOperatorByName(compareType);
        if (o == null) {
            o = lt.getOperators()[0];
        }
        return o;
    }

    @Override
    public void onDirty(DirtyEvent e) {
        Column col = ((ExpressionColumn) getLeft()).getColumn();

        Operator ope = col.getType().getOperatorByName(compareType);
        if (ope == null) {
            ope = col.getType().getOperators()[0];
        }

        op.setValue(getOperator());
        op.setAcceptableValues(col.getType().getOperators());
    }

    @Override
    public String getSQL(List args) {
        Operator op = getOperator();
        switch (op.getCardinality()) {
        case ZERO:
            return "(" + getLeft().getSQL(args) + " " + op.getName() + ")";
        case ONE:
        case MULTI:
            return "(" + getLeft().getSQL(args) + " " + getOperatorName() + " "
                    + getRight().getSQL(args) + ")";
        default:
            throw new RuntimeException("Unknown cardinality "
                    + op.getCardinality());
        }
    }

    public Expression getLeft() {
        return xleft.getValue();
    }

    public void setLeft(Expression left) {
        xleft.setValue(left);
    }

    public Expression getRight() {
        return xright.getValue();
    }

    public void setRight(Expression right) {
        xright.setValue(right);
    }

    // XXX one side ask about the other...
    // XXX expression have getTypeInfo?
    public Expression getOther(Expression me) {
        if (getLeft() == me) {
            return getRight();
        } else if (getRight() == me) {
            return getLeft();
        } else {
            throw new RuntimeException("Unable to find other side");
        }
    }

    public BaseSqlWidget remove() {
        return getParentExpression().remove(this);
    }

    public void add() {
        ConditionAndOr andOr = new ConditionAndOr(getSession(), 0, new Nop(),
                new Nop());
        getParentExpression().replace(this, andOr);
        andOr.setLeft(this);

        andOr.setRight(new Comparison(getSession()));
    }

    @Override
    public void traverse(Callback callback) {
        super.traverse(callback);
        if (xleft.getValue() != null) {
            xleft.getValue().traverse(callback);
        }
        if (xright.getValue() != null) {
            xright.getValue().traverse(callback);
        }
    }
}


@@ -4472,32 +4472,71 @@
 Operators()%5B0%5D;%0A
+            compareType = o.getName();%0A
         %7D%0A      
@@ -4521,32 +4521,32 @@
 me();%0A        %7D%0A
-
         return o
@@ -4604,24 +4604,24 @@
 yEvent e) %7B%0A
+
         Colu
@@ -4678,166 +4678,8 @@
 );%0A%0A
-        Operator ope = col.getType().getOperatorByName(compareType);%0A        if (ope == null) %7B%0A            ope = col.getType().getOperators()%5B0%5D;%0A        %7D%0A%0A
     

Fix compare type not updating after column change.