package haskell.prelude;

import haskell.lang.Data;
import haskell.lang.Exp;
import haskell.prelude.text.Show;

/**
 * data Int = minBound ... -1 | 0 | 1 ... maxBound
 */
public class Int
        extends AbstractIntegral<Int>
        implements Data<Int>,
                Eq<Int>,
                Ord<Int>,
                Enum<Int>,
                Bounded<Int>,
                Num<Int>,
                Real<Int>,
                Integral<Int>,
                Show<Int> {

    final Integer value;

    Int(final int value) {
        super(java.lang.String.valueOf(value));
        this.value = value;
    }

    public Int(final Exp<Int> expression) {
        super(expression);
        this.value = null;
    }

    public static Int valueOf(final int value) {
        return new Int(value);
    }

    /**
     * 0
     */
    public static Int Zero() {
        return Zero;
    }

    static final Int Zero = Int.valueOf(0);

    /**
     * 1
     */
    public static Int One() {
        return One;
    }

    static final Int One = Int.valueOf(1);

    public int value() {
        return eval().value;
    }

    // ---- java.lang.Object

    @Override
    public int hashCode() {
        return value();
    }

    @Override
    public boolean equals(final Int other) {
        return (value() == other.value());
    }

    // ---- java.lang.Comparable

    public int compareTo(final Int other) {
        final int x = value();
        final int y = other.value();
        if (x == y) {
            return 0;
        } else if (x <= y) {
            return -1;
        } else {
            return 1;
        }
    }

    // ---- instance Eq Int

    protected Eq.Support<Int> _Eq_() {
        return Eq();
    }

    public static Eq.Support<Int> Eq() {
        return Ord;
    }

    // ---- instance Ord Int

    protected Ord.Support<Int> _Ord_() {
        return Ord();
    }

    public static Ord.Support<Int> Ord() {
        return Ord;
    }

    static final Ord.Support<Int> Ord
            = new AbstractOrd.Support<Int>(Int.class);

    // ---- instance Enum Int

    protected Enum.Support<Int> _Enum_() {
        return Enum();
    }

    public static Enum.Support<Int> Enum() {
        return Enum;
    }

    static final Enum.Support<Int> Enum
            = new Enum.Support<Int>(Int.class) {

        /**
         * toEnum n
         */
        public Int toEnum(final Int n) {
            return n;
        }

        /**
         * fromEnum x
         */
        public Int fromEnum(final Int x) {
            return x;
        }

    };

    // ---- instance Bounded Int

    public static Bounded.Support<Int> Bounded() {
        return Bounded;
    }

    static final Bounded.Support<Int> Bounded
            = new Bounded.Support<Int>() {

        /**
         * minBound
         */
        public Int minBound() {
            return Int.valueOf(Integer.MIN_VALUE);
        }

        /**
         * maxBound
         */
        public Int maxBound() {
            return Int.valueOf(Integer.MAX_VALUE);
        }

    };

    // ---- instance Num Int

    protected Num.Support<Int> _Num_() {
        return Num();
    }

    public static Num.Support<Int> Num() {
        return Integral;
    }

    // ---- instance Integral Int

    static final Integral.Support<Int> Integral
            = new Integral.Support<Int>(Int.class) {

        /**
         * 0
         */
        public Int zero() {
            return zero();
        }

        /**
         * x + y
         */
        public Int plus(final Int x, final Int y) {
            return Int.valueOf(x.value() + y.value());
        }

        /**
         * x - y
         */
        public Int minus(final Int x, final Int y) {
            return Int.valueOf(x.value() - y.value());
        }

        /**
         * x * y
         */
        public Int multiply(final Int x, final Int y) {
            return Int.valueOf(x.value() * y.value());
        }

        /**
         * negate x
         */
        public Int negate(final Int x) {
            return Int.valueOf(-x.value());
        }

    };

}
