package haskell.prelude;

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

/**
 * data Ordering = LT | EQ | GT
 *     deriving (Eq, Ord, Enum, Bounded, Read, Show)
 */
public class Ordering
        extends AbstractEnum<Ordering>
        implements Data<Ordering>,
                Eq<Ordering>,
                Ord<Ordering>,
                Enum<Ordering>,
                Bounded<Ordering>,
                //Read<Ordering>,
                Show<Ordering> {

    final Integer value;

    Ordering(final java.lang.String name, final int value) {
        super(name);
        this.value = value;
    }

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

    public static Ordering valueOf(final int value) {
        return (value < 0 ? LT() : value == 0 ? EQ() : GT());
    }

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

    // ---- java.lang.Object

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

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

    // ---- java.lang.Comparable

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

    // ---- data Ordering

    /**
     * LT
     */
    public static Ordering LT() {
        return LT;
    }

    static final Ordering LT = new Ordering("LT", -1);

    public boolean isLT() {
        return (value() < 0);
    }

    /**
     * EQ
     */
    public static Ordering EQ() {
        return EQ;
    }

    static final Ordering EQ = new Ordering("EQ", 0);

    public boolean isEQ() {
        return (value() == 0);
    }

    /**
     * GT
     */
    public static Ordering GT() {
        return GT;
    }

    static final Ordering GT = new Ordering("GT", 1);

    public boolean isGT() {
        return (value() > 0);
    }

    // ---- instance Eq Ordering

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

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

    // ---- instance Ord Ordering

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

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

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

    // ---- instance Enum Ordering

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

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

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

        /**
         * toEnum n
         */
        public Ordering toEnum(final Int n) {
            return Ordering.valueOf(n.value());
        }

        /**
         * fromEnum x
         */
        public Int fromEnum(final Ordering x) {
            return Int.valueOf(x.value());
        }

    };

    // ---- instance Bounded Ordering

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

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

        /**
         * minBound
         */
        public Ordering minBound() {
            return LT;
        }

        /**
         * maxBound
         */
        public Ordering maxBound() {
            return GT;
        }

    };

}
