using System; 
 | 
using System.Collections.Generic; 
 | 
using System.Linq; 
 | 
using System.Text; 
 | 
using System.Reflection; 
 | 
using System.Collections; 
 | 
using Jace.Util; 
 | 
  
 | 
namespace Jace.Execution 
 | 
{ 
 | 
    public class FunctionRegistry : IFunctionRegistry 
 | 
    { 
 | 
        private const string DynamicFuncName = "Jace.DynamicFunc"; 
 | 
  
 | 
        private readonly bool caseSensitive; 
 | 
        private readonly Dictionary<string, FunctionInfo> functions; 
 | 
  
 | 
        public FunctionRegistry(bool caseSensitive) 
 | 
        { 
 | 
            this.caseSensitive = caseSensitive; 
 | 
            this.functions = new Dictionary<string, FunctionInfo>(); 
 | 
        } 
 | 
  
 | 
        public IEnumerator<FunctionInfo> GetEnumerator() 
 | 
        { 
 | 
            return functions.Values.GetEnumerator(); 
 | 
        } 
 | 
  
 | 
        IEnumerator IEnumerable.GetEnumerator() 
 | 
        { 
 | 
            return this.GetEnumerator(); 
 | 
        } 
 | 
  
 | 
        public FunctionInfo GetFunctionInfo(string functionName) 
 | 
        { 
 | 
            if (string.IsNullOrEmpty(functionName)) 
 | 
                throw new ArgumentNullException("functionName"); 
 | 
  
 | 
            FunctionInfo functionInfo = null; 
 | 
            return functions.TryGetValue(ConvertFunctionName(functionName), out functionInfo) ? functionInfo : null; 
 | 
        } 
 | 
  
 | 
        public void RegisterFunction(string functionName, Delegate function) 
 | 
        { 
 | 
            RegisterFunction(functionName, function, true, true); 
 | 
        } 
 | 
         
 | 
        public void RegisterFunction(string functionName, Delegate function, bool isIdempotent, bool isOverWritable) 
 | 
        { 
 | 
            if (string.IsNullOrEmpty(functionName)) 
 | 
                throw new ArgumentNullException("functionName"); 
 | 
  
 | 
            if (function == null) 
 | 
                throw new ArgumentNullException("function"); 
 | 
  
 | 
            Type funcType = function.GetType(); 
 | 
            bool isDynamicFunc = false; 
 | 
            int numberOfParameters = -1; 
 | 
             
 | 
            if (funcType.FullName.StartsWith("System.Func")) 
 | 
            { 
 | 
                foreach (Type genericArgument in funcType.GenericTypeArguments) 
 | 
                    if (genericArgument != typeof(double)) 
 | 
                        throw new ArgumentException("Only doubles are supported as function arguments.", "function"); 
 | 
  
 | 
                numberOfParameters = function 
 | 
                    .GetMethodInfo() 
 | 
                    .GetParameters() 
 | 
                    .Count(p => p.ParameterType == typeof(double)); 
 | 
            } 
 | 
            else if (funcType.FullName.StartsWith(DynamicFuncName)) 
 | 
            { 
 | 
                isDynamicFunc = true; 
 | 
            } 
 | 
            else 
 | 
                throw new ArgumentException("Only System.Func and " + DynamicFuncName + " delegates are permitted.", "function"); 
 | 
  
 | 
            functionName = ConvertFunctionName(functionName); 
 | 
  
 | 
            if (functions.ContainsKey(functionName) && !functions[functionName].IsOverWritable) 
 | 
            { 
 | 
                string message = string.Format("The function \"{0}\" cannot be overwriten.", functionName); 
 | 
                throw new Exception(message); 
 | 
            } 
 | 
  
 | 
            if (functions.ContainsKey(functionName) && functions[functionName].NumberOfParameters != numberOfParameters) 
 | 
            { 
 | 
                string message = string.Format("The number of parameters cannot be changed when overwriting a method."); 
 | 
                throw new Exception(message); 
 | 
            } 
 | 
  
 | 
            if (functions.ContainsKey(functionName) && functions[functionName].IsDynamicFunc != isDynamicFunc) 
 | 
            { 
 | 
                string message = string.Format("A Func can only be overwritten by another Func and a DynamicFunc can only be overwritten by another DynamicFunc."); 
 | 
                throw new Exception(message); 
 | 
            } 
 | 
  
 | 
            FunctionInfo functionInfo = new FunctionInfo(functionName, numberOfParameters, isIdempotent, isOverWritable, isDynamicFunc, function); 
 | 
  
 | 
            if (functions.ContainsKey(functionName)) 
 | 
                functions[functionName] = functionInfo; 
 | 
            else 
 | 
                functions.Add(functionName, functionInfo); 
 | 
        } 
 | 
  
 | 
            public bool IsFunctionName(string functionName) 
 | 
        { 
 | 
            if (string.IsNullOrEmpty(functionName)) 
 | 
                throw new ArgumentNullException("functionName"); 
 | 
  
 | 
            return functions.ContainsKey(ConvertFunctionName(functionName)); 
 | 
        } 
 | 
  
 | 
        private string ConvertFunctionName(string functionName) 
 | 
        { 
 | 
            return caseSensitive ? functionName : functionName.ToLowerFast(); 
 | 
        } 
 | 
    } 
 | 
} 
 |