import objectdraw.*;

/**
 * Abstract base class for representations for a binary operation regarded 
 * as an arithmetic expression
 * 
 * @author Russell C. Bjork 
 * @version March 20, 2008
 */
public abstract class BinaryOperation extends Node implements Expression
{
    protected Expression left;    // The first subexpression
    private char operator;        // The operator
    protected Expression right;   // The second subexpression
    
    /** Constructor
     * 
     *  @param left the first subexpression
     *  @param operator the operator
     *  @param right the second subexpression
     */
    public BinaryOperation(Expression left, char operator, Expression right) {
        this.left = left;
        this.operator = operator;
        this.right = right;
    }
    
    // Methods required by the Expression interface
    
    public String toString() {
        return "(" + left.toString() + operator + right.toString() + ")";
    }
    
    // evaluate() is implemented by concrete subclasses
    
    // derivative() is implemented by concrete subclasses\
    
    public Expression simplify() {
        Expression simplifiedLeft = left.simplify();
        Expression simplifiedRight = right.simplify();
        if (simplifiedLeft instanceof Constant &&
                simplifiedRight instanceof Constant)
            return new Constant(evaluate(0));
        else
            return simplify(simplifiedLeft, simplifiedRight);
    }
    
    /** Simplify a binary operation after simplifying the subexpressions.   This
     *  abstract method is implemented by each concrete subclass
     * 
     *  @param simplifiedLeft the simplified form of the left subexpression
     *  @param simplifiedRight the simplified form of the right subexpression
     *  @return the simplified overall expression
     */
    protected abstract Expression simplify(Expression simplifiedLeft,
                                           Expression simplifiedRight);
    
    public void draw(double x, double y, double width, DrawingCanvas canvas) {
        
        // Calculate positions for root and subtrees
        
        double centerX = x + width / 2;
        double centerY = y + TREE_NODE_DIAMETER / 2;
        double subtreeWidth = width / 2;
        double centerXLeft = x + subtreeWidth / 2;
        double centerXRight = subtreeWidth + centerXLeft;
        double subtreeY = y + 2 * TREE_NODE_DIAMETER;
        double centerYSubtrees = subtreeY + TREE_NODE_DIAMETER / 2;
        
        // Draw the lines connecting the root to subtrees
        
        new Line(centerX, centerY, centerXLeft, centerYSubtrees, canvas);
        new Line(centerX, centerY, centerXRight, centerYSubtrees, canvas);
        
        // Draw a node representing the operator at the root - must be done
        // after drawing the line to cover part of it
        
        drawNode("" + operator, x, y, width, canvas);
       
        // Draw the subtrees
        
        left.draw(x, subtreeY, subtreeWidth, canvas);
        right.draw(x + subtreeWidth, subtreeY, subtreeWidth, canvas);
    }
}
