/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ca.mcmaster.cas.matlab2smt;

import java.util.Collection;

/**
 *
 * @author matthew
 */
final class MatlabExpressionBinaryOperation implements MatlabExpression, MatlabExpressionWithSubExpression {

    MatlabExpressionBinaryOperation(MatlabExpression lhs, MatlabBinaryOperation op, MatlabExpression rhs) {
        m_lhs = lhs;
        m_rhs = rhs;
        m_op = op;
    }

    void setLHS(MatlabExpression expr) {
        m_lhs = expr;
    }

    void setRHS(MatlabExpression expr) {
        m_rhs = expr;
    }

    private VariableType getInputTypeForOutput(VariableTypeMarker requestedType) {
        Collection<VariableTypeMarker> allowedInputTypes = m_op.getInputTypeForOutput(requestedType);
        for(VariableTypeMarker allowedType : allowedInputTypes) {
            VariableType inputType = m_lhs.actualOutputTypeForRequestedOutput(allowedType);
            if(inputType != null &&
                    m_rhs.actualOutputTypeForRequestedOutput(inputType) != null) {
                return inputType;
            }
            inputType = m_rhs.actualOutputTypeForRequestedOutput(allowedType);
            if(inputType != null &&
                    m_lhs.actualOutputTypeForRequestedOutput(inputType) != null) {
                return inputType;
            }
        }
        return null;
    }

    @Override
    public VariableType actualOutputTypeForRequestedOutput(VariableTypeMarker requestedType) {
        VariableType inputType = getInputTypeForOutput(requestedType);
        if (inputType != null) {
            return m_op.getOutputForInput(inputType);
        }
        return null;
    }

    @Override
    public String getCheckerOutput(CheckerGenerator generator, VariableType requestedType) {
        VariableType inputType = getInputTypeForOutput(requestedType);
        if (inputType == null) {
            throw new IllegalArgumentException("Requested output type is not valid for the expression's output type (" + requestedType.getClass().getSimpleName() + "!");
        }

        String lhsExp = m_lhs.getCheckerOutput(generator, inputType);
        String rhsExp = m_rhs.getCheckerOutput(generator, inputType);

        return generator.GenerateBinaryOperation(m_op, lhsExp, rhsExp, inputType);
    }

    @Override
    public MatlabExpression getSubExpression() {
        return m_rhs;
    }

    @Override
    public void setSubExpression(MatlabExpression subExpression) {
        m_rhs = subExpression;
    }

    @Override
    public String toString() {
        return "(" + m_lhs.toString() + " " + m_op.toString() + " " + m_rhs.toString() + ")";
    }

    MatlabExpression m_lhs, m_rhs;
    MatlabBinaryOperation m_op;
}
