package io.burt.jmespath.function;

import java.util.Map;
import java.util.HashMap;
import java.util.List;

import io.burt.jmespath.Adapter;

/**
 * A collection of functions, used by the adapters to look up and call functions
 * by name.
 */
public class FunctionRegistry {
  private final Map<String, JmesPathFunction> functions;

  /**
   * Create a registry with the the functions specified in the JMESPath
   * specification.
   */
  public static FunctionRegistry createDefaultRegistry() {
    FunctionRegistry registry = new FunctionRegistry();
    registry.add(new AbsFunction());
    registry.add(new AvgFunction());
    registry.add(new ContainsFunction());
    registry.add(new CeilFunction());
    registry.add(new EndsWithFunction());
    registry.add(new FloorFunction());
    registry.add(new JoinFunction());
    registry.add(new KeysFunction());
    registry.add(new LengthFunction());
    registry.add(new MapFunction());
    registry.add(new MaxFunction());
    registry.add(new MaxByFunction());
    registry.add(new MergeFunction());
    registry.add(new MinFunction());
    registry.add(new MinByFunction());
    registry.add(new NotNullFunction());
    registry.add(new ReverseFunction());
    registry.add(new SortFunction());
    registry.add(new SortByFunction());
    registry.add(new StartsWithFunction());
    registry.add(new SumFunction());
    registry.add(new ToArrayFunction());
    registry.add(new ToStringFunction());
    registry.add(new ToNumberFunction());
    registry.add(new TypeFunction());
    registry.add(new ValuesFunction());
    return registry;
  }

  public FunctionRegistry() {
    this.functions = new HashMap<>();
  }

  public void add(JmesPathFunction function) {
    functions.put(function.name(), function);
  }

  /**
   * Call a function by name, passing the specified list of arguments.
   *
   * @throws FunctionCallException when the function is not found
   * @throws ArityException when there are too few or too many arguments
   * @throws ArgumentTypeException when an argument does not match the function's argument type constraints
   */
  public <T> T callFunction(Adapter<T> adapter, String functionName, List<ExpressionOrValue<T>> arguments) {
    JmesPathFunction function = functions.get(functionName);
    if (function != null) {
      return function.call(adapter, arguments);
    } else {
      throw new FunctionCallException(String.format("Unknown function: \"%s\"", functionName));
    }
  }
}

@@ -497,35 +497,14 @@
     
-FunctionRegistry registry =
+return
  new
@@ -521,36 +521,23 @@
 egistry(
-);
 %0A    
-registry.add(
+  
 new AbsF
@@ -545,36 +545,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new AvgF
@@ -570,36 +570,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Cont
@@ -600,36 +600,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Ceil
@@ -626,36 +626,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Ends
@@ -656,36 +656,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Floo
@@ -683,36 +683,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Join
@@ -709,36 +709,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Keys
@@ -735,36 +735,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Leng
@@ -763,36 +763,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new MapF
@@ -788,36 +788,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new MaxF
@@ -813,36 +813,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new MaxB
@@ -840,36 +840,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Merg
@@ -867,36 +867,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new MinF
@@ -892,36 +892,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new MinB
@@ -919,36 +919,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new NotN
@@ -948,36 +948,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Reve
@@ -977,36 +977,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Sort
@@ -1003,36 +1003,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Sort
@@ -1031,36 +1031,24 @@
 nction()
-);%0A    registry.add(
+,%0A      
 new Star
@@ -1063,36 +1063,24 @@
 nction()
-);%0A    registry.add(
+,%0A      
 new SumF
@@ -1088,36 +1088,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new ToAr
@@ -1117,36 +1117,24 @@
 nction()
-);%0A    registry.add(
+,%0A      
 new ToSt
@@ -1147,36 +1147,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new ToNu
@@ -1177,36 +1177,24 @@
 nction()
-);
+,
 %0A    
-registry.add(
+  
 new Type
@@ -1207,28 +1207,16 @@
 on()
-);
+,
 %0A    
-registry.add(
+  
 new 
@@ -1235,30 +1235,14 @@
 on()
-);
 %0A    
-return registry
+)
 ;%0A  
@@ -1262,32 +1262,61 @@
 unctionRegistry(
+JmesPathFunction... functions
 ) %7B%0A    this.fun
@@ -1347,28 +1347,14 @@
 ;%0A  
-%7D%0A%0A  public void add
+  for 
 (Jme
@@ -1375,24 +1375,36 @@
 function
+ : functions
 ) %7B%0A    
 function
@@ -1395,16 +1395,23 @@
 ) %7B%0A    
+  this.
 function
@@ -1444,16 +1444,22 @@
 ction);%0A
+    %7D%0A
   %7D%0A%0A  /

Make FunctionRegistry immutable