/// <summary>
        /// Gets the declaration data of a static function by searching for the give signature (<paramref name="functionIdentifier"/> and <paramref name="parameterTypes"/>)
        /// in the LibraryPlugin with the given <paramref name="libraryPluginIdentifier"/>.
        /// </summary>
        /// <param name="libraryPluginIdentifier">the synery identifier of the plugin</param>
        /// <param name="functionIdentifier">the long name of the function including the namespace</param>
        /// <param name="parameterTypes">the data typs of the parameters (the correct order is important!)</param>
        /// <returns></returns>
        public IStaticExtensionFunctionData GetStaticFunctionDataBySignature(string libraryPluginIdentifier, string functionIdentifier, Type[] parameterTypes)
        {
            var libraryPluginData = (from i in _AvailablePlugins
                                     where i.Key.SyneryIdentifier == libraryPluginIdentifier
                                     select i.Value).FirstOrDefault();

            if (libraryPluginData == null)
            {
                throw new LibraryPluginManagerException(this, String.Format(
                                                            "Error while calling a static extension function. A LibraryPlugin with the given SyneryIdentifier='{0}' wasn't found.",
                                                            libraryPluginIdentifier));
            }
            else
            {
                IStaticExtensionFunctionData functionData = FindFunctionDeclaration(libraryPluginData, functionIdentifier, parameterTypes);

                if (functionData == null)
                {
                    string paramTypeNames = string.Join(",", parameterTypes.Select(p => p.Name));

                    throw new LibraryPluginManagerException(this, String.Format(
                                                                "No static extension function with the signature {0}.{1}({2}) was found.",
                                                                libraryPluginIdentifier, functionIdentifier, paramTypeNames));
                }

                return(functionData);
            }
        }
        public IValue RunWithResult(SyneryParser.LibraryPluginFunctionCallContext context)
        {
            string libraryPluginIdentifier;
            string functionIdentifier;
            string fullIdentifier = context.libraryPluginFunctionCallIdentifier().ExternalLibraryIdentifier().GetText();

            // split the identifier

            bool success = FunctionHelper.FragmentLibraryPluginIdentifier(fullIdentifier, out libraryPluginIdentifier, out functionIdentifier);

            if (success == false)
            {
                throw new SyneryInterpretationException(context.libraryPluginFunctionCallIdentifier(), "Wasn't able to fragment the library plugin function identifier. It doesn't have the expected format.");
            }

            // validate the identifier

            if (String.IsNullOrEmpty(libraryPluginIdentifier))
            {
                throw new SyneryInterpretationException(context, "The library plugin identifier is empty.");
            }
            if (String.IsNullOrEmpty(functionIdentifier))
            {
                throw new SyneryInterpretationException(context, "The function identifier is empty.");
            }

            // get the parameters

            IList <IValue> listOfParameters = FunctionHelper.GetListOfParameterValues(Controller, context.expressionList());

            Type[]   listOfParameterTypes  = listOfParameters.Select(p => p.Type.UnterlyingDotNetType).ToArray();
            object[] listOfParameterValues = listOfParameters.Select(p => p.Value).ToArray();

            // find the function declaration

            IStaticExtensionFunctionData functionDeclaration = Memory.LibraryPluginManager.GetStaticFunctionDataBySignature(libraryPluginIdentifier, functionIdentifier, listOfParameterTypes);

            object result = null;

            try
            {
                // execute the function

                result = Memory.LibraryPluginManager.CallStaticFunctionWithPrimitiveReturn(functionDeclaration, listOfParameterValues);
            }
            catch (Exception ex)
            {
                // create a Synery exception that can be caught by the Synery developer

                LibraryPluginExceptionRecord syneryException = new LibraryPluginExceptionRecord();
                syneryException.Message                 = ExceptionHelper.GetNestedExceptionMessages(ex);
                syneryException.FullIdentifier          = fullIdentifier;
                syneryException.LibraryPluginIdentifier = libraryPluginIdentifier;

                Controller.HandleSyneryEvent(context, syneryException.GetAsSyneryValue());
            }

            return(new TypedValue(TypeHelper.GetSyneryType(functionDeclaration.ReturnType), result));
        }
        public IExpressionValue RunWithResult(SyneryParser.RequestLibraryPluginFunctionCallContext context, QueryMemory queryMemory)
        {
            string libraryPluginIdentifier;
            string functionIdentifier;
            string fullIdentifier = context.libraryPluginFunctionCallIdentifier().ExternalLibraryIdentifier().GetText();

            // split the identifier

            bool success = FunctionHelper.FragmentLibraryPluginIdentifier(fullIdentifier, out libraryPluginIdentifier, out functionIdentifier);

            if (success == false)
            {
                throw new SyneryInterpretationException(context.libraryPluginFunctionCallIdentifier(), "Wasn't able to fragment the library plugin function identifier. It doesn't have the expected format.");
            }

            // validate the identifer

            if (String.IsNullOrEmpty(libraryPluginIdentifier))
            {
                throw new SyneryInterpretationException(context, "The library plugin identifer is empty.");
            }
            if (String.IsNullOrEmpty(functionIdentifier))
            {
                throw new SyneryInterpretationException(context, "The function identifer is empty.");
            }

            // get the parameters

            IEnumerable <IExpressionValue> listOfParameters = FunctionHelper.GetListOfParameterExpressionValues(Controller, queryMemory, context.requestExpressionList());

            Type[] listOfParameterTypes = listOfParameters.Select(p => p.ResultType.UnterlyingDotNetType).ToArray();
            IEnumerable <Expression> listOfParameterExpressions = listOfParameters.Select(p => p.Expression);

            // find the function declaration

            IStaticExtensionFunctionData functionDeclaration = Memory.LibraryPluginManager.GetStaticFunctionDataBySignature(libraryPluginIdentifier, functionIdentifier, listOfParameterTypes);

            // check whether the function has a return
            // functions without a return value aren't supported inside of a request statement

            if (functionDeclaration.ReturnType == null)
            {
                throw new SyneryInterpretationException(context, String.Format("Cannot call a function without a return from a query. Please chose a function instead of '{0}.{1}' that has a return value.", libraryPluginIdentifier, functionIdentifier));
            }

            // build the LINQ expression for calling the function from inside the LINQ expression tree

            Expression functionCallExpression = BuildExpression(functionDeclaration, listOfParameterExpressions);

            return(new ExpressionValue(
                       expression: functionCallExpression,
                       resultType: TypeHelper.GetSyneryType(functionDeclaration.ReturnType)
                       ));
        }
        public void Calling_Function_Without_Parameters_And_With_A_String_ReturnValue_Works()
        {
            FirstDummyStaticExtension extension = new FirstDummyStaticExtension();
            string expectedResult = extension.SecondMethod();

            IStaticExtensionFunctionData functionDeclaration = _LibraryPluginManager.GetStaticFunctionDataBySignature("First", "SecondMethod", new Type[] { });

            object result = _LibraryPluginManager.CallStaticFunctionWithPrimitiveReturn(functionDeclaration, new object[] {});

            Assert.AreEqual(expectedResult, result);
        }
        /// <summary>
        /// Executes a static function that returns a primitive value like string, int, bool etc.
        /// </summary>
        /// <param name="functionData"></param>
        /// <param name="listOfParameters">parameter values (the correct order is important!)</param>
        /// <returns>the return value or null if the function has no return value</returns>
        public object CallStaticFunctionWithPrimitiveReturn(IStaticExtensionFunctionData functionData, object[] listOfParameters)
        {
            object result;

            Type[] parameterTypes = (from p in functionData.Parameters
                                     select p.Type).ToArray();

            IList <object> parameterValues = listOfParameters.ToList();

            while (parameterValues.Count() < parameterTypes.Count())
            {
                // Optional parameters must be set as "Missing".
                // Otherwise the Invoke-method will throw an exception because the lenght of the parameter array doesn't match the method signature.
                parameterValues.Add(Type.Missing);
            }

            Type       staticExtensionType = functionData.StaticExtension.GetType();
            MethodInfo method = staticExtensionType.GetMethod(functionData.MethodName, parameterTypes);

            if (method == null)
            {
                throw new LibraryPluginManagerException(this, String.Format(
                                                            "Couldn't resolve a method with the name='{0}' and {1} parameter(s) (type order: {2}).",
                                                            functionData.MethodName, functionData.Parameters.Count, string.Join(",", functionData.Parameters.Select(p => p.Type.Name))));
            }

            try
            {
                // call the function
                result = method.Invoke(functionData.StaticExtension, parameterValues.ToArray());
            }
            catch (Exception ex)
            {
                throw new LibraryPluginManagerException(this, String.Format(
                                                            "An unexpected error occured while calling the static extension function with name='{0}'. The called method is named '{1}' and has {2} parameter(s) (type order: {3}).",
                                                            functionData.FullSyneryIdentifier, functionData.MethodName, functionData.Parameters.Count, string.Join(",", functionData.Parameters.Select(p => p.Type.Name))),
                                                        ex);
            }

            if (functionData.ReturnType != null)
            {
                return(result);
            }
            else
            {
                return(null);
            }
        }
        public void Calling_Function_With_Alternative_Name()
        {
            List <IValue> parameters = new List <IValue>()
            {
                new TypedValue(TypeHelper.GetSyneryType(typeof(string)), "This is a test."),
            };

            FourthDummyStaticExtension extension = new FourthDummyStaticExtension();
            string expectedResult = extension.SecondMethod((string)parameters[0].Value);

            IStaticExtensionFunctionData functionDeclaration = _LibraryPluginManager.GetStaticFunctionDataBySignature("First", "FirstLevelNamespace.SecondLevelNamespace.FirstMethodWithAlternativeName", parameters.Select(p => p.Type.UnterlyingDotNetType).ToArray());

            object result = _LibraryPluginManager.CallStaticFunctionWithPrimitiveReturn(functionDeclaration, parameters.Select(p => p.Value).ToArray());

            Assert.AreEqual(expectedResult, result);
        }
        public void Calling_Overloaded_Function_With_DateTime_Parameter_Works()
        {
            List <IValue> parameters = new List <IValue>()
            {
                new TypedValue(TypeHelper.GetSyneryType(typeof(DateTime)), new DateTime(1987, 12, 15, 22, 30, 0)),
            };

            FirstDummyStaticExtension extension = new FirstDummyStaticExtension();
            string expectedResult = extension.OverloadedMethod((DateTime)parameters[0].Value);

            IStaticExtensionFunctionData functionDeclaration = _LibraryPluginManager.GetStaticFunctionDataBySignature("First", "OverloadedMethod", parameters.Select(p => p.Type.UnterlyingDotNetType).ToArray());

            object result = _LibraryPluginManager.CallStaticFunctionWithPrimitiveReturn(functionDeclaration, parameters.Select(p => p.Value).ToArray());

            Assert.AreEqual(expectedResult, result);
        }
        public void Calling_Function_With_One_Parameter_And_With_A_String_ReturnValue_Works()
        {
            List <IValue> parameters = new List <IValue>()
            {
                new TypedValue(TypeHelper.GetSyneryType(typeof(string)), "This is a test."),
            };

            FirstDummyStaticExtension extension = new FirstDummyStaticExtension();
            string expectedResult = extension.ThirdMethod((string)parameters[0].Value);

            IStaticExtensionFunctionData functionDeclaration = _LibraryPluginManager.GetStaticFunctionDataBySignature("First", "ThirdMethod", parameters.Select(p => p.Type.UnterlyingDotNetType).ToArray());

            object result = _LibraryPluginManager.CallStaticFunctionWithPrimitiveReturn(functionDeclaration, parameters.Select(p => p.Value).ToArray());

            Assert.AreEqual(expectedResult, result);
        }
        public void Calling_Function_Without_Parameters_And_Without_ReturnValue_Works()
        {
            // the dummy plugin creates a textfile that indicates whether the function was executed
            // the test was successfull if the textfile exists
            string expectedExistingFilePath = Path.Combine(_LibraryPluginRuntimeTestPath, "FirstMethod.txt");

            if (File.Exists(expectedExistingFilePath))
            {
                throw new Exception("The test-file already exists before starting the test");
            }

            IStaticExtensionFunctionData functionDeclaration = _LibraryPluginManager.GetStaticFunctionDataBySignature("First", "FirstMethod", new Type[] {});

            _LibraryPluginManager.CallStaticFunctionWithPrimitiveReturn(functionDeclaration, new object[] {});

            Assert.IsTrue(File.Exists(expectedExistingFilePath));
        }
        /// <summary>
        /// Builds an expression that looks like this:
        /// Memory.LibraryPluginManager.CallStaticFunctionWithPrimitiveReturn(functionDeclaration, listOfParameterValues)
        /// </summary>
        /// <param name="functionData"></param>
        /// <param name="listOfParameterExpressions"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        private Expression BuildExpression(IStaticExtensionFunctionData functionData, IEnumerable <Expression> listOfParameterExpressions)
        {
            // cast all parameters to objects because LINQ requires all parameter-array items to be of type object
            IEnumerable <Expression> listOfObjectParameterExpressions = listOfParameterExpressions.Select(ex => Expression.Convert(ex, typeof(object)));

            MethodInfo executeFunctionMethod = typeof(ILibraryPluginManager)
                                               .GetMethod("CallStaticFunctionWithPrimitiveReturn", new Type[] { typeof(IStaticExtensionFunctionData), typeof(object[]) });

            Expression libraryPluginManagerExpression = Expression.Constant(Memory.LibraryPluginManager);

            Expression paramFunctionDataExpression     = Expression.Constant(functionData, typeof(IStaticExtensionFunctionData));
            Expression paramListOfParametersExpression = Expression.NewArrayInit(typeof(object), listOfObjectParameterExpressions);

            Expression methodCallExpression = Expression.Call(
                libraryPluginManagerExpression,
                executeFunctionMethod,
                paramFunctionDataExpression,
                paramListOfParametersExpression);

            return(methodCallExpression);
        }