package function.builtin.math;

import java.util.function.BiFunction;
import java.util.function.Function;

import sexpression.Cons;
import sexpression.LispNumber;
import sexpression.SExpression;

class MathFunction {

    Function<LispNumber, LispNumber> singleValueOperation;
    BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation;

    public MathFunction(Function<LispNumber, LispNumber> singleValueOperation,
                        BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation) {
        this.singleValueOperation = singleValueOperation;
        this.multipleValueOperation = multipleValueOperation;
    }

    public LispNumber callTailRecursive(Cons argumentList) {
        Cons remainingArguments = (Cons) argumentList.getRest();
        SExpression firstArgument = argumentList.getFirst();
        LispNumber number1 = (LispNumber) firstArgument;

        if (remainingArguments.isNull())
            return singleValueOperation.apply(number1);

        SExpression secondArgument = remainingArguments.getFirst();
        LispNumber number2 = (LispNumber) secondArgument;
        LispNumber operationResult = multipleValueOperation.apply(number1, number2);
        SExpression remainingNumbers = remainingArguments.getRest();

        if (remainingNumbers.isNull())
            return operationResult;

        return callTailRecursive(new Cons(operationResult, remainingNumbers));
    }

}
