package interpreter.scheme;

import interpreter.*;
import interpreter.type.*;

import java.lang.IllegalArgumentException;

public class Base extends Library {
    public class Plus extends Primitive {
        public SchemeObject apply(Interpreter interpreter, SchemePair args) {
            double total = 0.0;
            while(args != null) {
                SchemeObject element = args.head;
                if(element instanceof SchemeNumber) {
                    total += ((SchemeNumber)element).value;
                } else {
                    throw new IllegalArgumentException("argument is not a Number");
                }
                args = SchemePair.of(args.tail);
            }
            return new SchemeNumber(total);
        }
    }

    public class Minus extends Primitive {
        public SchemeObject apply(Interpreter interpreter, SchemePair args) {
            if(args == null) {
                throw new IllegalArgumentException("not enough arguments");
            }
            if(!(args.head instanceof SchemeNumber)) {
                throw new IllegalArgumentException("argument is not a Number");
            }
            double total = ((SchemeNumber)args.head).value;
            if(args.tail == null) {
                return new SchemeNumber(-total);
            }
            args = SchemePair.of(args.tail);
            while(args != null) {
                SchemeObject element = args.head;
                if(!(element instanceof SchemeNumber)) {
                    throw new IllegalArgumentException("argument is not a Number");
                }
                total -= ((SchemeNumber)element).value;
                args = SchemePair.of(args.tail);
            }
            return new SchemeNumber(total);
        }
    }

    public class Times extends Primitive {
        public SchemeObject apply(Interpreter interpreter, SchemePair args) {
            double total = 1.0;
            while(args != null) {
                SchemeObject element = args.head;
                if(element instanceof SchemeNumber) {
                    total *= ((SchemeNumber)element).value;
                } else {
                    throw new IllegalArgumentException("argument is not a Number");
                }
                args = SchemePair.of(args.tail);
            }
            return new SchemeNumber(total);
        }
    }

    public class Divide extends Primitive {
        public SchemeObject apply(Interpreter interpreter, SchemePair args) {
            if(args == null) {
                throw new IllegalArgumentException("not enough arguments");
            }
            if(!(args.head instanceof SchemeNumber)) {
                throw new IllegalArgumentException("argument is not a Number");
            }
            double total = ((SchemeNumber)args.head).value;
            if(args.tail == null) {
                return new SchemeNumber(1 / total);
            }
            args = SchemePair.of(args.tail);
            while(args != null) {
                SchemeObject element = args.head;
                if(!(element instanceof SchemeNumber)) {
                    throw new IllegalArgumentException("argument is not a Number");
                }
                total /= ((SchemeNumber)element).value;
                args = SchemePair.of(args.tail);
            }
            return new SchemeNumber(total);
        }
    }


    public void importLib(Environment env) {
        env.define("+", new Plus());
        env.define("-", new Minus());
        env.define("*", new Times());
        env.define("/", new Divide());

        // Special forms
        env.define("if", new Syntax(Syntax.Special.IF));
        env.define("lambda", new Syntax(Syntax.Special.LAMBDA));
        env.define("begin", new Syntax(Syntax.Special.BEGIN));
        env.define("define", new Syntax(Syntax.Special.DEFINE));
        env.define("quote", new Syntax(Syntax.Special.QUOTE));
        env.define("set!", new Syntax(Syntax.Special.SET));
    }
}

@@ -3395,16 +3395,792 @@
 %0A    %7D%0A%0A
+    public class Equality extends Primitive %7B%0A        public SchemeObject apply(Interpreter interpreter, SchemePair args) %7B%0A            boolean result = true;%0A            SchemeNumber num = null;%0A            while(args != null) %7B%0A                SchemeObject element = args.head;%0A                if(!(element instanceof SchemeNumber)) %7B%0A                    throw new IllegalArgumentException(%22argument is not a Number%22);%0A                %7D%0A                if(num == null) %7B%0A                    num = ((SchemeNumber)element);%0A                %7D else %7B%0A                    result = result && num.value == ((SchemeNumber)element).value;%0A                %7D%0A                args = SchemePair.of(args.tail);%0A            %7D%0A            return new SchemeBoolean(result);%0A        %7D%0A    %7D%0A%0A
 %0A    pub
@@ -4368,16 +4368,57 @@
 vide());
+%0A        env.define(%22=%22, new Equality());
 %0A%0A      

Add = to scheme base