package org.nwapw.abacus.number;

import java.util.HashMap;

public class FunctionDatabase {

    private HashMap<String, Function> functions;

    private void registerDefault(){

        functions.put("+", new Function() {
            @Override
            protected boolean matchesParams(Number[] params) {
                return params.length >= 1;
            }

            @Override
            protected Number applyInternal(Number[] params) {
                Number sum = params[0];
                for(int i = 1; i < params.length; i++){
                    sum = sum.add(params[i]);
                }
                return sum;
            }
        });

        functions.put("-", new Function() {
            @Override
            protected boolean matchesParams(Number[] params) {
                return params.length == 2;
            }

            @Override
            protected Number applyInternal(Number[] params) {
                return params[0].subtract(params[1]);
            }
        });

        functions.put("*", new Function() {
            @Override
            protected boolean matchesParams(Number[] params) {
                return params.length >= 1;
            }

            @Override
            protected Number applyInternal(Number[] params) {
                Number product = params[1];
                for(int i = 1; i < params.length; i++){
                    product = product.multiply(params[i]);
                }
                return product;
            }
        });

        functions.put("/", new Function() {
            @Override
            protected boolean matchesParams(Number[] params) {
                return params.length == 2;
            }

            @Override
            protected Number applyInternal(Number[] params) {
                return params[0].divide(params[1]);
            }
        });
    }

    public FunctionDatabase(){
        functions = new HashMap<>();
        registerDefault();
    }

    public Function getFunction(String name){
        return functions.get(name);
    }

}

@@ -173,17 +173,16 @@
 ault()%7B%0A
-%0A
         
@@ -1866,16 +1866,785 @@
      %7D);
+%0A%0A        functions.put(%22!%22, new Function() %7B%0A            @Override%0A            protected boolean matchesParams(Number%5B%5D params) %7B%0A                return params.length == 1;%0A            %7D%0A%0A            @Override%0A            protected Number applyInternal(Number%5B%5D params) %7B%0A                Number factorial = params%5B0%5D;%0A                Number multiplier = params%5B0%5D;%0A                //It is necessary to later prevent calls of factorial on anything but non-negative integers.%0A                while(multiplier.signum() == 1)%7B%0A                    multiplier = multiplier.subtract(NaiveNumber.ONE.promoteTo(multiplier.getClass()));%0A                    factorial = factorial.multiply(multiplier);%0A                %7D%0A                return factorial;%0A            %7D%0A        %7D);
 %0A    %7D%0A%0A

Add factorial (external).