package haskell.prelude;

import haskell.lang.Class;

/**
 * class Enum a
 */
public interface Enum<A extends Enum<A>>
        extends Class<A> {

    abstract class Support<A extends Enum<A>> {

        protected final java.lang.Class<A> a;

        protected Support(final java.lang.Class<A> a) {
            this.a = a;
        }

        // Minimal complate definition:
        //     toEnum, fromEnum

        /**
         * pred :: a -> a
         */
        public final Function<A, A> pred() {
            return new Function<A, A>(this, a, "pred");
        }

        /**
         * pred = toEnum . (substract 1) . fromEnum
         */
        public A pred(final A x) {
            return toEnum(fromEnum(x)._minus_(Int.One()));
        }

        /**
         * succ :: a -> a
         */
        public final Function<A, A> succ() {
            return new Function<A, A>(this, a, "succ");
        }

        /**
         * succ :: toEnum . (+ 1) . fromEnum
         */
        public A succ(final A x) {
            return toEnum(fromEnum(x)._plus_(Int.One()));
        }

        /**
         * toEnum :: Int -> a
         */
        public final Function<Int, A> toEnum() {
            return new Function<Int, A>(this, a, "toEnum");
        }

        public abstract A toEnum(Int n);

        /**
         * fromEnum :: a -> Int
         */
        public final Function<A, Int> fromEnum() {
            return new Function<A, Int>(this, Int.class, "fromEnum");
        }

        public abstract Int fromEnum(A x);

        /**
         * enumFrom :: a -> [a]
         */

        /**
         * enumFrom x = map toEnum [fromEnum x ..]
         */

        /**
         * enumFromTo :: a -> a -> [a]
         */

        /**
         * enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
         */

        /**
         * enumFromThen :: a -> a -> [a]
         */

        /**
         * enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
         */

        /**
         * enumFromThenTo :: a -> a -> a -> [a]
         */

        /**
         * enumFromThenTo x y z = map toEnum [fromEnum x, fromEnum y .. fromEnum z]
         */

    }

}
