package haskell.prelude;

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

/**
 * data Char = ... 'a' | 'b' ... -- Unicode values
 */
public class Char
        extends AbstractEnum<Char>
        implements Data<Char>,
                Eq<Char>,
                Ord<Char>,
                Enum<Char>,
                Bounded<Char>,
                //Read<Char>,
                Show<Char> {

    final Character value;

    Char(final char value) {
        super(name(value));
        this.value = value;
    }

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

    static java.lang.String name(final char value) {
        switch (value) {
        case '\n':
            return "\\n";
        default:
            return java.lang.String.valueOf(value);
        }
    }

    public static Char valueOf(final char value) {
        return new Char(value);
    }

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

    // ---- java.lang.Object

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

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

    // ---- java.lang.Comparable

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

    // ---- instance Eq Char

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

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

    // ---- instance Ord Char

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

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

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

    // ---- instance Enum Char

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

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

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

        /**
         * toEnum = primIntToChar
         */
        public Char toEnum(final Int n) {
            return Char.valueOf((char) n.value());
        }

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

    };

    // ---- instance Bounded Char

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

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

        /**
         * minBound = '\0'
         */
        public Char minBound() {
            return Char.valueOf(Character.MIN_VALUE);
        }

        /**
         * maxBound = primUnicodeMaxChar
         */
        public Char maxBound() {
            return Char.valueOf(Character.MAX_VALUE);
        }

    };

    // ---- data [a]

    /**
     * this : tail
     */
    @Override
    @SuppressWarnings("unchecked")
    public final String _cons_(final List<Char> tail) {
        return new String(this, tail);
    }

}
