package haskell.prelude;

import haskell.lang.AbstractExp;
import haskell.lang.Exception;
import haskell.lang.Exp;
import haskell.lang.Type;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;

/**
 * type String = [Char]
 */
public class String
        extends List<Char>
        implements Type<List<Char>> {

    public String() {
    }

    public String(final Char head, final List<Char> tail) {
        super(head, tail);
    }

    String(final Exp<List<Char>> expression) {
        super(expression);
    }

    public static String valueOf(final java.lang.String value) {
        return valueOf(value.toCharArray());
    }

    public static String valueOf(final char[] chars) {
        return valueOf(chars, 0, chars.length);
    }

    public static String valueOf(
            final char[] chars, final int offset, final int length) {
        String s = Nil();
        for (int i = offset + length - 1; offset <= i; --i) {
            s = Cons(Char.valueOf(chars[i]), s);
        }
        return s;
    }

    public static String valueOf(final Char... array) {
        String s = Nil();
        for (int i = array.length - 1; 0 <= i; --i) {
            s = Cons(array[i], s);
        }
        return s;
    }

    public static String valueOf(final java.util.List<Char> list) {
        String s = Nil();
        for (int i = list.size() - 1; 0 <= i; --i) {
            s = Cons(list.get(i), s);
        }
        return s;
    }

    public static String valueOf(final Reader reader) {
        return new String(new ReaderExp("[a]", reader));
    }

    public static String valueOf(
            final java.lang.String expression, final Reader reader) {
        return new String(new ReaderExp(expression, reader));
    }

    public String eval() {
        return (String) super.eval();
    }

    static class ReaderExp extends AbstractExp<List<Char>> {

        BufferedReader reader;
        String value;

        protected ReaderExp(
                final java.lang.String expression,
                final Reader reader) {
            super(expression);
            if (reader instanceof BufferedReader) {
                this.reader = (BufferedReader) reader;
            } else {
                this.reader = new BufferedReader(reader);
            }
        }

        public String eval() {
            if (reader != null) {
                try {
                    value = evaluate();
                } finally {
                    reader = null;
                }
            }
            return value;
        }

        protected String evaluate() {
            try {
                java.lang.String line = reader.readLine();
                if (line == null) {
                    reader.close();
                    return Nil();
                }
                String s;
                //if (reader.ready()) {
                    s = new String(new ReaderExp(toString(), reader));
                    s = Cons(Char.valueOf('\n'), s);
                //} else {
                    //s = Nil();
                //}
                for (int i = line.length() - 1; 0 <= i; --i) {
                    s = Cons(Char.valueOf(line.charAt(i)), s);
                }
                return s;
            } catch (final IOException e) {
                throw new Exception(e);
            }
        }

    }

    // ---- java.lang.Object

    @Override
    protected java.lang.String $description() {
        return toString(this);
    }

    // ---- type String

    /**
     * []
     */
    @SuppressWarnings("unchecked")
    public static String Nil() {
        return new String();
    }

    /**
     * a : [a]
     */
    @SuppressWarnings("unchecked")
    public static Operator<Char, List<Char>, String> Cons() {
        return new Operator<Char, List<Char>, String>(
                ":", String.class, String.class, "Cons");
    }

    public static String Cons(final Char head, final List<Char> tail) {
        return new String(head, tail);
    }

    // ---- instance Eq String

    // ---- instance Ord String

    // ---- instance Functor String

    // ---- instance Monad String

    // ---- instance Show String

    @Override
    public String _show_() {
        return String.valueOf('"' + eval().toString() + '"');
//        final Char quot = Char.valueOf('"');
//        return String.Cons(quot,
//                append((List<Char>) this, Cons(quot, String.Nil())));
    }

    // ---- module PreludeList

    /**
     * lines :: String -> [String]
     */

    /**
     * words :: String -> [String]
     */

    /**
     * unlines :: [String] -> String
     */

    /**
     * unwords :: [String] -> String
     */

}
