package expression.generic;

/**
 * @author Doschennikov Nikita (me@fymio.us)
 */
public class IntCheckedType implements ArithmeticType<Integer> {

    public static final IntCheckedType INSTANCE = new IntCheckedType();

    private IntCheckedType() {}

    @Override
    public Integer fromInt(int value) {
        return value;
    }

    @Override
    public Integer add(Integer a, Integer b) {
        long result = (long) a + b;
        checkOverflow(result);
        return (int) result;
    }

    @Override
    public Integer subtract(Integer a, Integer b) {
        long result = (long) a - b;
        checkOverflow(result);
        return (int) result;
    }

    @Override
    public Integer multiply(Integer a, Integer b) {
        long result = (long) a * b;
        checkOverflow(result);
        return (int) result;
    }

    @Override
    public Integer divide(Integer a, Integer b) {
        if (b == 0) throw new ArithmeticException("Division by zero");
        if (a == Integer.MIN_VALUE && b == -1) throw new ArithmeticException(
            "Overflow"
        );
        return a / b;
    }

    @Override
    public Integer negate(Integer a) {
        if (a == Integer.MIN_VALUE) throw new ArithmeticException("Overflow");
        return -a;
    }

    @Override
    public Integer count(Integer a) {
        return Integer.bitCount(a);
    }

    @Override
    public Integer min(Integer a, Integer b) {
        return Math.min(a, b);
    }

    @Override
    public Integer max(Integer a, Integer b) {
        return Math.max(a, b);
    }

    private static void checkOverflow(long result) {
        if (result != (int) result) throw new ArithmeticException("Overflow");
    }
}
