public class EmptyChildException extends MathException
{
    private static final long serialVersionUID = 5101446079156444420L;

    /** Default constructor, constructs a default message */
    public EmptyChildException()
    { super("An empty child was found in a class where no empty child is allowed."); }

    /** Constructor, constructs a default message
     * @param index The index of the child that is empty */
    public EmptyChildException(int index)
    { super("An empty child was found in a class at index " + index + ", no empty child is allowed there."); }

    /** Constructor, constructs an exception with the given message
     * @param msg The message that the exception should be constructed with */
    public EmptyChildException(String msg)
    { super(msg); }
} public class MathException extends Exception
{
	private static final long serialVersionUID = 3030104203573345473L;

	// note: javadoc copy-pasted from exception, because {@inheritDoc} doesn't
	// work for some reason
	/**
	 * Constructs a new mathematical exception with <code>null</code> as its
	 * detail message. The cause is not initialized, and may subsequently be
	 * initialized by a call to {@link #initCause}.
	 */
	public MathException()
	{
	}

	/**
	 * Constructs a new mathematical exception with the specified detail
	 * message. The cause is not initialized, and may subsequently be
	 * initialized by a call to {@link #initCause}.
	 * 
	 * @param message
	 *            the detail message. The detail message is saved for later
	 *            retrieval by the {@link #getMessage()} method.
	 */
	public MathException(String message)
	{
		super(message);
	}

	/**
	 * Constructs a new mathematical exception with the specified cause and a
	 * detail message of <tt>(cause==null ? null : cause.toString())</tt> (which
	 * typically contains the class and detail message of <tt>cause</tt>). This
	 * constructor is useful for exceptions that are little more than wrappers
	 * for other throwables (for example,
	 * {@link java.security.PrivilegedActionException}).
	 * 
	 * @param cause
	 *            the cause (which is saved for later retrieval by the
	 *            {@link #getCause()} method). (A <tt>null</tt> value is
	 *            permitted, and indicates that the cause is nonexistent or
	 *            unknown.)
	 * @since 1.4
	 */
	public MathException(Throwable cause)
	{
		super(cause);
	}

	/**
	 * Construct a new mathematical exception with the specified cause and a
	 * detail message that describes the error.
	 * 
	 * @param message
	 *            The detailed human-readable message.
	 * @param cause
	 *            Some evil demon that wants to crash our program.
	 */
	public MathException(String message, Throwable cause)
	{
		super(message, cause);
	}
} public class ParseException extends MathException
{
    private static final long serialVersionUID = -5061683875213406313L;

    // note: javadoc copy-pasted from exception, because {@inheritDoc} doesn't
    // work for some reason
    /**
     * Constructs a new parse exception with <code>null</code> as its detail
     * message. The cause is not initialized, and may subsequently be
     * initialized by a call to {@link #initCause}.
     */
    public ParseException()
    {}

    /**
     * Constructs a new parse exception with the specified detail message. The
     * cause is not initialized, and may subsequently be initialized by a call
     * to {@link #initCause}.
     * 
     * @param message
     *        the detail message. The detail message is saved for later
     *        retrieval by the {@link #getMessage()} method.
     */
    public ParseException(String message)
    {
        super(message);
    }

    /**
     * Constructs a new parse exception with the specified cause and a detail
     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
     * typically contains the class and detail message of <tt>cause</tt>). This
     * constructor is useful for exceptions that are little more than wrappers
     * for other throwables (for example,
     * {@link java.security.PrivilegedActionException}).
     * 
     * @param cause
     *        the cause (which is saved for later retrieval by the
     *        {@link #getCause()} method). (A <tt>null</tt> value is permitted,
     *        and indicates that the cause is nonexistent or unknown.)
     * @since 1.4
     */
    public ParseException(Throwable cause)
    {
        super(cause);
    }

    /**
     * Construct a new parse exception with the specified cause and a detail
     * message that describes the error.
     * 
     * @param message
     *        The detailed human-readable message.
     * @param cause
     *        Some evil demon that wants to crash our program.
     */
    public ParseException(String message, Throwable cause)
    {
        super(message, cause);
    }

    /**
     * Construct a new parse exception with the specified abstract syntax tree
     * that caused this exception to be thrown.
     * 
     * @param ast
     *        The abstract syntax tree from Symja.
     */
    public ParseException(AST ast)
    {
        super(ast.toString() + ": invalid operation");
    }

    /**
     * Construct a new parse exception with the specified mathematical
     * expression that caused this exception to be thrown.
     * 
     * @param expr
     *        The mathematical expression from Symja.
     */
    public ParseException(IExpr expr)
    {
        super(expr.toString() + ": invalid operation");
    }
} public class Empty extends Expression
{
    public static final String NAME = "empty";
    
    /** The ratio (width : height) of the empty child box (i.e. the golden ratio) */
    public final static float RATIO = 1 / 1.61803398874989f;
    
    /** The paint that's used to draw the child */
    private Paint paint = new Paint();
    
    /** Constructor */
    public Empty()
    {
        // Initialise the paint
        paint.setColor(Color.rgb(0x88, 0x88, 0x88));
        paint.setStyle(Paint.Style.STROKE);
        paint.setPathEffect(new DashPathEffect(new float[] {16.0f, 16.0f}, 0));
    }
    
    @Override
    public String toString()
    { return " "; }
    
    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException
    {
        // Will always throw an error since empty boxes do not have children
        checkChildIndex(index);
        return null;
    }

    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the bounding box
        Rect rect = this.getOperatorBoundingBoxes()[0];
        
        // Set the right color of the paint
        paint.setColor(getColor());
        
        // Draw the dashed rectangle
        paint.setStrokeWidth(lineWidth);
        rect.inset((int) Math.ceil(paint.getStrokeWidth() / 2), (int) Math.ceil(paint.getStrokeWidth() / 2));
        canvas.drawRect(rect, paint);
        
        //If you're trying to drag the item, make an aiming cross
        if(this.state == HoverState.DRAG)
        {
            paint.setStyle(Paint.Style.FILL);
            canvas.drawCircle(rect.left + rect.width() / 2, rect.top + rect.height() / 2, Math.min(rect.height(), rect.width()) / 10, paint);
            paint.setStyle(Paint.Style.STROKE);
        }
    }
    
    @Override
    public Rect calculateBoundingBox()
    {    	
    	int width = (int) (defaultHeight * RATIO);
    	int height = defaultHeight;
    	
    	for(int t = 0; t < this.level && t < MAX_LEVEL; t++)
        {
            width = 2*width/3;
            height = 2*height/3;
        }
        
        return new Rect(0, 0, width, height);
    }
    
    @Override
    public Rect[] calculateOperatorBoundingBoxes()
    {
        //emptyObjects don't have an operator, but they do need one for the drag and drop
        return new Rect[] { this.getBoundingBox()};
    }

    @Override
    public void writeToXML(Document doc, Element el)
    {
        el.appendChild(doc.createElement(NAME));
    }

    @Override
    public boolean isCompleted()
    { return false; }
} public abstract class Expression
{
    /** The line width that is to be used to draw operators */
    public static float lineWidth = 2.0f;
    
    /** The children of this {@link Expression} */
    protected ArrayList<Expression> children = new ArrayList<Expression>();

    /** The center of this object */
    protected Point center;
    
    /** The bounding boxes of this object */
    protected ArrayList<Rect> childrenBoundingBoxes = new ArrayList<Rect>();
    protected ArrayList<Rect> operatorBoundingBoxes = new ArrayList<Rect>();
    protected Rect totalBoundingBox = null;
    
    /** The boolean to keep track if the bounding boxes are still valid */
    protected boolean operatorBoundingBoxValid = false;
    /** The boolean to keep track if the child bounding boxes are still valid */
    protected boolean childrenBoundingBoxValid = false;
    /** The boolean to keep track if the total bounding box is still valid */
    protected boolean totalBoundingBoxValid = false;
    /** The boolean to keep track if the center is still valid */
    protected boolean centerValid = false;
    
    /** The default height of an object */
    protected int defaultHeight = 100;
    
    /** The maximum level depth */
    public final static int MAX_LEVEL = 4;

    /** The current hover state */
    protected HoverState state = HoverState.NONE;
    
    /** The current 'level' of the object*/
    protected int level = 0;
    
    /** Returns the precedence of this operation.
     * The highest precedence is 0, greater values are lower precedences.
     * @return The precedence
     */
    public int getPrecedence()
    { return Precedence.HIGHEST; }

    /**
     * Returns the number of children this {@link Expression} has
     * 
     * @return The number of children this {@link Expression} has
     */
    public int getChildCount()
    { return children.size(); }

    /**
     * Returns the child at the given index
     * 
     * @param index
     *        The index of the child to return
     * @return The requested child
     * @throws IndexOutOfBoundsException
     *         thrown when the index number is invalid (i.e. out of range).
     */
    public Expression getChild(int index) throws IndexOutOfBoundsException
    { return children.get(index); }

    /**
     * Sets the child at the given index
     * 
     * @param index
     *        The index of the child that is to be changed
     * @param child
     *        The {@link Expression} that should become the child at the given index
     * @throws IndexOutOfBoundsException
     *         thrown when the index number is invalid (i.e. out of range).
     */
    public void setChild(int index, Expression child) throws IndexOutOfBoundsException
    {
        // Check the child index
        checkChildIndex(index);
        
        // Create an MathObjectEmpty if null is given
        if(child == null)
            child = new Empty();
        
        // Set the child
        children.set(index, child);

        // Refresh all levels and default heights
        // Also reset the bounding box cache
        setAll(level, defaultHeight, false);
    }

    /** Sets the child at the given index without refreshing the level, default height or bounding box cache.
     * You'll have to do this yourself.
     * 
     * @param index
     *        The index of the child that is to be changed
     * @param child
     *        The {@link Expression} that should become the child at the given index
     * @throws IndexOutOfBoundsException
     *         thrown when the index number is invalid (i.e. out of range).
     */
    public void setChildWithoutRefresh(int index, Expression child) throws IndexOutOfBoundsException
    {
        // Check the child index
        checkChildIndex(index);
        
        // Create an MathObjectEmpty if null is given
        if(child == null)
            child = new Empty();
        
        // Set the child
        children.set(index, child);
    }
    
    /** Returns the default height for this {@link Expression}
     * @return The default height for this {@link Expression} */
    public int getDefaultHeight()
    { return defaultHeight; }
    
    /** Sets the default height for this {@link Expression} and all of its children
     * @param height The default height */
    public void setDefaultHeight(int height)
    {
        // Invalidate the cache (if necessary)
        if(height != defaultHeight)
            invalidateBoundingBoxCacheForSelf();
        
        // Set the default height
        defaultHeight = height;
        
        // Pass the new default height to all children
        for(Expression child : children)
            child.setDefaultHeight(defaultHeight);
    }
    
    /** Invalidate or validate all bounding boxes in the cache (for this expression and all of its children) */
    public void invalidateBoundingBoxCache()
    {
        // Invalidate the whole cache
        invalidateBoundingBoxCacheForSelf();
        
        // Invalidate the whole cache for every child as well
        for(Expression child : children)
            child.invalidateBoundingBoxCache();
    }

    /** Invalidate or validate all bounding boxes in the cache (only for this expression) */
    public void invalidateBoundingBoxCacheForSelf()
    {
        // Invalidate the whole cache
        operatorBoundingBoxValid = false;
        childrenBoundingBoxValid = false;
        totalBoundingBoxValid = false;
        centerValid = false;
    }
    
    /** Get the state of the bounding box cache */
    public boolean getOperatorBoundingBoxValid()
    { return operatorBoundingBoxValid; }
    
    /** Get the state of the children bounding box cache */
    public boolean getChildrenBoundingBoxValid()
    { return childrenBoundingBoxValid; }
    
    /** Get the state of the total bounding box cache */
    public boolean getTotalBoundingBoxValid()
    { return totalBoundingBoxValid; }
    
    
    /**
     * Returns the bounding boxes of the operator of this {@link Expression}.
     * The aspect ratio of the bounding boxes should always be the same.
     * 
     * @param maxWidth
     *        The maximum width the {@link Expression} can have (can be
     *        {@link Expression#NO_MAXIMUM})
     * @param maxHeight
     *        The maximum height the {@link Expression} can have (can be
     *        {@link Expression#NO_MAXIMUM})
     * @return An array containing the requested bounding boxes
     */
    public abstract Rect[] calculateOperatorBoundingBoxes();

    public Rect[] getOperatorBoundingBoxes()
    {    	
        // If the cache is invalid or there are no bounding boxes in the current cache, recalculate them
        if( !getOperatorBoundingBoxValid() || operatorBoundingBoxes.isEmpty())
        {
            // First clear the current list
            operatorBoundingBoxes.clear();
            
            // Recalculate the bounding boxes
            Rect[] operatorBB = calculateOperatorBoundingBoxes();
            
            for(int i = 0; i < operatorBB.length; i ++)
                operatorBoundingBoxes.add( operatorBB[i]);
            
            // Set the cache to valid
            operatorBoundingBoxValid = true;
        }
        
        // Create a new array and get a copy of all the bounding boxes
        Rect[] result = new Rect[ operatorBoundingBoxes.size()];
        
        for(int i = 0; i < result.length; i ++)
            result[i] = new Rect(operatorBoundingBoxes.get(i));
        
        // Return the array with the rectangles
        return result;
    }
    /**
     * Returns the bounding box of the child at the given index.
     * The aspect ratio of the box should always be the same.
     * 
     * @param index
     *        The index of the child whose bounding box is to be returned
     * @return An array containing the requested bounding boxes
     * @throws IndexOutOfBoundsException
     *         If an invalid child index is given
     */
    public abstract Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException;

    public Rect getChildBoundingBox(int index) throws IndexOutOfBoundsException
    {    	
        // If the cache is invalid or the amount of bounding boxes isn't the amount of children, recalculate them
        if( !getChildrenBoundingBoxValid() || (getChildCount() != childrenBoundingBoxes.size()))
        {
            childrenBoundingBoxes.clear();
            
            this.calculateAllChildBoundingBox();
             
            childrenBoundingBoxValid = true;
        }
        
        // Return a copy of the requested bounding box
        return new Rect(childrenBoundingBoxes.get(index));
    }
    
    /** Calculate all the children's bounding boxes and add them to the children arraylist */
    public void calculateAllChildBoundingBox()
    {
    	int size = getChildCount();
        
        for(int i = 0; i < size; i ++)
            childrenBoundingBoxes.add( calculateChildBoundingBox(i));
    }
    
    /**
     * Returns the bounding box for the entire {@link Expression}.
     * The aspect ratio of the box should always be the same.
     * 
     * @return The bounding box for the entire {@link Expression}
     */
    public Rect calculateBoundingBox()
    {    	
        // This will be our result
        Rect out = new Rect();

        // Add all operator bounding boxes
        Rect[] operatorBoundingBoxes = getOperatorBoundingBoxes();
        for(Rect tmp : operatorBoundingBoxes)
            out.union(tmp);

        // Add all child bounding boxes
        for(int i = 0; i < getChildCount(); ++i)
            out.union(getChildBoundingBox(i));
        int width = out.width();
        int height = out.height();

        // Return the result
        return new Rect(0,0,width, height);
    }
    
    public Rect getBoundingBox()
    {
        // If the cache is invalid or there is no bounding box in the cache, recalculate
        if( !getTotalBoundingBoxValid() || totalBoundingBox == null)
        {
            totalBoundingBox = calculateBoundingBox();
            totalBoundingBoxValid = true;
        }
        
        // Return a copy of the bounding box
        return new Rect(totalBoundingBox);
    }
    
    /**
     * Retrieve the current hover state.
     * @return {@link #state}
     */
    public final HoverState getState()
    { return state; }

    /**
     * Modifies current state and return the old state. Subclasses may override
     * this method in order to perform actions (e.g. fire a <q>
     * HoverStateChangedListener</q> or something like that).
     * 
     * @param state
     *        The new state
     * @return The old state.
     * @throws NullPointerException
     *         thrown if {@link #state}<tt> == null</tt>
     */
    public HoverState setState(HoverState state)
    {
        if(state == null)
            throw new NullPointerException("state");
        HoverState old = this.state;
        this.state = state;
        return old;
    }

    /**
     * Draws the {@link Expression}
     * 
     * @param canvas
     *        The canvas to draw the {@link Expression} on
     */
    public abstract void draw(Canvas canvas);
    
    /**
     * Draw the child with the given index child on <tt>canvas</tt> within the specified bounding box.
     * @param index The index of the child that is to be drawn
     * @param canvas The graphical instance to draw on
     * @param box The bounding box of the child
     */
    protected void drawChild(int index, Canvas canvas, final Rect box)
    {
        // Draw the child
        canvas.save();
        canvas.translate(box.left, box.top);
        getChild(index).draw(canvas);
        canvas.restore();
    }
    
    /** Draws all children
     * @param canvas The canvas that the children should be drawn on

     */
    protected void drawChildren(Canvas canvas)
    {
        // Loop through all children and draw them
        for(int i = 0; i < children.size(); ++i)
            drawChild(i, canvas, getChildBoundingBox(i));
    }

    /**
     * Checks if the given child index is valid, and throws an exception if it
     * isn't.
     * 
     * @param index
     *        The child index that is to be checked
     * @throws IndexOutOfBoundsException
     *         If the child index is invalid
     */
    protected final void checkChildIndex(int index) throws IndexOutOfBoundsException
    {
        final int childCount = getChildCount();

        if(childCount == 0)
            throw new IndexOutOfBoundsException(getClass().getCanonicalName()
                    + " doesn't have any children.");
        else if(childCount == 1 && index != 0)
            throw new IndexOutOfBoundsException("Invalid child index "
                    + Integer.toString(index) + ", "
                    + getClass().getCanonicalName() + " has only 1 child.");
        else if(index < 0 || index >= childCount)
            throw new IndexOutOfBoundsException("Invalid child index "
                    + Integer.toString(index) + ", "
                    + getClass().getCanonicalName() + " has only "
                    + Integer.toString(childCount) + " children.");
    }
    
    /** Returns the color for the current state
     * @return The color for the current state
     */
    protected int getColor()
    {
        if(this.state == HoverState.DRAG)
            return Color.rgb(0x88, 0x88, 0x88);
        if(this.state == HoverState.HOVER)
            return Color.rgb(0x44, 0x44, 0xff);
        return Color.BLACK;
    }
    
    /** Set the state of the center point*/
    public void validateCenter(boolean bool)
    {
    	centerValid = bool;
    	
    	if(!bool)
    		for(Expression child : children)
    			child.validateCenter(false);
    }
    
    /** Get the state of the center point */
    public boolean getCenterValid()
    { return centerValid; }
    
    /** Returns the centre of the {@link Expression}
     * @return The centre of the {@link Expression}
     */
    public Point getCenter()
    {
    	if(!getCenterValid() || center == null)
    	{
    		center = calculateCenter();
    		this.validateCenter(true);
    	}
    	
        return center;
    }
    
    /** Calculate the center point */
    public Point calculateCenter()
    {
    	Rect bounding = this.getBoundingBox();
		return new Point(bounding.centerX(), bounding.centerY());
    }
    
    /** The deltas that should be added to the level for each corresponding child */
    protected int[] levelDeltas = null;
    
    /** Sets the new level for this {@link Expression} and all of its children
     * @param l The new level */
    public void setLevel(int l)
    {
        // Invalidate the cache (if necessary)
        if(l != level)
            invalidateBoundingBoxCacheForSelf();
        
        // Set the level
        level = l;
        
        // Set the level every child
        for(int i = 0; i < getChildCount(); ++i)
        {
            if(levelDeltas != null && i < levelDeltas.length)
                getChild(i).setLevel(l + levelDeltas[i]);
            else
                getChild(i).setLevel(l);
        }
    }
    
    /** Sets the level, bounding boxes validation and default height for this expression and all of it's children at once
     * @param lvl The new level
     * @param defHeight The new default height
     * @param valid Whether or not the bounding boxes should be valid */
    public void setAll(int lvl, int defHeight, boolean valid)
    {
        // Set the values
        level = lvl;
        defaultHeight = defHeight;
        operatorBoundingBoxValid = valid;
        childrenBoundingBoxValid = valid;
        totalBoundingBoxValid = valid;
        centerValid = valid;
        
        // Set the values for all children
        for(int i = 0; i < getChildCount(); ++i)
        {
            if(levelDeltas != null && i < levelDeltas.length)
                getChild(i).setAll(lvl + levelDeltas[i], defHeight, valid);
            else
                getChild(i).setAll(lvl, defHeight, valid);
        }
    }
    
    /** Whether or not to draw the bounding boxes */
    private final static boolean DRAW_BOUNDING = false;
    
    /** Draws the bounding box and the bounding boxes of the children (for debug purposes).
     * The boxes will only be drawn if {@link Expression#DRAW_BOUNDING DRAW_BOUNDING} is set to true.
     * @param canvas The canvas to draw on
     */
    protected void drawBoundingBoxes(Canvas canvas)
    {
        // Check if we should draw the bounding boxes
        if(!DRAW_BOUNDING) return;

        // Draw the bounding boxes
        Paint paint = new Paint();
        paint.setColor(0x4400ff00);
        canvas.drawRect(getBoundingBox(), paint);
        paint.setColor(0x44ff0000);
        for(int i = 0; i < getChildCount(); ++i)
            canvas.drawRect(getChildBoundingBox(i), paint);
    }
    
    /** The name of the XML root element */
    public static final String XML_ROOT = "root";

    /** The current version of the XML structure */
    public static final int XML_VERSION = 1;
    
    /** Creates an empty XML document that can be used for the {@link Expression#writeToXML(Document, Element) writeToXML()} method
     * @return The created document 
     * @throws ParserConfigurationException If something goes wrong while creating the document */
    public static Document createXMLDocument() throws ParserConfigurationException
    {
        // Create an empty document
        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        Document doc = builder.newDocument();
        
        // Create a root element
        Element root = doc.createElement(XML_ROOT);
        root.setAttribute("version", Integer.toString(XML_VERSION));
        doc.appendChild(root);
        
        // Return the document
        return doc;
    }
    
    /** Serialize current instance in a XML document in a specified element. 
     * @param doc The XML document
     * @param parent The parent XML element
     */
    public void writeToXML(Document doc, Element parent)
    {
        Log.w("XML", "not a writable element yet");
        parent.appendChild(doc.createElement(Empty.NAME));
    }
    
    /**
     * Checks if all children have been fully filled in, and also their children and so on recursively down the tree.
     * @return returns true if all children of this MathObject have been filled in.
     */
    public boolean isCompleted()
    {
        for(Expression child : children)
        {
            if(!child.isCompleted())
                return false;
        }
        
        return true;
    }
} public class Function extends Expression
{
    /** An enumeration that describes the types of functions this function can be */
    public static enum FunctionType
    {
        SIN("sin"),
        COS("cos"),
        TAN("tan"),
        SINH("sinh"),
        COSH("cosh"),
        ARCSIN("sin\u207B\u00B9", "arcsin"),
        ARCCOS("cos\u207B\u00B9", "arccos"),
        ARCTAN("tan\u207B\u00B9", "arctan"),
        SEC("sec\u207B\u00B9", "sec"),
        CSC("csc\u207B\u00B9", "csc"),
        COT("cot\u207B\u00B9", "cot"),
        LN("ln");
        
        /** The name of the function type */
        private String name;
        
        /** The xml-safe name of the function type */
        private String xmlName;
        
        /** Constructor
         * @param nameAndXmlName The name of the function type and its xml-safe name
         */
        private FunctionType(String nameAndXmlName)
        {
            name = nameAndXmlName;
            xmlName = nameAndXmlName;
        }

        /** Constructor
         * @param normalName The name of the function type
         * @param xmlSafeName The xml-safe name of the function type
         */
        private FunctionType(String normalName, String xmlSafeName)
        {
            name = normalName;
            xmlName = xmlSafeName;
        }
        
        /** Returns the name of the function type
         * @return The name of the function type as a string (may contain high unicode characters) */
        public String getName()
        { return name; }

        /** Returns the XML safe name of the function type
         * @return The XML safe name of the function type as a string */
        public String getXmlName()
        { return xmlName; }
        
        /** Returns the {@link FunctionType} that belongs to the given XML safe name
         * @param xmlName The XML safe name
         * @return The {@link FunctionType}, or <tt>null</tt> if none belong to the given XML safe name */
        public static FunctionType getByXmlName(String xmlName)
        {
            if(xmlName.equals(SIN.xmlName))
                return SIN;
            else if(xmlName.equals(COS.xmlName))
                return COS;
            else if(xmlName.equals(TAN.xmlName))
                return TAN;
            else if(xmlName.equals(SINH.xmlName))
                return SINH;
            else if(xmlName.equals(COSH.xmlName))
                return COSH;
            else if(xmlName.equals(ARCSIN.xmlName))
                return ARCSIN;
            else if(xmlName.equals(ARCCOS.xmlName))
                return ARCCOS;
            else if(xmlName.equals(ARCTAN.xmlName))
                return ARCTAN;
            else if(xmlName.equals(LN.xmlName))
                return LN;
            return null;
        }
    }
    
    /** The paint that is used for drawing the operator */
    protected Paint operatorPaint = new Paint();
    
    /** The ratio (width : height) of a bracket (i.e. half the golden ratio) */
    private final float PARENTHESES_RATIO = 0.5f / 1.61803398874989f;

    /** Which function we represent */
    public FunctionType type = null;
    
    /** Default constructor */
    public Function()
    {
        this(FunctionType.SIN);
    }
    
    /**
     * Constructor with specified type
     * 
     * @param t
     *        The kind of function that we're constructing
     */
    public Function(FunctionType t)
    {
        this(t, null);
    }

    /**
     * Constructor with specified type and value.
     * 
     * @param t
     *        The kind of function that we're constructing
     * @param value
     *        The mathematical expression
     */
    public Function(FunctionType t, Expression value)
    {
        type = t;
        children.add(value != null ? value : new Empty());
        operatorPaint.setAntiAlias(true);
        operatorPaint.setStrokeWidth(Expression.lineWidth);
        operatorPaint.setTypeface(TypefaceHolder.dejavuSans);
    }
    
    /** Returns the current function type */
    public FunctionType getType()
    { return type; }
    
    @Override
    public String toString()
    {
        String childString = getChild(0).toString();
        if(childString.startsWith("(") && childString.endsWith(")"))
            childString = childString.substring(1, childString.length() - 1);
        return type.getXmlName() + '(' + childString + ')';
    }
    
    public int getPrecedence()
    { return Precedence.FUNCTION; }

    /** Calculates the right text size for the given level
     * @return The right text size for the given level */
    protected float findTextSize()
    {
        return defaultHeight * (float) Math.pow(2.0 / 3.0, level + 1);
    }   
    
    /** Adds padding to the given size rectangle
     * @param size The size where the padding should be added to
     * @return The size with the padding
     */
    protected Rect sizeAddPadding(Rect size)
    {
        // Copy the rectangle
        Rect out = new Rect(size);
        
        // Add the padding
        out.inset(-(int)(Expression.lineWidth  * 2.5), -(int)(Expression.lineWidth * 2.5));
        out.offsetTo(0, 0);
        
        // Return the result
        return out;
    }
    
    /** Calculates the size of this function when using the given font size
     * @param fontSize The font size
     * @return The size of this {@link MathConstant}
     */
    protected Rect getSize(float fontSize)
    {
        // Set the text size
        operatorPaint.setTextSize(fontSize);

        // Calculate the total width and the height of the text
        Rect out = new Rect(0, 0, 0, 0);
        operatorPaint.getTextBounds(type.getName(), 0, type.getName().length(), out);
        out.offsetTo(0, 0);
        
        // Return the size
        return out;
    }
    
    @Override
    public Rect[] calculateOperatorBoundingBoxes() 
    {
        // Get the sizes
        final Rect childRect = getChild(0).getBoundingBox();
        final int parentheseWidth = (int)(childRect.height() * PARENTHESES_RATIO);
        Rect textBounding = sizeAddPadding(getSize(findTextSize()));
        
        // Make sure everything is aligned nicely
        final int childCenterY = getChild(0).getCenter().y;
        final int childTop = Math.max(textBounding.centerY() - childCenterY, 0);
        textBounding.offsetTo(0, Math.max(childCenterY - textBounding.centerY(), 0));
        
        // Return the bounding boxes
        return new Rect[]{ textBounding,
                 new Rect(textBounding.width(), childTop, textBounding.width() + parentheseWidth, childTop + childRect.height()), 
                 new Rect(textBounding.width() + parentheseWidth + childRect.width(), childTop, textBounding.width() + childRect.width() + 2 * parentheseWidth, childTop + childRect.height())};
    }
    
    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException 
    {
        // Make sure the child index is valid
        checkChildIndex(index);
        
        // Gets the needed sizes and centres
        final Rect childRect = getChild(index).getBoundingBox();
        final int parentheseWidth = (int)(childRect.height() * PARENTHESES_RATIO);
        Rect textBounding = sizeAddPadding(getSize(findTextSize()));
        
        // Align the child's vertical centre with the text's vertical centre
        // also offset it horizontally to place it behind the opening bracket
        childRect.offsetTo(textBounding.width() + parentheseWidth, Math.max(textBounding.centerY() - getChild(index).getCenter().y, 0));
        
        // Return the result
        return childRect;
    }
    
    //Complete bounding box
    @Override
    public Rect calculateBoundingBox()
    {
        Rect[] operatorSizes = getOperatorBoundingBoxes();
        Rect child = getChild(0).getBoundingBox();
        
        return new Rect(0,Math.min(operatorSizes[0].top, child.top), operatorSizes[0].width() + operatorSizes[1].width() + operatorSizes[2].width() + child.width(), Math.max(getChild(0).getBoundingBox().height(), operatorSizes[0].height()));
    }

    
    @Override
    public Point calculateCenter()
    {        
        return new Point(this.getBoundingBox().centerX(), getChild(0).getCenter().y);
    }
    
    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes 
        drawBoundingBoxes(canvas);
        
        // Set the right values for the paint
        operatorPaint.setColor(getColor());
        operatorPaint.setTextSize(findTextSize());
        
        // Get our operator bounding boxes
        Rect[] operatorBounding = this.getOperatorBoundingBoxes();
        
        //Draws the operator
        canvas.save();
        Rect textBounding = new Rect();
        operatorPaint.getTextBounds(type.getName(), 0, type.getName().length(), textBounding);
        canvas.translate((operatorBounding[0].width() - textBounding.width()) / 2, (operatorBounding[0].height() - textBounding.height()) / 2);
        canvas.drawText(type.getName(), operatorBounding[0].left - textBounding.left, operatorBounding[0].top - textBounding.top, operatorPaint);
        canvas.restore();
        

        // Use stroke style for the parentheses
        operatorPaint.setStyle(Paint.Style.STROKE);
        
        // Draw the left bracket
        canvas.save();
        canvas.clipRect(operatorBounding[1], Region.Op.INTERSECT);
        RectF bracket = new RectF(operatorBounding[1]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(bracket.width() / 4, 0);
        canvas.drawArc(bracket, 100.0f, 160.0f, false, operatorPaint);
        canvas.restore();
        
        // Draw the right bracket
        canvas.save();
        canvas.clipRect(operatorBounding[2], Region.Op.INTERSECT);
        bracket = new RectF(operatorBounding[2]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(-bracket.width() / 4, 0);
        canvas.drawArc(bracket, -80.0f, 160.0f, false, operatorPaint);
        canvas.restore();

        // Set the paint back to fill style
        operatorPaint.setStyle(Paint.Style.FILL);
        
        // Draw the children
        drawChildren(canvas);
    }
    
    /** The name of the XML node for this class */
    public static final String NAME = "function";
    
    /** The XML attribute for which type of function this is */
    public static final String ATTR_TYPE = "type";

    @Override
    public final void writeToXML(Document doc, Element el)
    {
        Element e = doc.createElement(NAME);
        e.setAttribute(ATTR_TYPE, type.getXmlName());
        getChild(0).writeToXML(doc, e);
        el.appendChild(e);
    }
} public abstract class Operation extends Expression
{
    public static final String NAME = "operation";
    public static final String ATTR_OPERANDS = "operands";
    public static final String ATTR_TYPE = "type";

    /**
     * Construct unary mathematical operation (i.e. only one operand).
     * 
     * @see #MathOperation(int)
     */
    protected Operation()
    {
        this(1);
    }

    /**
     * Construct mathematical operation with specified number of operands. The
     * number of operands should be 1 or more. <b>Note:</b> the number of
     * operands is not guaranteed to be immutable. The implementation indicates
     * whether it is mutable.
     * 
     * @param operands
     *        The number of operands.
     */
    protected Operation(int operands)
    {
        if(operands < 1)
            throw new IllegalArgumentException(operands + ": invalid number of operands, 1 or more expected ");
        this.children.ensureCapacity(operands);
    }

    /**
     * Assign list to current children using deep-copy.
     * 
     * @param list
     *        The source collection.
     */
    protected void set(List<Expression> list)
    {
        if(list == null)
            throw new NullPointerException("list");
        
        children = new ArrayList<Expression>(list);
        for(int i = 0; i < list.size(); ++i)
        {
            if(children.get(i) == null)
                children.set(i, new Empty());
        }
    }
    
    protected abstract String getType();
    
    protected abstract void writeChildrenToXML(Document doc, Element el);
    
    public final void writeToXML(Document doc, Element el)
    {
        Element e = doc.createElement(NAME);
        e.setAttribute(ATTR_OPERANDS, String.valueOf(getChildCount()));
        e.setAttribute(ATTR_TYPE, getType());
        writeChildrenToXML(doc, e);
        el.appendChild(e);
    }
} public class Parentheses extends Expression
{
    /** The name of the XML element for this class */
    public static final String NAME = "parentheses";
    
    /** The ratio (width : height) of a bracket (i.e. half the golden ratio) */
    final float RATIO = 0.5f / 1.61803398874989f;
    
    /** The paint that's used to draw the parentheses */
    private Paint paint = new Paint();
    
    /** Default constructor */
    public Parentheses(int defWidth, int defHeight)
    { this(null); }

    /** Constructor
     * 
     * @param child The child to wrap the parentheses around
     */
    public Parentheses(Expression child)
    {
        // We have one child
        children.add(child == null ? new Empty() : child);
        
        // Initialise the paint
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
    }
    
    @Override
    public String toString()
    {
        final String str = getChild(0).toString();
        if(str.startsWith("(") && str.endsWith(")"))
            return str;
        return "(" + str + ")";
    }
    
    @Override
    public Rect[] calculateOperatorBoundingBoxes()
    {
    	final Rect childRect = getChild(0).getBoundingBox();
    	final int width = (int)(childRect.height() * RATIO);
        
        // Return the bounding boxes
        return new Rect[] {new Rect(0, 0, width, childRect.height()), new Rect(width + childRect.width(), 0, width * 2 + childRect.width(), childRect.height())};
    }
    
    @Override
    public Rect calculateBoundingBox()
    {
    	final Rect childRect = getChild(0).getBoundingBox();
    	return new Rect(0, 0, 2 * (int)(childRect.height() * RATIO) + childRect.width(), childRect.height());
    }
    
    public Expression getChild()
    {
        return getChild(0);
    }
    
    public void setChild(Expression child)
    {
        setChild(0, child);
    }

    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException
    {
        // Check the child index
        checkChildIndex(index);
        
        // Get the sizes
        Rect childRect = getChild(0).getBoundingBox();
        
        // Position the bounding box of the child
        childRect.offset((int)(childRect.height() * RATIO), 0);
        
        // Return the bounding box
        return childRect;
    }

    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the operator bounding boxes
        Rect[] boxes = getOperatorBoundingBoxes();
        
        // Prepare the paint and canvas for drawing the brackets
        paint.setColor(getColor());
        paint.setStrokeWidth(lineWidth);
        
        // Draw the left bracket
        canvas.save();
        canvas.clipRect(boxes[0], Region.Op.INTERSECT);
        RectF bracket = new RectF(boxes[0]);
        bracket.inset(0, -paint.getStrokeWidth());
        bracket.offset(bracket.width() / 4, 0);
        canvas.drawArc(bracket, 100.0f, 160.0f, false, paint);
        canvas.restore();
        
        // Draw the right bracket
        canvas.save();
        canvas.clipRect(boxes[1], Region.Op.INTERSECT);
        bracket = new RectF(boxes[1]);
        bracket.inset(0, -paint.getStrokeWidth());
        bracket.offset(-bracket.width() / 4, 0);
        canvas.drawArc(bracket, -80.0f, 160.0f, false, paint);
        canvas.restore();
        
        // Draw the child
        drawChildren(canvas);
    }

    @Override
    public void writeToXML(Document doc, Element el)
    {
        Element e = doc.createElement(NAME);
        children.get(0).writeToXML(doc, e);
        el.appendChild(e);
    }
    
    @Override
    public Point calculateCenter()
    {
    	return new Point( this.getBoundingBox().centerX(), this.getChild(0).getCenter().y);
    }
} public class Symbol extends Expression
{
    /**
     * Cached mathematical symbolic constant for the mathematical <tt>-1</tt> in
     * order to speed up helpers and parsers so they don't need to make this
     * symbolic constant themselves.
     */
    public static final Symbol M_ONE = new Symbol(-1);
    /**
     * Cached mathematical symbolic constant for the mathematical <tt>0</tt> in
     * order to speed up helpers and parsers so they don't need to make this
     * symbolic constant themselves.
     */
    public static final Symbol ZERO = new Symbol();
    /**
     * Cached mathematical symbolic constant for the mathematical <tt>1</tt> in
     * order to speed up helpers and parsers so they don't need to make this
     * symbolic constant themselves.
     */
    public static final Symbol ONE = new Symbol(1);
    /**
     * Cached mathematical symbolic constant for the mathematical <tt>10</tt> in
     * order to speed up helpers and parsers so they don't need to make this
     * symbolic constant themselves.
     */
    public static final Symbol TEN = new Symbol(10);
    
    /** The factor of this constant */
    private double factor = 0;
    /** The power of the E constant */
    private long ePow = 0;
    /** The power of the PI constant */
    private long piPow = 0;
    /** The power of the imaginary unit */
    private long iPow = 0;
    /** The powers of the variables */
    private long varPows[] = new long[VAR_POWS_LENGTH];
    
    /**
     * Maximum supported number of variable powers. Specifying arrays with more
     * elements than {@code VAR_POWS_LENGTH} will be accepted, but only the
     * first {@code VAR_POWS_LENGTH} elements will be copied.
     */
    public static final int VAR_POWS_LENGTH = 26;
    
    /** The paint that is used to draw the factor and the constants */
    protected Paint paint = new Paint();
    
    /** Superscript character lookup table */
    private final static char[] SUPERSCRIPT = new char[] {'\u2070', '\u00b9', '\u00b2', '\u00b3','\u2074','\u2075','\u2076','\u2077', '\u2078', '\u2079'};

    /** Default constructor */
    public Symbol()
    { 
        this(0);
    }
    
    /**
     * Simple constructor with a factor just for simplicity.
     * @param factor The base number
     */
    public Symbol(double factor)
    {
        this(factor, 0, 0, 0);
    }
    
    /** Construct mathematical constant using specified values for simplicity.
     * @param factor The base number
     * @param ePow The Euler power
     * @param piPow The pi power
     * @param iPow The imaginary power
     */
    public Symbol(double factor, long ePow, long piPow, long iPow)
    {
        this(factor, ePow, piPow, iPow, new long[0]);
    }
    
    /** Construct mathematical constant using specified values.
     * @param factor The base number
     * @param ePow The Euler power
     * @param piPow The pi power
     * @param iPow The imaginary power
     * @param varPows The first <tt>varPows.length</tt> powers for the variables (may be <tt>null</tt>)
     */
    public Symbol(double factor, long ePow, long piPow, long iPow, long[] varPows)
    {
        initPaints();
        setFactor(factor);
        this.ePow = ePow;
        this.piPow = piPow;
        this.iPow = iPow;
        if(varPows != null)
        {
            // arraycopy is safer and more efficient.
            System.arraycopy(varPows, 0, this.varPows, 0, Math.min(VAR_POWS_LENGTH, Math.min(varPows.length, this.varPows.length)));
        }
    }
    
    /** Returns a symbol that simply consists out of the given variable
     * @param var The variable that should be put in the symbol
     * @return The symbol with the given variable */
    public static Symbol createVarSymbol(char var)
    {
        Symbol out = new Symbol(1);
        out.setVarPow(var, 1);
        return out;
    }
    
    /** Initialises the paints */
    private void initPaints()
    {
        paint.setAntiAlias(true);
        paint.setTypeface(TypefaceHolder.dejavuSans);
    }

    /**
     * Helper method for appending literals.
     * @param sb The {@link StringBuilder} to append the string to
     * @param c The character of the symbol
     * @param pow The power of the symbol
     */
    private static void appendLit(StringBuilder sb, char c, long pow)
    {
        if(pow != 0)
        {
            sb.append(c);
            if(pow != 1)
            {
                if(pow < 0)
                {
                    sb.append('\u207b');
                    pow *= -1;
                }
                long num = pow;
                StringBuilder sb2 = new StringBuilder();
                while (num > 0)
                {
                    sb2.append(SUPERSCRIPT[(int) (num % 10)]);
                    num /= 10;
                }
                sb.append(sb2.reverse());
            }
        }
    }
    
    /** Calculates the size of this {@link Symbol} when using the given font size
     * @param fontSize The font size
     * @return The size of this {@link Symbol}
     */
    protected Rect getSize(float fontSize)
    {
        // Set the text size
        paint.setTextSize(fontSize);
        
        // Calculate the total width and the height of the text
        Rect out = new Rect(0, 0, 0, 0);
        Rect bounds = new Rect();
        String str = toString();
        str = str.substring(1, str.length() - 1);
        paint.getTextBounds(str, 0, str.length(), bounds);      
        out.right = bounds.width();
        out.bottom = bounds.height();
        return out;
    }

    /** Adds padding to the given size rectangle
     * @param size The size where the padding should be added to
     * @return The size with the padding
     */
    protected Rect sizeAddPadding(Rect size)
    {
        // Copy the rectangle
        Rect out = new Rect(size);
        
        // Add the padding
        out.inset(-(int)(Expression.lineWidth  * 2.5), -(int)(Expression.lineWidth * 2.5));
        out.offsetTo(0, 0);
        
        // Return the result
        return out;
    }
    
    /** Calculates the right text size for the given level
     * @param lvl The level
     * @return The right text size for the given level */
    protected float findTextSize(int lvl)
    {
        return defaultHeight * (float) Math.pow(2.0 / 3.0, Math.min(lvl, MAX_LEVEL));
    }

    @Override
    public Rect[] calculateOperatorBoundingBoxes()
    {
        // Find the right text size and return the bounding box for it
        return new Rect[]{ sizeAddPadding(getSize(findTextSize(level))) };
    }

    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException
    {
        // Will always throw an error since constants do not have children
        checkChildIndex(index);
        return null;
    }
    
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the text size and the bounding box
        final float textSize = findTextSize(level);
        Rect textBounding = getSize(textSize);
        Rect totalBounding = sizeAddPadding(textBounding);

        // Set the text size and colour
        paint.setTextSize(textSize);
        paint.setColor(getColor());
        
        // Translate the canvas
        canvas.save();
        canvas.translate((totalBounding.width() - textBounding.width()) / 2, (totalBounding.height() - textBounding.height()) / 2);

        String str = toString();
        str = str.substring(1, str.length() - 1);
        Rect bounds = new Rect();
        paint.getTextBounds(str, 0, str.length(), bounds);
        canvas.drawText(str, -bounds.left, textBounding.height() - bounds.height() - bounds.top, paint);
        
        // Restore the canvas translation
        canvas.restore();
    }
    
    /**
     * Check whether the current instance and <tt>o</tt> are identical. It is
     * heavily called by unit test cases, so do not remove this method!
     * @param o the instance to compare with
     * @return <tt>true</tt> when equal, <tt>false</tt> otherwise.
     */
    public boolean equals(Object o)
    {
        if(!(o instanceof Symbol))
            return false;
        Symbol c = (Symbol) o;

        return c.factor == factor && c.ePow == ePow && c.piPow == piPow && c.iPow == iPow && Arrays.equals(c.varPows, varPows);
    }
    
    /**
     * Gives the constant as a string
     * @return The constant as a string
     */
    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();

        if(symbolVisible())
            sb.append(factor == -1 ? '-' : (factor == 1 ? "" : doubleToString(factor)) );
        else
            sb.append(doubleToString(factor));
        
        if(factor != 0)
        {
            appendLit(sb, '\u03c0', piPow);
            appendLit(sb, 'e', ePow);
            appendLit(sb, '\u03b9', iPow);
            for(int i = 0; i < varPows.length; i++)
                appendLit(sb, (char) (i + 'a'), varPows[i]);
        }
        return "(" + sb.toString() + ")";
    }
    
    /** Converts a <tt>double</tt> to a string, dropping <tt>".0"</tt> if necessary.
     * Also returns, for example, <tt>"0.002"</tt> instead of <tt>"2.0E-3"</tt>.
     * @param x The <tt>double</tt> to convert
     * @return The <tt>double</tt> as a string */
    private String doubleToString(double x)
    {
        // Convert the double to a string
        String str = Double.toString(x);
        
        // Search for an 'E'
        final int ePos = str.indexOf('E');
        if(ePos != -1)
        {
            // Determine the amount of zeros and whether they need to be appended or prepended
            int zeros = Integer.parseInt(str.substring(ePos + 1));
            final boolean append = zeros >= 0;
            if(!append)
                zeros = (-zeros) - 1;
            
            // Remember the part before the 'E'
            String before = str.substring(0, ePos);
            final int dotPos = before.indexOf('.');
            if(dotPos != -1)
            {
                String tmp = before.substring(dotPos + 1);
                while(tmp.endsWith("0"))
                    tmp = tmp.substring(0, tmp.length() - 1);
                before = before.substring(0, dotPos) + tmp;
                
                if(append)
                    zeros -= tmp.length();
                if(zeros < 0)
                    before = before.substring(0, before.length() + zeros) + '.' + before.substring(before.length() + zeros);
            }
            boolean negative = before.startsWith("-");
            if(negative)
                before = before.substring(1);
            
            // Prepend/append the zeros
            while(zeros > 0)
            {
                if(append)
                    before += '0';
                else
                    before = '0' + before;
                --zeros;
            }
            if(zeros == 0 && !append)
                before = "0." + before;
            
            // Put back the minus sign
            if(negative)
                before = '-' + before;
            
            // Remember the result
            str = before;
        }
        
        // Chop off unnecessary '.' and '0'
        while(str.contains(".") && (str.endsWith(".") || str.endsWith("0")))
            str = str.substring(0, str.length() - 1);
        
        // Return the string
        return str;
    }

    /**
     * Checks whether only {@code factor != 0}.
     * 
     * @return <tt>true</tt> if all other variables equal <tt>0</tt>.
     *         <tt>false</tt> otherwise.
     */
    public boolean isFactorOnly()
    {
        for(int i = 0; i < varPows.length; ++i)
        {
            if(varPows[i] != 0)
            {
                return false;
            }
        }
        return ePow == 0 && piPow == 0 && iPow == 0;
    }

    /** Retrieve the factor
     * @return The base number */
    public double getFactor()
    { return factor; }

    /** Assign the new factor to <tt>factor</tt>
     * @param factor the new <tt>factor</tt> */
    public void setFactor(double factor)
    {
        // Round the factor to 6 decimals
        double decimals = factor > 0 ? factor - Math.floor(factor) : factor - Math.ceil(factor);
        decimals = Math.round(decimals * 1000000) / 1000000.0;
        
        // Set the factor
        this.factor = (factor > 0 ? Math.floor(factor) : Math.ceil(factor)) + decimals;
    }
    
    /**
     * Invert the current factor and return the new value.
     * @return <tt>-</tt>{@link factor}
     */
    public double invertFactor()
    {
        return this.factor = -factor;
    }

    /** Get the current power for <tt>pi</tt>
     * @return The current power for <tt>pi</tt> */
    public long getPiPow()
    { return piPow; }

    /** Set the new power for <tt>pi</tt>
     * @param piPow the new power for <tt>pi</tt> */
    public void setPiPow(long piPow)
    { this.piPow = piPow; }

    /** Get the current power for <tt>e</tt>
     * @return The current power for <tt>e</tt> */
    public long getEPow()
    { return ePow; }

    /** Set the new power for <tt>e</tt>
     * @param ePow the new power for <tt>e</tt> */
    public void setEPow(long ePow)
    { this.ePow = ePow; }

    /** Get the current power for <tt>i</tt>
     * @return The current power for <tt>i</tt> */
    public long getIPow()
    { return iPow; }

    /** Set the new power for <tt>i</tt>
     * @param iPow the new power for <tt>i</tt> */
    public void setIPow(long iPow)
    { this.iPow = iPow; }

    /** Get the current power for the given variable
     * @param index The variable index
     * @return The current power for the given variable */
    public long getVarPow(int index)
    { return varPows[index]; }

    /** Set the new power for the given variable
     * @param index The variable index
     * @param pow the new power for the variable */
    public void setVarPow(int index, long pow)
    { varPows[index] = pow; }
    
    public void setVarPow(char index, long pow)
    { setVarPow(index > 'Z' ? index - 'a' : index - 'A', pow); }
    
    public int getVarCount()
    {
        int count = 0;
        for (int i = 0; i < varPows.length; ++i)
        {
            if (varPows[i] != 0)
                ++count;
        }
        return count;
    }
    
    /** The amount of variables that this symbol supports */
    public int varPowCount()
    { return varPows.length; }
    
    /**
     * Raises the current symbol to the given power. That is, all powers are multiplied with the given power.
     * @param power The power to multiply the current powers with.
     * @return True if successful, or false otherwise (e.g. when one of the powers wouldn't be an integer).
     */
    public boolean tryRaisePower(double power)
    {
        try
        {
            // Try multiplying the powers
            long newPiPow = tryMultiplyWithIntegerResult(piPow, power);
            long newEPow = tryMultiplyWithIntegerResult(ePow, power);
            long newIPow = tryMultiplyWithIntegerResult(iPow, power);
            long[] newVarPows = new long[varPows.length];
            for(int i = 0; i < varPows.length; ++i)
            {
                newVarPows[i] = tryMultiplyWithIntegerResult(varPows[i], power);
            }

            // If we've come here, all powers could be multiplied successfully and we can use the new powers
            piPow = newPiPow;
            ePow = newEPow;
            iPow = newIPow;
            varPows = newVarPows;

            // We have successfully raised the symbol to a power
            return true;
        }
        catch(Exception exc)
        {
            return false;
        }
    }

    /**
     * Reset all numerical values to new specified values.
     * @param factor The new factor
     * @param ePow The new euler power
     * @param piPow The new pi power
     * @param iPow The new imaginary power
     */
    public void set(double factor, long ePow, long piPow, long iPow)
    {
        setFactor(factor);
        setEPow(ePow);
        setPiPow(piPow);
        setIPow(iPow);
    }

    /** Returns whether or not some symbols (i.e. variables or the constants pi, e, i) are visible (i.e. their power != 0)
     * @return True if one or more symbols are visible, false otherwise */
    public boolean symbolVisible()
    {
        if((piPow | ePow | iPow) != 0)
            return true;
        for(int i = 0; i < varPows.length; ++i)
        {
            if(varPows[i] != 0)
                return true;
        }
        return false;
    }
    
    /** The XML element name */
    public static final String NAME = "constant";
    /** The factor XML element attribute */
    public static final String ATTR_FACTOR = "factor";
    /** The E constant XML element attribute */
    public static final String ATTR_E = "eulers_number";
    /** The PI constant XML element attribute */
    public static final String ATTR_PI = "pi";
    /** The I constant XML element attribute */
    public static final String ATTR_I = "imaginary_unit";
    /** The prefix for a variable XML element attribute (followed by the name of the variable) */
    public static final String ATTR_VAR = "var_";
    
    @Override
    public void writeToXML(Document doc, Element el)
    {
        Element e = doc.createElement(NAME);
        e.setAttribute(ATTR_FACTOR, String.valueOf(factor));
        e.setAttribute(ATTR_E, String.valueOf(ePow));
        e.setAttribute(ATTR_PI, String.valueOf(piPow));
        e.setAttribute(ATTR_I, String.valueOf(iPow));
        for(int i = 0; i < varPows.length; i++)
        {
            if(varPows[i] != 0)
                e.setAttribute(ATTR_VAR + (char) ('a' + i), String.valueOf(varPows[i]));
        }
        el.appendChild(e);
    }

    /** The precision for determining roundoff errors in the powers. */
    private static final double EPSILON = 0.0000001;

    /**
     * Tries to multiply the given integer and real number to get an integer result.
     * Throws an exception if the result is not an integer.
     * @param integer The integer to multiply with the real value.
     * @param real The real value to multiply with the integer.
     * @return The multiplied value.
     * @throws Exception When the result is not an integer.
     */
    private long tryMultiplyWithIntegerResult(long integer, double real) throws Exception
    {
        double result = integer * real;
        long resultAsInteger = Math.round(result);
        if(Math.abs(result - resultAsInteger) >= EPSILON)
            throw new Exception("Multiplying " + Long.toString(integer) + " and " + Double.toString(real) + " does not give an integer.");
        return resultAsInteger;
    }
} public abstract class Binary extends Operation
{	
    public Binary()
    {
        this(null, null);
    }

    public Binary(Expression left, Expression right)
    {
        // We have two children
        children.add(new Empty());
        children.add(new Empty());
        
        // Set the left and right child
        set(left, right);
    }
    
    public String toString()
    {
        return "(" + getLeft().toString() + "," + getRight().toString() + ")";
    }
    
    /**
     * Ensure both children are not empty. If at least one of them is empty,
     * <tt>EmptyChildException</tt> will be thrown with the empty index number.
     * @throws EmptyChildException Thrown when at least one of both children is
     * empty.
     */
    protected void checkChildren() throws EmptyChildException
    {
        if(getChild(0) == null)
            throw new EmptyChildException(0);
        if(getChild(1) == null)
            throw new EmptyChildException(1);
    }
    /**
     * Set mathematical expression to the left and to the right to new specified
     * mathematical objects.
     * 
     * @param left
     *        The mathematical expression to the left.
     * @param right
     *        The mathematical expression to the right.
     */
    public void set(Expression left, Expression right)
    {
        setChildWithoutRefresh(0, left);
        setChildWithoutRefresh(1, right);
        setAll(level, defaultHeight, false);
    }

    /**
     * Assign <tt>o</tt> to mathematical expression to the left.
     * 
     * @param o
     *        The mathematical expression.
     */
    public void setLeft(Expression o)
    {
        setChild(0, o);
    }

    /**
     * Retrieve the mathematical expression to the left. <b>Note:</b>
     * <tt>null</tt> may be returned.
     * 
     * @return The mathematical expression to the left.
     */
    public Expression getLeft()
    {
        return getChild(0);
    }

    /**
     * Assign <tt>o</tt> to mathematical expression to the right.
     * 
     * @param o
     *        The mathematical expression.
     */
    public void setRight(Expression o)
    {
        setChild(1, o);
    }

    /**
     * Retrieve the mathematical expression to the right. <b>Note:</b>
     * <tt>null</tt> may be returned.
     * 
     * @return The mathematical expression to the right.
     */
    public Expression getRight()
    {
        return getChild(1);
    }
    
    /**
     * Returns the sizes of the bounding of the children.
     * 
     * @param maxWidth
     *        The maximum width the {@link MathObject} can have (can be {@link MathObject#NO_MAXIMUM})
     * @param maxHeight
     *        The maximum height the {@link MathObject} can have (can be {@link MathObject#NO_MAXIMUM})
     * @return The size of the child bounding boxes
     */
    public Rect[] getChildrenSize()
    {
        // Get the sizes both operands want to take
        Rect leftSize = getChild(0).getBoundingBox();
        Rect rightSize = getChild(1).getBoundingBox();
        
        // Return the Sizes
        return new Rect[] {leftSize, rightSize};
    }
    
    protected final void writeChildrenToXML(Document doc, Element el)
    {
        getLeft().writeToXML(doc, el);
        getRight().writeToXML(doc, el);
    }
} public class Integral extends Operation
{

	protected Paint operatorPaint = new Paint();
	public static final String TYPE = "integral";
	final float signHeightAdd = 1.5f;
	final float maxSignWidth = 100;
	final float RATIO = 0.5f / 1.61803398874989f;
	final float betweenIntegralPadding = 10 * lineWidth;
	final int maxFontSize = 500;
	final String integralSign = "\u222B"; // Unicode for the integral sign
	
	public Integral()
	{ this(null, null, null, null); }
	
	public Integral(Expression integrate, Expression over)
    { this(integrate, over, null, null); }
	
	public Integral(Expression integrate, Expression over, Expression from, Expression to)
	{
	    super(4);
	    
		children.add(new Empty());
        children.add(new Empty());
        children.add(new Empty());
        children.add(new Empty());
        
        levelDeltas = new int[] {1, 1, 1, 1};
        
		set(integrate, over, from, to);
		initPaint();
	}
	
	private void initPaint()
	{
	    operatorPaint.setTypeface(TypefaceHolder.dejavuSans);
	    operatorPaint.setAntiAlias(true);
	}
	
	public String toString()
	{
	    String over = getIntegrateOver().toString();
	    if(over.startsWith("(") && over.endsWith(")"))
	        over = over.substring(1, over.length() - 1);
	    
		if(getIntegrateFrom() instanceof Empty && getIntegrateTo() instanceof Empty)
			return "Integrate(" + getIntegratePart().toString() + "," + over + ")";
		else
			return "Integrate(" + getIntegratePart().toString() + ",{" + over + "," + getIntegrateFrom().toString() + "," + getIntegrateTo().toString() + "})";
	}

    public int getPrecedence()
    { return Precedence.INTEGRAL; }
	
    private Rect[] getIntegrateOverSizes()
    {
    	Expression child = getIntegratePart();
    	
    	while(true)
    	{
    		if(!(((Integral) child).getIntegratePart() instanceof Integral))
    			return ((Integral) child).getSizes();
    		
    		child = ((Integral) child).getIntegratePart();
    	}
    }
    
	public Rect[] getSizes()
	{
		/* Index of the rectangles
		 * 0: bb of the integral sign
		 * 1: bb of the thing to integrate
		 * 2: bb of the thing to integrate over
		 * 3: bb of the "d"
		 * 4: bb of the to integral
		 * 5: bb of the from integral
		 */
		
		// Get the bounding boxes of the children
		Rect main = getChild(0).getBoundingBox();
		Rect over = getChild(1).getBoundingBox();
		
		Rect from = getChild(2).getBoundingBox();
		Rect to = getChild(3).getBoundingBox();
		
		// Calculate the height and width of the integral sign
		int signHeight;
		
		if(getIntegratePart() instanceof Integral)
		{
			Rect[] childSizes = getIntegrateOverSizes();
			signHeight = (int) (Math.max( childSizes[1].height(), childSizes[2].height()) * signHeightAdd);
		}
		else
			signHeight = (int) (Math.max( main.height(), over.height()) * signHeightAdd);

		Rect sign = new Rect( );
		
		operatorPaint.setTextSize( Math.min( maxFontSize, signHeight));
		operatorPaint.getTextBounds( integralSign, 0, integralSign.length(), sign);
		
		// Add some padding
		sign.bottom += sign.height() * 0.2;
		sign.right += sign.width() * 0.4;
		
		// Get the bounding box of the d
		operatorPaint.setTextSize( Math.min( maxFontSize, over.height()));
		Rect bounds = new Rect();
		operatorPaint.getTextBounds( "d", 0, "d".length(), bounds);
		
		// add a nice padding between the d and the last child
		bounds.right += bounds.width() * 0.2;
		
		// Return all the bounding boxes
		return new Rect[]	{
								sign,
								main,
								over,
								bounds,
								to,
								from
							};
	}
	
	
	@Override
	public Rect[] calculateOperatorBoundingBoxes() {
		
		// Get all the sizes of the bounding boxes
		Rect sizes[] = getSizes();
		int horizontalOffset = getHorizontalOffset( sizes );
		int height = sizes[0].height();
				
		// Offset all the bounding boxes
		if(getIntegratePart() instanceof Integral)
		{			
			sizes[0].offsetTo( horizontalOffset, (int) Math.max( getIntegralSignHeightOffset(), sizes[4].height()));
			sizes[3].offsetTo( (int) betweenIntegralPadding + Math.max( Math.max( horizontalOffset + sizes[0].width(), sizes[4].width()), sizes[5].width()) + sizes[1].width(), Math.max( sizes[4].height(),(int) getIntegralSignHeightOffset()) + (sizes[0].height() - sizes[3].height()) / 2);		
		}else{
			sizes[0].offsetTo( horizontalOffset, sizes[4].height());
			sizes[3].offsetTo( horizontalOffset + sizes[0].width() + sizes[1].width(), sizes[4].height() + (height - sizes[3].height()) / 2);		
		}
		// Return them
		return new Rect[]	{	
								sizes[0],
								sizes[3]
							};
	}

	@Override
	public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException {
		// Get the sizes of the bounding boxes
		Rect[] sizes = getSizes();
				
		int horizontalOffset = getHorizontalOffset( sizes );
		int signWidth = Math.max( Math.max( sizes[0].width(), sizes[4].width()), sizes[5].width());
		int height = sizes[0].height();
				
		// Offset all the bounding boxes
		if(getIntegratePart() instanceof Integral)
		{			
			sizes[1].offsetTo( (int) betweenIntegralPadding + Math.max( Math.max(horizontalOffset + sizes[0].width(), sizes[4].width()), sizes[5].width()), Math.max( 0, sizes[4].height() - (int) getIntegralSignHeightOffset()));

			sizes[4].offsetTo( Math.max( 0, signWidth - sizes[4].width()) / 2, Math.max( 0, (int) getIntegralSignHeightOffset() - sizes[4].height()));
			sizes[5].offsetTo( Math.max( 0, signWidth - sizes[5].width()) / 2, sizes[4].height() + sizes[0].height() + Math.max( 0, (int) getIntegralSignHeightOffset() - sizes[4].height()));
			sizes[2].offsetTo( (int) betweenIntegralPadding + Math.max( Math.max(horizontalOffset + sizes[0].width(), sizes[4].width()),  sizes[5].width()) + sizes[1].width() + sizes[3].width(), (sizes[0].height() - sizes[2].height())/2 + sizes[4].bottom);
		}
		else
		{
			sizes[1].offsetTo( horizontalOffset + sizes[0].width(), sizes[4].height() + (height - sizes[1].height()) / 2);
			sizes[2].offsetTo( horizontalOffset + sizes[0].width() + sizes[1].width() + sizes[3].width(), sizes[4].height() + (height - sizes[2].height()) / 2);
			sizes[4].offsetTo( Math.max( 0, signWidth - sizes[4].width()) / 2, 0);
			sizes[5].offsetTo( Math.max( 0, signWidth - sizes[5].width()) / 2, sizes[0].height() + sizes[4].height());
		}

		// Switch to return the correct bounding box
		switch( index) 
		{
		case 0:
			return sizes[1];
					
		case 1:
			return sizes[2];

		case 2:
			return sizes[5];
					
		case 3:
			return sizes[4];
		}
				
		return null;
	}
	
	@Override
    public Rect calculateBoundingBox()
    {
		// Get the sizes
        Rect[] sizes = getSizes();
        int horizontalOffset = getHorizontalOffset( sizes );
        
        // Return a bounding box, containing the bounding boxes of the children
        int width, height;
        
        if(getIntegratePart() instanceof Integral)
        {
        	width = (int) betweenIntegralPadding + Math.max(Math.max(horizontalOffset + sizes[0].width(), sizes[4].width()),sizes[5].width()) + sizes[1].width() + sizes[3].width() + sizes[2].width();
        	height = Math.max(getIntegratePart().getBoundingBox().height() + getChildBoundingBox(0).top, sizes[0].height() + sizes[4].height() + sizes[5].height() + getChildBoundingBox(3).top);
        }
        else
        {
        	width = horizontalOffset + sizes[0].width() + sizes[1].width() + sizes[3].width() + sizes[2].width();
        	width = Math.max( Math.max( width,  sizes[4].width()), sizes[5].width());
        	height = sizes[0].height() + sizes[4].height() + sizes[5].height();
        }

        return new Rect(0, 0, width, height);
    }

	private float getIntegralSignHeightOffset()
	{
		float result = 0;
		
		Expression child = getIntegratePart();
    	
    	while(true)
    	{
    		if(!(((Integral) child).getIntegratePart() instanceof Integral))
    			return Math.max( result, ((Integral) child).getIntegrateTo().getBoundingBox().height());
    		else
    			result = Math.max( result, ((Integral) child).getIntegrateTo().getBoundingBox().height());
    		
    		child = ((Integral) child).getIntegratePart();
    	}
		
	}
	
	@Override
	public void draw(Canvas canvas) {
		// Draw the bounding boxes
		drawBoundingBoxes( canvas);
				
		operatorPaint.setColor(getColor());
		operatorPaint.setStrokeWidth(lineWidth);
				
		// Get the sizes
		Rect[] sizes = getSizes();
		int horizontalOffset = getHorizontalOffset( sizes );
				
		int height = sizes[0].height();        
        
        // Draw the integral sign
        if(getIntegratePart() instanceof Integral)
        {
        	Rect[] childSizes = getIntegrateOverSizes();
        	
        	// Draw the D
            operatorPaint.setStyle(Paint.Style.FILL);
            operatorPaint.setTextSize( Math.min( maxFontSize, sizes[2].height()) );
            canvas.drawText( "d", (int) betweenIntegralPadding + Math.max(Math.max( horizontalOffset + sizes[0].width(), sizes[4].width()), sizes[5].width()) + sizes[1].width(), Math.max( getIntegralSignHeightOffset(), sizes[4].height()) + (sizes[0].height() + sizes[3].height())/2, operatorPaint);
            
            operatorPaint.setTextSize( Math.min( maxFontSize, Math.max( childSizes[1].height(), childSizes[2].height()) * signHeightAdd));
            sizes[0].offsetTo( (int) ((sizes[0].width() / 1.2) * 0.1 + horizontalOffset),  (int) (Math.max( getIntegralSignHeightOffset(), sizes[4].height()) + sizes[0].height() * 0.75)); // We need to decrease the height by a little bit, because the integral sign isn't draw with the origin at the bottom.
        }
        else
        {
        	// Draw the D
            operatorPaint.setStyle(Paint.Style.FILL);
            operatorPaint.setTextSize( Math.min( maxFontSize, sizes[2].height()) );
            canvas.drawText( "d", horizontalOffset + sizes[0].width() + sizes[1].width(), sizes[4].height() + (height - sizes[3].height()) / 2 + sizes[3].height(), operatorPaint);
            
        	operatorPaint.setTextSize( (int) (Math.min( maxFontSize, Math.max( sizes[1].height(), sizes[2].height()) * signHeightAdd)));
        	sizes[0].offsetTo( (int) ((sizes[0].width() / 1.2) * 0.1 + horizontalOffset), (int) (sizes[4].height() + sizes[0].height() * 0.75)); // We need to decrease the height by a little bit, because the integral sign isn't draw with the origin at the bottom.
        }
        
        canvas.drawText( integralSign, sizes[0].left, sizes[0].top, operatorPaint);
        
        // Draw the children
		drawChildren( canvas);
	}

	int getHorizontalOffset(Rect[] sizes)
	{
		// Get the offset between the integral sign and the left side of the bounding box
		return Math.max( 0, Math.max( sizes[4].width(), sizes[5].width()) - sizes[0].width()) / 2;
	}
	
	public void set(Expression integrate, Expression over)
	{ set(integrate, over, getIntegrateFrom(), getIntegrateTo()); }
	
	public void set(Expression integrate, Expression over, Expression from, Expression to)
    {
	    // Check whether `over` is valid
        if(over != null)
        {
            if(!(over instanceof Symbol))
                throw new IllegalArgumentException("'over' should be null or a symbolic constant");
            
            Symbol sym = (Symbol) over;
            if(sym.getVarCount() != 1)
                throw new IllegalArgumentException("multiple variables not allowed for 'over'");
        }
        
		// Set all the children
        setChildWithoutRefresh(0, integrate);
        setChildWithoutRefresh(1, over);
        setChildWithoutRefresh(2, from);
        setChildWithoutRefresh(3, to);
        setAll(level, defaultHeight, false);
    }
	
	/** Returns the child that should be integrated */
	public Expression getIntegratePart()
	{ return getChild(0); }

    /** Returns the child over which should be integrated */
    public Expression getIntegrateOver()
    { return getChild(1); }
    
    /** Returns the child from whose value should be integrated */
    public Expression getIntegrateFrom()
    { return getChild(2); }

    /** Returns the child to whose value should be integrated */
    public Expression getIntegrateTo()
    { return getChild(3); }
	
	@Override
  	public void setLevel(int l)
  	{
        // Invalidate the cache (if necessary)
        if(l != level)
            invalidateBoundingBoxCacheForSelf();
        
        // Set the level
        level = l;
        
        // Special treatment for the integrate part
        if(getIntegratePart() instanceof Integral)
            getChild(0).setLevel(level);
        else
            getChild(0).setLevel(level + 1);
        
        // Set the level every child
        for(int i = 1; i < getChildCount(); ++i)
        {
            if(levelDeltas != null && i < levelDeltas.length)
                getChild(i).setLevel(l + levelDeltas[i]);
            else
                getChild(i).setLevel(l);
        }
  	}

    @Override
	public void setAll(int lvl, int defHeight, boolean valid)
    {
        // Set the values
        level = lvl;
        defaultHeight = defHeight;
        operatorBoundingBoxValid = valid;
        childrenBoundingBoxValid = valid;
        totalBoundingBoxValid = valid;
        centerValid = valid;
        
        // Special treatment for the integrate part
        if(getIntegratePart() instanceof Integral)
            getChild(0).setAll(lvl, defHeight, valid);
        else
            getChild(0).setAll(lvl + 1, defHeight, valid);
        
        // Set the values for all children
        for(int i = 1; i < getChildCount(); ++i)
        {
            if(levelDeltas != null && i < levelDeltas.length)
                getChild(i).setAll(lvl + levelDeltas[i], defHeight, valid);
            else
                getChild(i).setAll(lvl, defHeight, valid);
        }
    }
	
	@Override
	protected String getType()
	{
		return TYPE;
	}

	@Override
	protected void writeChildrenToXML(Document doc, Element el)
	{
	    for(Expression child : children)
	        child.writeToXML(doc, el);
	}

	@Override
    public boolean isCompleted()
    {
	    if(!getIntegratePart().isCompleted() || !getIntegrateOver().isCompleted())
	        return false;
        if(getIntegrateFrom() instanceof Empty && getIntegrateTo() instanceof Empty)
            return true;
        if(getIntegrateFrom().isCompleted() && getIntegrateTo().isCompleted())
            return true;
        return false;
    }
} public class Limit extends Operation
{
    public static final String TYPE = "limit";
    
    private String name = "lim";
    
    /** The ratio (width : height) of a bracket (i.e. half the golden ratio) */
    private final float PARENTHESES_RATIO = 0.5f / 1.61803398874989f;
    
    /** The paint that is used for drawing the operator */
    protected Paint operatorPaint = new Paint();
    
    /** Constructor
     * @param start What variable should be approach the value of <tt>end</tt>
     * @param end The value that <tt>start</tt> should approach
     * @param expression The expression to calculate the limit of
     */
    public Limit(Expression start, Expression end, Expression expression)
    {
        super(3);
        
        setChildWithoutRefresh(0, start);
        setChildWithoutRefresh(1, end);
        setChildWithoutRefresh(2, expression);
        setAll(level, defaultHeight, false);
        
        levelDeltas = new int[] {2, 2, 0};
    }
    
    /** Default constructor */
    public Limit()
    { this(null, null, null); }
    
    public String toString()
    {
        return "lim(" + getStart() + "->" + getEnd() + "," + getExpression() + ")";
    }

    /**
     * Retrieve the mathematical start state of this limit. E.g. <tt>x</tt>.
     * @return A mathematical expression indicating the start state.
     * @see #getEnd()
     */
    public Expression getStart()
    {
        return getChild(0);
    }

    /**
     * Retrieve the mathematical end state of this limit. E.g. <tt>34</tt>.
     * @return A mathematical expression indicating the end state.
     * @see #getStart()
     */
    public Expression getEnd()
    {
        return getChild(1);
    }

    /**
     * Retrieve the mathematical expression the limit manipulates upon.
     * @return A mathematical expression.
     */
    public Expression getExpression()
    {
        return getChild(2);
    }
    
    /**
     * Returns the sizes of the bounding of the children.
     * 
     * @param maxWidth
     *        The maximum width the {@link MathObject} can have (can be {@link MathObject#NO_MAXIMUM})
     * @param maxHeight
     *        The maximum height the {@link MathObject} can have (can be {@link MathObject#NO_MAXIMUM})
     * @return The size of the child bounding boxes
     */
    public Rect[] getChildrenSize()
    {
        // Get the sizes both operands want to take
        Rect leftSize = getChild(0).getBoundingBox();
        Rect rightSize = getChild(1).getBoundingBox();
        Rect Base = getChild(2).getBoundingBox();
        
        // Return the Sizes
        return new Rect[] {leftSize, rightSize, Base};
    }
    
    
    /**
     * Assign a mathematical expression indicating the start state of this limit.
     * @param start The start state.
     */
    public void setStart(Expression start)
    {
        setChild(0, start);
    }
    
    /**
     * Assign a mathematical expression indicating the end state of this limit.
     * @param end The end state.
     */
    public void setEnd(Expression end)
    {
        if (end != null)
        {
            if (!(end instanceof Symbol))
            {
                throw new IllegalArgumentException("'end' should be null or a symbolic constant");
            }
            Symbol sym = (Symbol) end;
            if (sym.getVarCount() > 1)
            {
                throw new IllegalArgumentException("multiple variables not allowed for 'over'");
            }
        }
        setChild(1, end);
    }
    
    //Complete bounding box
    @Override
    public Rect getBoundingBox()
    {
        Rect[] operatorSizes = getOperatorBoundingBoxes();
        Rect[] child = this.getChildrenSize();
        
        return new Rect(Math.min(operatorSizes[0].left, getChildBoundingBox(0).left),Math.min(operatorSizes[0].top, child[2].top), operatorSizes[0].width() + operatorSizes[1].width() + operatorSizes[2].width() + child[2].width(),Math.max(operatorSizes[0].bottom + child[1].bottom, child[2].bottom));
    }

    
    /**
     * Assign a mathematical expression that this limit manipulates.
     * @param expr A mathematical expression.
     */
    public void setExpression(Expression expr)
    {
        setChild(2, expr);
    }

    @Override
    protected String getType()
    {
        return TYPE;
    }

    @Override
    protected void writeChildrenToXML(Document doc, Element el)
    {
        getStart().writeToXML(doc, el);
        getEnd().writeToXML(doc, el);
        getExpression().writeToXML(doc, el);
    }
    /** Calculates the right text size for the given level
     * @return The right text size for the given level */
    protected float findTextSize()
    {
        return defaultHeight * (float) Math.pow(2.0 / 3.0, level + 1);
    }   
    
    
    /** Calculates the size of this function when using the given font size
     * @param fontSize The font size
     * @return The size of this {@link MathConstant}
     */
    protected Rect getSize(float fontSize)
    {
        // Set the text size
        operatorPaint.setTextSize(fontSize);

        // Calculate the total width and the height of the text
        Rect out = new Rect(0, 0, 0, 0);
        operatorPaint.getTextBounds(this.name, 0, this.name.length(), out);
        out.offsetTo(0, 0);
        
        // Return the size
        return out;
    }
    @Override
    public Rect[] calculateOperatorBoundingBoxes()
    {
    	  // Get the sizes
        final Rect[] child = getChildrenSize();
        final int parentheseWidth = (int)(child[1].height() * PARENTHESES_RATIO);
        Rect textBounding = getSize(findTextSize());
        final int arrowWidth = textBounding.width()/4;
        
        // Make sure everything is aligned nicely
        final int childCenterY = getChild(2).getCenter().y;
        final int childTop = Math.max(textBounding.centerY() - childCenterY, 0);
        textBounding.offsetTo(0,this.getChild(2).getCenter().y - textBounding.centerY());
        
        // Return the bounding boxes
        return new Rect[]{ textBounding,
                 new Rect(textBounding.width(), childTop, textBounding.width() + parentheseWidth, childTop + child[2].height()), 
                 new Rect(textBounding.width() + parentheseWidth +  child[2].width(), childTop, textBounding.width() + child[2].width() + 2 * parentheseWidth, childTop + child[2].height()),
                 new Rect(textBounding.centerX() - arrowWidth, textBounding.bottom,textBounding.centerX() + arrowWidth, child[0].height()),};
    }

    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException
    {
    	// Make sure the child index is valid
        checkChildIndex(index);

        // Get the sizes
        Rect[] operatorSize = getOperatorBoundingBoxes();
        Rect leftChild = getChild(0).getBoundingBox();
        Rect rightChild = getChild(1).getBoundingBox();
        Rect mainChild = getChild(2).getBoundingBox();
        
        // Translate and return the operand's bounding box
        if(index == 0)
        {
            leftChild.offsetTo(operatorSize[0].centerX() - operatorSize[3].width()/2 - leftChild.width(),operatorSize[0].bottom);
            return leftChild;
        }
        else if(index == 1)
        {
            rightChild.offsetTo(operatorSize[0].centerX() + operatorSize[3].width()/2, operatorSize[0].bottom);
            return rightChild;
        }
        else 
        {
        	mainChild.offsetTo(operatorSize[0].width() + operatorSize[2].width(), 0);
        	return mainChild;
        }
    }
    
    @Override
    public void calculateAllChildBoundingBox()
    {
        // Get the sizes
        Rect[] operatorSize = getOperatorBoundingBoxes();
        Rect leftChild = getChild(0).getBoundingBox();
        Rect rightChild = getChild(1).getBoundingBox();
        Rect mainChild = getChild(2).getBoundingBox();
        
        // Translate and return the operand's bounding box
        leftChild.offsetTo(operatorSize[0].centerX() - operatorSize[3].width()/2 - leftChild.width(),operatorSize[0].bottom);
        rightChild.offsetTo(operatorSize[0].centerX() + operatorSize[3].width()/2, operatorSize[0].bottom);
        mainChild.offsetTo(operatorSize[0].width() + operatorSize[2].width(), 0);
        
        // Add the bounding boxes
        childrenBoundingBoxes.add( leftChild);
        childrenBoundingBoxes.add( rightChild);
        childrenBoundingBoxes.add( mainChild);
    }

    @Override
    public void draw(Canvas canvas)
    {
    	 // Draw the bounding boxes 
        drawBoundingBoxes(canvas);
        
        // Set the right values for the paint
        operatorPaint.setColor(getColor());
        operatorPaint.setTextSize(findTextSize());
        
        // Get our operator bounding boxes
        Rect[] operatorBounding = this.getOperatorBoundingBoxes();
        
        //Draws the operator
        canvas.save();
        Rect textBounding = new Rect();
        operatorPaint.getTextBounds(name, 0, name.length(), textBounding);
        canvas.translate((operatorBounding[0].width() - textBounding.width()) / 2, (operatorBounding[0].height() - textBounding.height()) / 2);
        canvas.drawText(name, operatorBounding[0].left - textBounding.left, operatorBounding[0].top - textBounding.top, operatorPaint);
        canvas.drawLine(operatorBounding[3].left, operatorBounding[3].bottom - operatorBounding[3].height()/2, operatorBounding[3].right, operatorBounding[3].bottom - operatorBounding[3].height()/2, operatorPaint);
        canvas.restore();
        

        // Use stroke style for the parentheses
        operatorPaint.setStyle(Paint.Style.STROKE);
        
        // Draw the left bracket
        canvas.save();
        canvas.clipRect(operatorBounding[1], Region.Op.INTERSECT);
        RectF bracket = new RectF(operatorBounding[1]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(bracket.width() / 4, 0);
        canvas.drawArc(bracket, 100.0f, 160.0f, false, operatorPaint);
        canvas.restore();
        
        // Draw the right bracket
        canvas.save();
        canvas.clipRect(operatorBounding[2], Region.Op.INTERSECT);
        bracket = new RectF(operatorBounding[2]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(-bracket.width() / 4, 0);
        canvas.drawArc(bracket, -80.0f, 160.0f, false, operatorPaint);
        canvas.restore();

        // Set the paint back to fill style
        operatorPaint.setStyle(Paint.Style.FILL);
        
        // Draw the children
        drawChildren(canvas);
    }
} public class Negate extends Operation
{
    /** The type of the XML element for this class */
    public static final String TYPE = "negate";
    
    /** The paint that's used to draw the operator */
    private Paint paint = new Paint();
    
    /** Default constructor */
    public Negate()
    {
        super(1);
        children.add(new Empty());
        
        initPaint();
    }
    
    /** Constructor
     * @param child The child of this negate operation */
    public Negate(Expression child)
    {
        this();
        setChild(0, child);
    }
    
    /** Initialises the paint */
    private void initPaint()
    {
        paint.setTypeface(TypefaceHolder.dejavuSans);
    }

    @Override
    public String toString()
    { return "(-" + getChild(0).toString() + ")"; }

    @Override
    protected String getType()
    { return TYPE; }

    @Override
    protected void writeChildrenToXML(Document doc, Element el)
    { getChild(0).writeToXML(doc, el); }
    
    /** Returns the text size for the current level
     * @return The text size */
    private float getTextSize()
    { return defaultHeight * (float) Math.pow(2.0 / 3.0, level); }
    
    @Override
    public int getPrecedence()
    { return Precedence.NEGATE; }

    @Override
    public Rect[] calculateOperatorBoundingBoxes()
    {
        // Get the child centre
        final Point childCenter = getChild(0).getCenter();
        
        // Determine the size of our operator bounding box
        Rect out = new Rect();
        paint.setTextSize(getTextSize());
        paint.getTextBounds("-", 0, 1, out);
        
        // Add some padding
        out.inset((int) (-2 * lineWidth), 0);
        
        // Position the operator bounding box and return it
        out.offsetTo(0, Math.max(0, childCenter.y - out.height() / 2));
        return new Rect[]{ out };
    }

    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException
    {
        // Make sure the child index is valid
        checkChildIndex(index);

        // Determine the size of our operator bounding box
        Rect operatorBounding = new Rect();
        paint.setTextSize(getTextSize());
        paint.getTextBounds("-", 0, 1, operatorBounding);
        
        // Add some padding
        operatorBounding.inset((int) (-2 * lineWidth), 0);
        
        // Get the size and centre of our child bounding box
        Rect out = getChild(0).getBoundingBox();
        final Point childCenter = getChild(0).getCenter();
        
        // Position the child bounding box and return it
        out.offsetTo(operatorBounding.width(), Math.max(0, operatorBounding.height() / 2 - childCenter.y));
        return out;
    }

    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the bounding box
        final Rect operator = getOperatorBoundingBoxes()[0];
        
        // Draw the operator
        paint.setColor(getColor());
        paint.setTextSize(getTextSize());
        Rect textBounds = new Rect();
        paint.getTextBounds("-", 0, 1, textBounds);
        canvas.drawText("-", operator.left - textBounds.left, operator.top - textBounds.top, paint);
        
        // Draw the children
        drawChildren(canvas);
    }
} public class Add extends Linear
{
	public static final String TYPE = "add";
	
    public Add()
    {}

    public Add(Expression left, Expression right)
    { 
    	super(left, right);
	}
    
    public String toString(){
        return "(" + getLeft().toString() + "+" + getRight().toString() + ")";
    }
    
    @Override
    public int getPrecedence()
    { return Precedence.ADD; }


    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the bounding box
        final Rect operator = getOperatorBoundingBoxes()[0];
        
        // Draw the operator
        operator.inset(operator.width() / 10, operator.height() / 10);      // Padding
        canvas.save();
        canvas.translate(operator.left, operator.top);
        operatorPaint.setStrokeWidth(lineWidth);
        operatorPaint.setColor(this.getColor());
        canvas.drawLine(0, operator.height() / 2, operator.width(), operator.height() / 2, operatorPaint);
        canvas.drawLine(operator.width() / 2, 0, operator.width() / 2, operator.height(), operatorPaint);
        canvas.restore();
        
        // Draw the children
        drawChildren(canvas);
    }

    @Override
    protected String getType()
    {
        return TYPE;
    }
} public class Derivative extends Binary
{
    /** The paint that is used for drawing the operator */
    protected Paint operatorPaint = new Paint();
    final float RATIO = 0.5f / 1.61803398874989f;
    public static final String TYPE = "derivative";
    
    public Derivative()
    { initPaint(); }
    
    public Derivative(Expression left, Expression right)
    {
        super(left, right);
        initPaint();
    }
    
    private void initPaint()
    {
        operatorPaint.setAntiAlias(true);
        operatorPaint.setTypeface(TypefaceHolder.dejavuSans);
    }
    
    @Override
    public String toString()
    {
        return "derive(" + getLeft().toString() + "," + getRight().toString() + ")";
    }

    @Override
    public int getPrecedence()
    { return Precedence.MULTIPLY; }
    
    /**
     * Returns the sizes of the bounding boxes.
     * The first rectangle is the size of the operator, the second and third rectangle are the sizes of the children.
     * 
     * @param maxWidth
     *        The maximum width the {@link Expression} can have (can be {@link Expression#NO_MAXIMUM})
     * @param maxHeight
     *        The maximum height the {@link Expression} can have (can be {@link Expression#NO_MAXIMUM})
     * @return The size of the child bounding boxes
     */
    protected Rect[] getSizes()
    {    
        /* Index of what the sizes are:
         * 0: bounding box size of the breakline
         * 1: bounding box size of the top child
         * 2: bounding box size of the bottom child
         * 3: bounding box size of the top "d"
         * 4: bounding box size of the bottom "d"
         * 5: bounding box size of the top left bracket 
         * 6: bounding box size of the top right bracket
         */
        
        // Get the size both operands want to take
        Rect topSize = getChild(0).getBoundingBox();
        Rect bottomSize = getChild(1).getBoundingBox();
        
        // Calculate the bounding box of the "d" letters
        Rect boundsTop = new Rect();
        operatorPaint.setTextSize(defaultHeight * (float) Math.pow(2.0 / 3.0, level));
        operatorPaint.getTextBounds("d", 0, 1, boundsTop);
        Rect boundsBottom = new Rect(boundsTop);
        
        // Add a small amount of padding to the top "d" and place both of them at (0, 0)
        boundsTop.inset((int) (-2 * lineWidth), 0);
        boundsTop.offsetTo(0, 0);
        boundsBottom.offsetTo(0, 0);
        
        // Calculate the height the operator wants to take
        int operatorHeight = Math.max((topSize.height() + bottomSize.height()) / 15 , 5);
        
        // Return the bounding boxes
        final int bracketWidth = (int)(topSize.height() * RATIO);
        Rect leftBracket = new Rect(0, 0, bracketWidth, topSize.height());
        Rect rightBracket = new Rect(0, 0, bracketWidth, topSize.height());
        
        // If we have no maximum height or it isn't breached, we're done
            return new Rect[] 
                    {
                    new Rect(0, 0, Math.max(boundsBottom.width() + bottomSize.width(), topSize.width() + boundsTop.width() + leftBracket.width() + rightBracket.width()), operatorHeight),
                    topSize, 
                    bottomSize,
                    boundsTop,
                    boundsBottom,
                    leftBracket,
                    rightBracket
                    };
    }

    @Override
    public Rect[] calculateOperatorBoundingBoxes()
    {
        // Get the sizes
        Rect[] sizes = getSizes();

        // Position the bounding boxes and return them
        sizes[0].offsetTo(0, Math.max(sizes[1].height(), sizes[3].height()));
        sizes[3].offsetTo(Math.max(0, sizes[0].width() - sizes[1].width() - sizes[3].width() - sizes[5].width() - sizes[6].width()) / 2, Math.max(0, (sizes[1].height() - sizes[3].height()) / 2));
        sizes[4].offsetTo(Math.max(0, sizes[0].width() - sizes[2].width() - sizes[4].width()) / 2, sizes[0].bottom + Math.max(0, (sizes[2].height() - sizes[4].height()) / 2));
        
        // Make a rectangle the size of the brackets
        Rect leftBracket = new Rect( 0, 0, sizes[5].width(), sizes[5].height());
        Rect rightBracket = new Rect( 0, 0, sizes[6].width(), sizes[6].height());
        
        // Move them to the correct position
        leftBracket.offsetTo( sizes[3].width() + Math.max( 0, sizes[0].width() - sizes[3].width() - sizes[1].width() - rightBracket.width() - leftBracket.width()) / 2, Math.max(0, (sizes[3].height() - sizes[1].height()) / 2));
        rightBracket.offsetTo( sizes[3].width() + sizes[1].width() + leftBracket.width() + Math.max( 0, sizes[0].width() - sizes[3].width() - sizes[1].width() - rightBracket.width() - leftBracket.width()) / 2, Math.max(0, (sizes[3].height() - sizes[1].height()) / 2));
        
        return new Rect[] {sizes[0], sizes[3], sizes[4], leftBracket, rightBracket};
    }

    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException
    {
        // Make sure the child index is valid
        checkChildIndex(index);

        // Get the sizes and the total height
        Rect[] sizes = getSizes();
        final int ownCenterX = sizes[0].width() / 2;
        
        // Translate the operand's bounding box
        if(index == 0)
        {
            Point childCenter = getChild(0).getCenter();
            sizes[1].offsetTo(ownCenterX - childCenter.x + sizes[3].width() / 2, Math.max(0, (sizes[3].height() - sizes[1].height()) / 2));
        }
        else
        {
            Point childCenter = getChild(1).getCenter();
            sizes[2].offsetTo(ownCenterX - childCenter.x + sizes[4].width() / 2, Math.max(sizes[1].height(), sizes[3].height()) + sizes[0].height() + Math.max(0, sizes[4].height() - sizes[2].height()));
        }

        // Return the requested bounding box
        return sizes[index + 1];
    }
    
    @Override
    public void calculateAllChildBoundingBox()
    {
        // Get the sizes and the total height
        Rect[] sizes = getSizes();
        final int ownCenterX = sizes[0].width() / 2;
        
        Point childCenter = getChild(0).getCenter();
        sizes[1].offsetTo(ownCenterX - childCenter.x + sizes[3].width() / 2, Math.max(0, (sizes[3].height() - sizes[1].height()) / 2));
        childCenter = getChild(1).getCenter();
        sizes[2].offsetTo(ownCenterX - childCenter.x + sizes[4].width() / 2, Math.max(sizes[3].height(), sizes[1].height()) + sizes[0].height() + Math.max(0, (sizes[4].height() - sizes[2].height()) / 2));

        // Add the bounding boxes
        childrenBoundingBoxes.add( sizes[1]);
        childrenBoundingBoxes.add( sizes[2]);
    }
    
    @Override
    public Rect calculateBoundingBox()
    {
        // Get the sizes
        Rect[] sizes = getSizes();
        
        // Return a bounding box, containing the bounding boxes of the children
        return new Rect(0, 0,
                sizes[0].width(),
                sizes[0].height() + Math.max(sizes[1].height(), sizes[3].height()) + Math.max(sizes[2].height(), sizes[4].height()));
    }
    
    @Override
    public Point calculateCenter()
    {
        // Get the operator bounding box
        Rect operatorBounding = getOperatorBoundingBoxes()[0];
        
        // Return the centre, which is the centre of the operator
        return new Point(operatorBounding.centerX(), operatorBounding.centerY());
    }

    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the operator bounding boxes
        final Rect[] operatorBoxes = getOperatorBoundingBoxes();
        
        // Draw the operator
        operatorPaint.setStyle(Paint.Style.FILL);
        operatorPaint.setColor(getColor());
        operatorPaint.setStrokeWidth(lineWidth);
        canvas.drawLine(operatorBoxes[0].left, operatorBoxes[0].centerY(), operatorBoxes[0].right, operatorBoxes[0].centerY(), operatorPaint);
        
        // Draw the text at the correct position
        Rect dBounds = new Rect();
        operatorPaint.setTextSize(defaultHeight * (float) Math.pow(2.0 / 3.0, level));
        operatorPaint.getTextBounds("d", 0, 1, dBounds);
        canvas.drawText("d", operatorBoxes[1].left - dBounds.left, operatorBoxes[1].top - dBounds.top, operatorPaint);
        canvas.drawText("d", operatorBoxes[2].left - dBounds.left, operatorBoxes[2].top - dBounds.top, operatorPaint);

        
        // Draw the brackets
        operatorPaint.setStyle(Paint.Style.STROKE);
        
        // Draw the left bracket
        canvas.save();
        canvas.clipRect(operatorBoxes[3], Region.Op.INTERSECT);
        RectF bracket = new RectF(operatorBoxes[3]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(bracket.width() / 4, 0);
        canvas.drawArc(bracket, 100.0f, 160.0f, false, operatorPaint);
        canvas.restore();
        
        // Draw the right bracket
        canvas.save();
        canvas.clipRect(operatorBoxes[4], Region.Op.INTERSECT);
        bracket = new RectF(operatorBoxes[4]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(-bracket.width() / 4, 0);
        canvas.drawArc(bracket, -80.0f, 160.0f, false, operatorPaint);
        canvas.restore();
        
        // Draw the children
        drawChildren(canvas);
    }

    @Override
    protected String getType() 
    {
        return TYPE;
    }
} public class Divide extends Binary
{
	public static final String TYPE = "divide";
	
    /** The paint that is used for drawing the operator */
    protected Paint operatorPaint = new Paint();

    public Divide()
    { this(null, null); }
    
    public Divide(Expression left, Expression right)
    {
    	super(left, right);
        
        levelDeltas = new int[] {1, 1};
    }
    
    public String toString()
    {
        return "(" + getLeft().toString() + "/" + getRight().toString() + ")";
    }

    @Override
    public int getPrecedence()
    { return Precedence.MULTIPLY; }
    
    /**
     * Returns the sizes of the bounding boxes.
     * The first rectangle is the size of the operator, the second and third rectangle are the sizes of the children.
     * 
     * @param maxWidth
     *        The maximum width the {@link Expression} can have (can be {@link Expression#NO_MAXIMUM})
     * @param maxHeight
     *        The maximum height the {@link Expression} can have (can be {@link Expression#NO_MAXIMUM})
     * @return The size of the child bounding boxes
     */
    protected Rect[] getSizes()
    {
        // Get the size both operands want to take
        Rect topSize = getChild(0).getBoundingBox();
        Rect bottomSize = getChild(1).getBoundingBox();
        
        // Calculate the height the operator wants to take
        int operatorHeight = Math.max((topSize.height() + bottomSize.height()) / 15 , 5);

        // If we have no maximum height or it isn't breached, we're done
            return new Rect[] 
            		{
        			new Rect(0, 0, Math.max(topSize.width(), bottomSize.width()), operatorHeight),
        			topSize, 
        			bottomSize
        			};
    }

    @Override
    public Rect[] calculateOperatorBoundingBoxes()
    {
        // Get the sizes
        Rect[] sizes = getSizes();

        // Position the bounding box and return it
        sizes[0].offsetTo(0, sizes[1].height());
        return new Rect[] {sizes[0]};
    }

    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException
    {
        // Make sure the child index is valid
        checkChildIndex(index);

        // Get the sizes and the total height
        Rect[] sizes = getSizes();
        Point center_one = getChild(0).getCenter();
        Point center_two = getChild(1).getCenter();
        Point center_this = this.getCenter();
        
        // Translate the operand's bounding box
        if(index == 0)
            sizes[1].offsetTo(center_this.x - center_one.x, 0);
        else
            sizes[2].offsetTo(center_this.x - center_two.x, sizes[0].height() + sizes[1].height());

        // Return the requested bounding box
        return sizes[index + 1];
    }
    
    @Override
    public void calculateAllChildBoundingBox()
    {
        // Get the sizes and the total height
        Rect[] sizes = getSizes();
        Point center_one = getChild(0).getCenter();
        Point center_two = getChild(1).getCenter();
        Point center_this = this.getCenter();
        
        // Translate the operand's bounding box
        sizes[1].offsetTo(center_this.x - center_one.x, 0);
        sizes[2].offsetTo(center_this.x - center_two.x, sizes[0].height() + sizes[1].height());

        // Add the bounding boxes
        childrenBoundingBoxes.add( sizes[1]);
        childrenBoundingBoxes.add( sizes[2]);
    }
    
    @Override
    public Rect calculateBoundingBox()
    {
        // Get the sizes
        Rect[] sizes = getSizes();
        
        // Return a bounding box, containing the bounding boxes of the children
       
        int width = Math.max(sizes[1].width(), sizes[2].width());
        int height = sizes[0].height() + sizes[1].height() + sizes[2].height();

        return new Rect(0, 0, width, height);
    }
    
    /**
     * Retrieve the dividend (i.e. the numerator)
     * 
     * @return The numerator
     */
    public Expression getNumerator()
    {
        return getLeft();
    }

    /**
     * Assign a new mathematical expression to the numerator.
     * 
     * @param num
     *        The new numerator
     */
    public void setNumerator(Expression num)
    {
        setLeft(num);
    }

    /**
     * Retrieve the divisor (i.e. the denominator)
     * 
     * @return The denominator
     */
    public Expression getDenominator()
    {
        return getRight();
    }

    /**
     * Assign a new mathematical expression to the denominator.
     * 
     * @param denom
     *        The new denominator
     */
    public void setDenominator(Expression denom)
    {
        setRight(denom);
    }
    
    @Override
    public Point calculateCenter()
    {
        // Get the operator bounding box
        Rect operatorBounding = getOperatorBoundingBoxes()[0];
        
        // Return the center, which is the center of the operator
        return new Point(operatorBounding.centerX(), operatorBounding.centerY());
    }

    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the bounding boxes
        final Rect operator = getOperatorBoundingBoxes()[0];
        
        // Draw the operator
        operatorPaint.setColor(getColor());
        operatorPaint.setStrokeWidth(lineWidth);
        canvas.drawLine(operator.left, operator.centerY(), operator.right, operator.centerY(), operatorPaint);

        // Draw the children
        drawChildren(canvas);
    }

    @Override
    protected String getType()
    {
        return TYPE;
    }
} public class Log extends Binary
{
    /** the Type of the operation */
	public final static String TYPE = "log";
	
    /** The name of the function type */
    private String name;
    
    /** The xml-safe name of the function type */
    private String xmlName;

    /** Returns the name of the function type
     * @return The name of the function type as a string (may contain high unicode characters) */
    public String getName()
    { return name; }

    /** Returns the XML safe name of the function type
     * @return The XML safe name of the function type as a string */
    public String getXmlName()
    { return xmlName; }
    
    /** The paint that is used for drawing the operator */
    protected Paint operatorPaint = new Paint();
    
    /** The ratio (width : height) of a bracket (i.e. half the golden ratio) */
    private final float PARENTHESES_RATIO = 0.5f / 1.61803398874989f;
    
    /** Default constructor */
    public Log()
    { this(null, null); }

    /** Constructor */
    public Log(Expression base, Expression parameter)
    {
        super(base, parameter);
        this.name = "log";
        
        levelDeltas = new int[] {2, 0};
        
        initPaint();
    }
    
    /** Initialises the paint */
    private void initPaint()
    {
        operatorPaint.setTypeface(TypefaceHolder.dejavuSans);
        operatorPaint.setAntiAlias(true);
    }
    
    @Override
    public String toString()
    {
        String baseString = getChild(0).toString();
        if(baseString.startsWith("(") && baseString.endsWith(")"))
            baseString = baseString.substring(1, baseString.length() - 1);
        
        String argString = getChild(0).toString();
        if(argString.startsWith("(") && argString.endsWith(")"))
            argString = argString.substring(1, argString.length() - 1);
        
        return "log(" + baseString + ',' + argString + ')';
    }
    
    public int getPrecedence()
    { return Precedence.FUNCTION; }

    /** Calculates the right text size for the given level
     * @return The right text size for the given level */
    protected float findTextSize()
    {
        return defaultHeight * (float) Math.pow(2.0 / 3.0, level + 1);
    }   
    
    
    /** Calculates the size of this function when using the given font size
     * @param fontSize The font size
     * @return The size of this {@link MathConstant}
     */
    protected Rect getSize(float fontSize)
    {
        // Set the text size
        operatorPaint.setTextSize(fontSize);

        // Calculate the total width and the height of the text
        Rect out = new Rect(0, 0, 0, 0);
        operatorPaint.getTextBounds(this.name, 0, this.name.length(), out);
        out.offsetTo(0, 0);
        
        // Return the size
        return out;
    }

    
    @Override
    public Rect[] calculateOperatorBoundingBoxes() 
    {
        // Get the sizes
        final Rect[] child = getChildrenSize();
        final int parentheseWidth = (int)(child[1].height() * PARENTHESES_RATIO);
        Rect textBounding = getSize(findTextSize());
        
        // Make sure everything is aligned nicely
        final int childCenterY = getChild(1).getCenter().y;
        final int childTop = Math.max(textBounding.centerY() - childCenterY, 0);
        textBounding.offsetTo(0, Math.max(childCenterY - textBounding.centerY(), 0));
        
        // Return the bounding boxes
        return new Rect[]{ textBounding,
                 new Rect(textBounding.width() + child[0].width(), childTop, textBounding.width() + child[0].width() + parentheseWidth, childTop + child[1].height()), 
                 new Rect(textBounding.width() + parentheseWidth + child[0].width() + child[1].width(), childTop, textBounding.width() + child[0].width() + child[1].width() + 2 * parentheseWidth, childTop + child[1].height())};
    }
    
    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException 
    {
    	// Make sure the child index is valid
        checkChildIndex(index);

        // Get the sizes
        Rect[] operatorSize = getOperatorBoundingBoxes();
        Rect leftChild = getChild(0).getBoundingBox();
        Rect rightChild = getChild(1).getBoundingBox();
        
        // Translate and return the operand's bounding box
        if(index == 0)
        {
            leftChild.offsetTo(operatorSize[0].width(), rightChild.height() - leftChild.height()/3);
            return leftChild;
        }
        else
        {
            rightChild.offsetTo(operatorSize[0].width() + operatorSize[1].width() + leftChild.width(), 0);
            return rightChild;
        }
    }
    
    @Override
    public void calculateAllChildBoundingBox()
    {
        // Get the sizes
        Rect[] operatorSize = getOperatorBoundingBoxes();
        Rect leftChild = getChild(0).getBoundingBox();
        Rect rightChild = getChild(1).getBoundingBox();
        
        // Translate and return the operand's bounding box
        leftChild.offsetTo(operatorSize[0].width(), rightChild.height() - leftChild.height()/3);
        rightChild.offsetTo(operatorSize[0].width() + operatorSize[1].width() + leftChild.width(), 0);
        
        // Add the bounding boxes
        childrenBoundingBoxes.add( leftChild);
        childrenBoundingBoxes.add( rightChild);
    }
    
    //Complete bounding box
    @Override
    public Rect calculateBoundingBox()
    {
        Rect[] operatorSizes = getOperatorBoundingBoxes();
        Rect[] child = this.getChildrenSize();
        
        return new Rect(0,Math.min(operatorSizes[0].top, child[1].top), operatorSizes[0].width() + operatorSizes[1].width() + operatorSizes[2].width() + child[0].width() + child[1].width(), child[0].bottom + child[1].bottom- child[0].height()/3);
    }

    
    @Override
    public Point calculateCenter()
    {        
        return new Point(this.getBoundingBox().centerX(), getChild(1).getCenter().y);
    }
    
    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes 
        drawBoundingBoxes(canvas);
        
        // Set the right values for the paint
        operatorPaint.setColor(getColor());
        operatorPaint.setTextSize(findTextSize());
        
        // Get our operator bounding boxes
        Rect[] operatorBounding = this.getOperatorBoundingBoxes();
        
        //Draws the operator
        canvas.save();
        Rect textBounding = new Rect();
        operatorPaint.getTextBounds(this.name, 0, this.name.length(), textBounding);
        canvas.translate((operatorBounding[0].width() - textBounding.width()) / 2, (operatorBounding[0].height() - textBounding.height()) / 2);
        canvas.drawText(name, operatorBounding[0].left - textBounding.left, operatorBounding[0].top - textBounding.top, operatorPaint);
        canvas.restore();
        

        // Use stroke style for the parentheses
        operatorPaint.setStyle(Paint.Style.STROKE);
        operatorPaint.setStrokeWidth(lineWidth);
        
        // Draw the left bracket
        canvas.save();
        canvas.clipRect(operatorBounding[1], Region.Op.INTERSECT);
        RectF bracket = new RectF(operatorBounding[1]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(bracket.width() / 4, 0);
        canvas.drawArc(bracket, 100.0f, 160.0f, false, operatorPaint);
        canvas.restore();
        
        // Draw the right bracket
        canvas.save();
        canvas.clipRect(operatorBounding[2], Region.Op.INTERSECT);
        bracket = new RectF(operatorBounding[2]);
        bracket.inset(0, -operatorPaint.getStrokeWidth());
        bracket.offset(-bracket.width() / 4, 0);
        canvas.drawArc(bracket, -80.0f, 160.0f, false, operatorPaint);
        canvas.restore();

        // Set the paint back to fill style
        operatorPaint.setStyle(Paint.Style.FILL);
        
        // Draw the children
        drawChildren(canvas);
    }
    
    /** The name of the XML node for this class */
    public static final String NAME = "function";
    
    /** The XML attribute for which type of function this is */
    public static final String ATTR_TYPE = "type";

	@Override
	protected String getType() {return TYPE;}

    @Override
    public boolean isCompleted()
    {
        return getChild(1).isCompleted();
    }
} public class Multiply extends Linear
{
	public static final String TYPE = "multiply";
	
    public Multiply()
    {}
    
    public Multiply(Expression left, Expression right)
    { 
        super(left, right);
    }
    
    public String toString()
    {
        return "(" + getLeft().toString() + "*" + getRight().toString() + ")";
    }

    @Override
    public int getPrecedence()
    { return Precedence.MULTIPLY; }
    
    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the bounding box
        final Rect operator = getOperatorBoundingBoxes()[0];
        
        // Draw the operator
        operator.inset(operator.width() / 10, operator.height() / 10);      // Padding
        canvas.save();
        canvas.translate(operator.left, operator.top);
        operatorPaint.setStrokeWidth(lineWidth);
        operatorPaint.setColor(this.getColor());
        operatorPaint.setAntiAlias(true);
        canvas.drawCircle(operator.width()/2, operator.height()/2, operator.width()/10, operatorPaint);
        canvas.restore();
        
        // Draw the children
        drawChildren(canvas);
    }
    
    @Override
    protected String getType()
    {
        return TYPE;
    }
} public class Power extends Binary
{
    public static final String TYPE = "power";
    
    /** A paint that's used to draw the operator when the user is hovering over this object */
    private Paint operatorPaint = new Paint();
    
    public Power()
    { this(null, null); }
    
    public Power(Expression base, Expression power)
    {
        super(base, power);
        
        levelDeltas = new int[] {0, 1};
        
        // Initialise the paint
        operatorPaint.setColor(0xcc4444ff);
    }
    
    public String toString()
    {
        return "(" + getLeft().toString() + "^" + getRight().toString() + ")";
    }
    
    @Override
    public int getPrecedence()
    { return Precedence.POWER; }
    
    /**
     * Assign <tt>o</tt> to mathematical expression to base expression.
     * 
     * @param o
     *        The mathematical expression.
     */
    public void setBase(Expression o)
    {
        setLeft(o);
    }

    /**
     * Retrieve the base mathematical expression. <b>Note:</b> <tt>null</tt>
     * may be returned.
     * 
     * @return The base mathematical expression.
     */
    public Expression getBase()
    {
        return getLeft();
    }
    
    /**
     * Assign <tt>o</tt> to mathematical expression to exponent expression.
     * 
     * @param o
     *        The mathematical expression.
     */
    public void setExponent(Expression o)
    {
        setRight(o);
    }

    /**
     * Retrieve the exponent mathematical expression. <b>Note:</b> <tt>null</tt>
     * may be returned.
     * 
     * @return The exponent mathematical expression.
     */
    public Expression getExponent()
    {
        return getRight();
    }

    @Override
    public Rect[] calculateOperatorBoundingBoxes() 
    {
        // Get the children sizes
        Rect[] sizes = getChildrenSize();
        
        // Powers don't have a visible operator
        // However, they need an operator bounding box (for dropping other operations on them)
        return new Rect[] {
                new Rect(0, 0, sizes[0].width(), sizes[1].height()),
                new Rect(sizes[0].width(), sizes[1].height(), sizes[0].width() + sizes[1].width(), sizes[0].height() + sizes[1].height())
            };
    }

    /**
     * Returns the sizes of the bounding of the children.
     * 
     * @param maxWidth
     *        The maximum width the {@link Expression} can have (can be {@link Expression#NO_MAXIMUM})
     * @param maxHeight
     *        The maximum height the {@link Expression} can have (can be {@link Expression#NO_MAXIMUM})
     * @return The size of the child bounding boxes
     */
    public Rect[] getChildrenSize()
    {
        // Get the sizes both operands want to take
        Rect leftSize = getChild(0).getBoundingBox();
        Rect rightSize = getChild(1).getBoundingBox();
        
        // Return the Sizes
        return new Rect[] {leftSize, rightSize};
    }

    @Override
    public Rect calculateBoundingBox()
    {
        // Get the sizes
        Rect[] sizes = getChildrenSize();
        
        // Return a bounding box, containing the bounding boxes of the children
        return new Rect(0, 0, sizes[0].width() + sizes[1].width(), sizes[0].height() + sizes[1].height());
    }
    
    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException 
    {
        // Check if the child exists
        this.checkChildIndex(index);
        
        // Get the Size of the children
        Rect[] childrenSize = getChildrenSize();
        
        // Move the bounding boxes to the correct position
        childrenSize[0].offsetTo(0, childrenSize[1].height());
        childrenSize[1].offsetTo(childrenSize[0].width(), 0);
        
        // Return the right bounding box
        return childrenSize[index];
    }
    
    @Override
    public void calculateAllChildBoundingBox()
    {        
        // Get the Size of the children
        Rect[] childrenSize = getChildrenSize();
        
        // Move the bounding boxes to the correct position
        childrenSize[0].offsetTo(0, childrenSize[1].height());
        childrenSize[1].offsetTo(childrenSize[0].width(), 0);
        
        // Return the right bounding box
        childrenBoundingBoxes.add( childrenSize[0]);
        childrenBoundingBoxes.add( childrenSize[1]);
    }
    
    //We regard the base operand as the vertical center of the mathObject
    @Override
    public Point calculateCenter()
    {
        // Get the Size of the children
        Rect[] childrenSize = getChildrenSize();
        
        // Return the centre, that is:
        // Horizontally: simply the centre of our total width
        // Vertically: the vertical centre of the base operand
        return new Point((childrenSize[0].width() + childrenSize[1].width()) / 2, childrenSize[1].height() + getBase().getCenter().y);
    }

    @Override
    public void draw(Canvas canvas) 
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Draw the operator if we're hovering
        if(state == HoverState.HOVER)
        {
            final Rect[] boxes = getOperatorBoundingBoxes();
            for(Rect box : boxes)
                canvas.drawRect(box, operatorPaint);
        }
        
        // Only draw the children
        drawChildren(canvas);
    }
    
    @Override
    protected String getType()
    {
        return TYPE;
    }
} public class Root extends Binary
{
	public static final String TYPE = "root";
    protected Paint operatorPaint = new Paint();
    
    public Root()
    { this(null, null); }

    public Root(Expression base, Expression exponent)
    {
        super(exponent, base);
        
        levelDeltas = new int[] {1, 0};

        // Initialise the paint
        operatorPaint.setAntiAlias(true);
        operatorPaint.setStyle(Paint.Style.STROKE);
    }
    
    /**
     * Assign <tt>o</tt> to mathematical expression to base expression.
     * 
     * @param o
     *        The mathematical expression.
     */
    public void setBase(Expression o)
    {
        setChild(1, o);
    }

    /**
     * Retrieve the base mathematical expression. <b>Note:</b> <tt>null</tt>
     * may be returned.
     * 
     * @return The base mathematical expression.
     */
    public Expression getBase()
    { return getChild(1); }

    @Override
    public String toString()
    {
        return "(" + getBase().toString() + "^ (1/" + getExponent().toString() + "))";
    }
    
    /**
     * Assign <tt>o</tt> to mathematical expression to exponent expression.
     * 
     * @param o
     *        The mathematical expression.
     */
    public void setExponent(Expression o)
    {
        setChild(0, o);
    }

    /**
     * Retrieve the exponent mathematical expression. <b>Note:</b> <tt>null</tt>
     * may be returned.
     * 
     * @return The exponent mathematical expression.
     */
    public Expression getExponent()
    {
        return getChild(0);
    }

    @Override
    public Rect[] calculateOperatorBoundingBoxes() 
    {
        // Get the bounding boxes (not the sizes) of the children
        Rect exponentBounding = getChildBoundingBox(0);
        Rect baseBounding = getChildBoundingBox(1);
        
        // The size of the gap
        final int gapSize = (int) (3 * Expression.lineWidth);
        
        // We'll need 3 bounding boxes to contain the operator
        return new Rect[] {
                new Rect(exponentBounding.left, exponentBounding.bottom, baseBounding.left, baseBounding.bottom),
                new Rect(exponentBounding.right, baseBounding.top - gapSize, baseBounding.left, exponentBounding.bottom),
                new Rect(baseBounding.left, baseBounding.top - gapSize, baseBounding.right, baseBounding.top)
            };
    }

    @Override
    public Rect calculateBoundingBox()
    {
        // Get the bounding box (not the size) of the base
        Rect baseBounding = getChildBoundingBox(1);
        
        // Return a bounding box, containing the bounding boxes of the children
        return new Rect(0, 0, baseBounding.right, baseBounding.bottom);
    }
    
    @Override
    public Rect calculateChildBoundingBox(int index) throws IndexOutOfBoundsException 
    {
        // Check if the child exists
        checkChildIndex(index);
        
        // The size of the gap
        final int gapSize = (int) (3 * Expression.lineWidth);
        
        // We'll always need the y-coordinate of the centre of the base
        final int centerY = getChild(1).getCenter().y;
        
        // We'll always need the bounding box of the exponent
        Rect exponentBounding = getChild(0).getBoundingBox();
        if(exponentBounding.bottom - gapSize / 2 < centerY)
            exponentBounding.offset(0, centerY - (exponentBounding.bottom - gapSize / 2));
        
        // If we're calculating the bounding box of the exponent, we're done
        if(index == 0)
            return exponentBounding;
        
        // We want the bounding box of the base, so we'll need its size
        Rect baseBounding = getChild(1).getBoundingBox();
        
        // Position the bounding box
        baseBounding.offsetTo(exponentBounding.right + 2 * gapSize, Math.max(0, exponentBounding.bottom + gapSize / 2 - centerY));
        
        // Return the bounding box
        return baseBounding;
    }
    
    @Override
    public void calculateAllChildBoundingBox()
    {        
        // The size of the gap
        final int gapSize = (int) (3 * Expression.lineWidth);
        
        // We'll always need the y-coordinate of the centre of the base
        final int centerY = getChild(1).getCenter().y;
        
        // We'll always need the bounding box of the exponent
        Rect exponentBounding = getChild(0).getBoundingBox();
        if(exponentBounding.bottom - gapSize / 2 < centerY)
            exponentBounding.offset(0, centerY - (exponentBounding.bottom - gapSize / 2));
        
        // add the exponent bounding box
        childrenBoundingBoxes.add( exponentBounding);
        
        // We want the bounding box of the base, so we'll need its size
        Rect baseBounding = getChild(1).getBoundingBox();
        
        // Position the bounding box
        baseBounding.offsetTo(exponentBounding.right + 2 * gapSize, Math.max(0, exponentBounding.bottom + gapSize / 2 - centerY));
        
        // Add the base bounding box
        childrenBoundingBoxes.add( baseBounding);
    }
    
    @Override
    public Point calculateCenter()
    {
        // The size of the gap
        final int gapSize = (int) (3 * Expression.lineWidth);
        
        // The bounding box of the exponent
        Rect exponentBounding = getChildBoundingBox(0);
        
        // We regard the vertical centre of the base operand as the vertical centre of the root
        // The centre of the base operand is the same as the bottom of the exponent operand + gapSize / 2
    	return new Point((exponentBounding.width() + 2 * gapSize + getChild(1).getBoundingBox().width()) / 2, exponentBounding.bottom + gapSize / 2);
    }

    @Override
    public void draw(Canvas canvas) 
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);

        // Get the bounding boxes (not the sizes) of the children
        Rect exponentBounding = getChildBoundingBox(0);
        Rect baseBounding = getChildBoundingBox(1);

        // The size of the gap and the centre y-coordinate
        final int gapSize = (int) (3 * Expression.lineWidth);
        final int centerY = getCenter().y;
        
        // Create a path to draw the operator
        Path path = new Path();
        path.moveTo(exponentBounding.left, centerY);
        path.lineTo(baseBounding.left - 2 * gapSize, centerY);
        path.lineTo(baseBounding.left - gapSize / 2, baseBounding.bottom - Expression.lineWidth / 2);
        path.lineTo(baseBounding.left - gapSize / 2, baseBounding.top - gapSize / 2);
        path.lineTo(baseBounding.right, baseBounding.top - gapSize / 2);
        
        // Draw the operator
        canvas.save();
        operatorPaint.setColor(getColor());
        operatorPaint.setStrokeWidth(lineWidth);
        canvas.drawPath(path, operatorPaint);
        canvas.restore();
        
        // Draw the children
        drawChildren(canvas);
    }
    
    @Override
    protected String getType()
    {
        return TYPE;
    }
    
    @Override
    public boolean isCompleted()
    {
        return getBase().isCompleted();
    }
} public class Subtract extends Linear
{
	public static final String TYPE = "subtract";
	
    public Subtract()
    {}

    public Subtract(Expression left, Expression right)
    { 
        super(left, right);
    }
    
    @Override
    public int getPrecedence()
    { return Precedence.ADD; }
    
    @Override
    public String toString()
    { return "(" + getLeft().toString() + "-" + getRight().toString() + ")"; }
    
    @Override
    public void draw(Canvas canvas)
    {
        // Draw the bounding boxes
        drawBoundingBoxes(canvas);
        
        // Get the bounding box
        final Rect operator = getOperatorBoundingBoxes()[0];
        
        // Draw the operator
        operator.inset(operator.width() / 10, operator.height() / 10);      // Padding
        canvas.save();
        operatorPaint.setStrokeWidth(lineWidth);
        operatorPaint.setColor(getColor());
        canvas.drawLine(operator.left, operator.centerY(), operator.right, operator.centerY(), operatorPaint);
        canvas.restore();
        
        // Draw the children
        drawChildren(canvas);
    }
    
    @Override
    protected String getType()
    {
        return TYPE;
    }
}
import org.matheclipse.core.expression.F;
import org.matheclipse.core.expression.FractionSym;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.ISymbol;
import org.teaminfty.math_dragon.exceptions.EmptyChildException;
import org.teaminfty.math_dragon.exceptions.MathException;
import org.teaminfty.math_dragon.exceptions.ParseException;
import org.teaminfty.math_dragon.view.math.Empty;
import org.teaminfty.math_dragon.view.math.Expression;
import org.teaminfty.math_dragon.view.math.Function;
import org.teaminfty.math_dragon.view.math.Operation;
import org.teaminfty.math_dragon.view.math.Parentheses;
import org.teaminfty.math_dragon.view.math.Symbol;
import org.teaminfty.math_dragon.view.math.operation.Binary;
import org.teaminfty.math_dragon.view.math.operation.Integral;
import org.teaminfty.math_dragon.view.math.operation.Limit;
import org.teaminfty.math_dragon.view.math.operation.Negate;
import org.teaminfty.math_dragon.view.math.operation.binary.Add;
import org.teaminfty.math_dragon.view.math.operation.binary.Derivative;
import org.teaminfty.math_dragon.view.math.operation.binary.Divide;
import org.teaminfty.math_dragon.view.math.operation.binary.Log;
import org.teaminfty.math_dragon.view.math.operation.binary.Multiply;
import org.teaminfty.math_dragon.view.math.operation.binary.Power;
import org.teaminfty.math_dragon.view.math.operation.binary.Root;
import org.teaminfty.math_dragon.view.math.operation.binary.Subtract;
package org.teaminfty.math_dragon.model;


/**
 * Mathematical evaluator for {@link Expression}s into expressions returned by the Symja library.
 * 
 * @author Folkert van Verseveld
 */
public class EvalHelper
{
    private EvalHelper()
    {}
    
    /** The list of substitutions */
    public static Database.Substitution[] substitutions = null;
    
    /** Whether or not substitutions should be done */
    public static boolean substitute = true;
    
    /** Set to true when substitutions have been made (should be set to false manually before evaluating) */
    public static boolean substitutionsMade = false;

    /**
     * Convert the mathematical expression to a symja compatible expression.
     * Never returns <tt>null</tt>. On failure, a {@link MathException} is
     * thrown.
     * 
     * @param expr
     *        The mathematical expression. May not be <tt>null</tt>.
     * @return The mathematical expression returned by symja.
     * @throws MathException
     *         Thrown when it could not be converted.
     */
    public static IExpr eval(Expression expr) throws MathException
    {
        if(expr == null)
            throw new NullPointerException("expr");
        if (expr instanceof Operation)
            return operation((Operation) expr);
        if(expr instanceof Function)
            return function((Function) expr);
        if(expr instanceof Symbol)
            return symbol((Symbol) expr);
        if(expr instanceof Parentheses)
            return eval(expr.getChild(0));
        if(expr instanceof Empty)
            throw new EmptyChildException();

        throw new ParseException(expr.toString());
    }
    
    /**
     * Convert the mathematical operation to a symja compatible expression.
     * 
     * @param op
     *        The mathematical operation
     * @return A mathematical operation returned by symja.
     * @throws MathException
     *         Thrown when it could not be converted.
     */
    static IExpr operation(Operation op) throws MathException
    {
        if(op instanceof Binary)
            return binary((Binary) op);
        if(op instanceof Limit)
            return limit((Limit) op);
        if(op instanceof Integral)
            return integral((Integral) op);
        if(op instanceof Negate)
            return negate((Negate) op);
        throw new MathException(op.toString());
    }

    /**
     * Convert the binary mathematical operation to a symja compatible
     * expression.
     * 
     * @param bin
     *        The binary mathematical operation
     * @return A binary mathematical operation returned by symja.
     * @throws MathException
     *         Thrown when it could not be converted.
     */
    static IExpr binary(Binary bin) throws MathException
    {
        if(bin instanceof Add)