package expression;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;

/**
 * @author Doschennikov Nikita (me@fymio.us)
 */
public class Cube extends AbstractExpression {
    private final AbstractExpression operand;

    public Cube(AbstractExpression operand) {
        this.operand = operand;
    }

    private static int checkedMul(int a, int b) {
        if (a == 0 || b == 0) return 0;
        if (a == Integer.MIN_VALUE || b == Integer.MIN_VALUE) throw new OverflowException("cube");
        int r = a * b;
        if (r / a != b) throw new OverflowException("cube");
        return r;
    }

    private static int cubeInt(int n) {
        return checkedMul(checkedMul(n, n), n);
    }

    @Override public int        evaluate(int x)               { return cubeInt(operand.evaluate(x)); }
    @Override public int        evaluate(int x, int y, int z) { return cubeInt(operand.evaluate(x,y,z)); }
    @Override public int        evaluate(List<Integer> vars)  { return cubeInt(operand.evaluate(vars)); }
    @Override public BigInteger evaluateBi(List<BigInteger> vars) { return operand.evaluateBi(vars).pow(3); }
    @Override public BigDecimal evaluateBd(List<BigDecimal> vars) { return operand.evaluateBd(vars).pow(3); }

    @Override public String toString()     { return "(" + operand + ")³"; }

    @Override
    public String toMiniString() {
        String s = operand.toMiniString();
        boolean needParens = operand instanceof AbstractBinaryOperation
                || operand instanceof Cbrt
                || operand instanceof Sqrt
                || (s.startsWith("-") && (s.length() < 2 || !Character.isDigit(s.charAt(1))));
        return needParens ? "(" + s + ")³" : s + "³";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof Cube)) return false;
        return operand.equals(((Cube) obj).operand);
    }

    @Override public int hashCode() { return operand.hashCode() ^ 0x43554245; }
}