package function.builtin;

import static function.builtin.EVAL.lookupFunctionOrLambda;
import static table.FunctionTable.lookupFunction;

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

@FunctionNames({ "APPLY" })
public class APPLY extends LispFunction {

    private ArgumentValidator argumentValidator;

    public static SExpression apply(Cons argumentList) {
        return lookupFunction("APPLY").call(argumentList);
    }

    public APPLY(String name) {
        this.argumentValidator = new ArgumentValidator(name);
        this.argumentValidator.setExactNumberOfArguments(2);
        this.argumentValidator.setTrailingArgumentExpectedType(Cons.class);
    }

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

        Cons rest = (Cons) argumentList.getRest();
        Cons functionArguments = (Cons) rest.getFirst();
        SExpression functionName = argumentList.getFirst();
        LispFunction function = lookupFunctionOrLambda(functionName);

        return function.call(functionArguments);
    }

}
