package expression;

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

/**
 * @author Doschennikov Nikita (me@fymio.us)
 */
public class Variable extends AbstractExpression {

    private final String name;
    private final int index;

    public Variable(String name) {
        this.name = name;
        this.index = -1;
    }

    public Variable(int index) {
        this.index = index;
        this.name = "$" + index;
    }

    public Variable(int index, String name) {
        this.index = index;
        this.name = name;
    }

    @Override
    public int evaluate(int x) {
        if (index >= 0) {
            if (index == 0) return x;
            throw new IllegalStateException(
                "Positional variable $" +
                    index +
                    " cannot be evaluated with a single value"
            );
        }
        if ("x".equals(name)) return x;
        throw new IllegalStateException(
            "Variable '" + name + "' is not 'x'; use evaluate(x, y, z) instead"
        );
    }

    @Override
    public int evaluate(int x, int y, int z) {
        if (index >= 0) {
            return switch (index) {
                case 0 -> x;
                case 1 -> y;
                case 2 -> z;
                default -> throw new IndexOutOfBoundsException(
                    "Variable index " +
                        index +
                        " out of range for triple evaluate"
                );
            };
        }
        return switch (name) {
            case "x" -> x;
            case "y" -> y;
            case "z" -> z;
            default -> throw new IllegalStateException(
                "Unknown variable: " + name
            );
        };
    }

    @Override
    public int evaluate(List<Integer> vars) {
        return vars.get(resolvedIndex());
    }

    @Override
    public BigInteger evaluateBi(List<BigInteger> vars) {
        return vars.get(resolvedIndex());
    }

    @Override
    public BigDecimal evaluateBd(List<BigDecimal> vars) {
        return vars.get(resolvedIndex());
    }

    private int resolvedIndex() {
        if (index >= 0) return index;
        return switch (name) {
            case "x" -> 0;
            case "y" -> 1;
            case "z" -> 2;
            default -> throw new IllegalStateException(
                "Unknown variable: " + name
            );
        };
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public String toMiniString() {
        return name;
    }

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

    @Override
    public int hashCode() {
        return name.hashCode();
    }
}
