package function.builtin.special;

import static function.builtin.EVAL.eval;

import function.ArgumentValidator;
import function.FunctionNames;
import function.LispSpecialFunction;
import sexpression.Cons;
import sexpression.SExpression;

@FunctionNames({ "IF" })
public class IF extends LispSpecialFunction {

    private ArgumentValidator argumentValidator;

    public IF(String name) {
        this.argumentValidator = new ArgumentValidator(name);
        this.argumentValidator.setMinimumNumberOfArguments(2);
        this.argumentValidator.setMaximumNumberOfArguments(3);
    }

    @Override
    public SExpression call(Cons argumentList) {
        argumentValidator.validate(argumentList);

        SExpression test = eval(argumentList.getFirst());
        SExpression thenForm = getThenForm(argumentList);
        SExpression elseForm = getElseForm(argumentList);

        return isNil(test) ? eval(elseForm) : eval(thenForm);
    }

    private boolean isNil(SExpression test) {
        return test.isNull();
    }

    private SExpression getThenForm(Cons argumentList) {
        Cons expressions = getRestOfList(argumentList);

        return expressions.getFirst();
    }

    private Cons getRestOfList(Cons argumentList) {
        return (Cons) argumentList.getRest();
    }

    private SExpression getElseForm(Cons argumentList) {
        Cons expressions = getRestOfList(argumentList);

        return getRestOfList(expressions).getFirst();
    }

}
