/// <summary>
        /// Whether or not a timespan can be created from the number of arguments supplied.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public static TimeSpan CreateTimeFrom(object[] args)
        {
            // Validate
            if (!CanCreateTimeFrom(args.Length))
            {
                throw new ArgumentException("Incorrect number of inputs for creating time");
            }

            // Convert object into ints
            int[] timeArgs = LangTypeHelper.ConvertToInts(args);
            int   len      = args.Length;

            // 1. 0 args = new TimeSpan()
            if (len == 0)
            {
                return(new TimeSpan());
            }

            // 2. 3 args = new TimeSpan(hours, mins, secs)
            if (len == 3)
            {
                return(new TimeSpan(timeArgs[0], timeArgs[1], timeArgs[2]));
            }

            // 3. 4 args = new TimeSpan(days, hours, mins, secs)
            return(new TimeSpan(timeArgs[0], timeArgs[1], timeArgs[2], timeArgs[3]));
        }
        public static object CheckConvert(object result)
        {
            // Finally, convert to fluentscript types.
            // Case 1: Aleady an LObject
            if (result is LObject)
            {
                return(result);
            }

            // Case 2: C# type so wrap inside of fluentscript type.
            return(LangTypeHelper.ConvertToLangValue(result));
        }
        /// <summary>
        /// Add 2 unites together.
        /// </summary>
        /// <param name="u1"></param>
        /// <param name="u2"></param>
        /// <returns></returns>
        public static LUnit AddUnits(LUnit u1, LUnit u2)
        {
            // Validate
            LangTypeHelper.ValidateUnits(u1, u2);

            // Now convert the values to their base value.
            double totalBase = u1.BaseValue + u2.BaseValue;
            var    unit      = new LUnit(totalBase);

            unit.BaseValue = totalBase;
            unit.Group     = u1.Group;
            unit.SubGroup  = u1.SubGroup;

            // Set the value to the converted relative value
            // e.g. if u1.subgroup = feet and u2.subgroup == inches.
            // then multiply result.basevalue by the conversion value.
            // Now convert the units
            return(unit);
        }
        /// <summary>
        /// Call a fluent script function from c#.
        /// </summary>
        /// <param name="context">The context of the call.</param>
        /// <param name="expr">The lambda function</param>
        /// <param name="convertApplicableTypes">Whether or not to convert applicable c# types to fluentscript types, eg. ints and longs to double, List(object) to LArrayType and Dictionary(string, object) to LMapType</param>
        /// <param name="args"></param>
        public static object CallFunctionViaCSharpUsingLambda(Context context, FunctionExpr expr, bool convertApplicableTypes, params object[] args)
        {
            var argsList = args.ToList <object>();

            if (convertApplicableTypes)
            {
                LangTypeHelper.ConvertToLangTypeValues(argsList);
            }
            var execution = new Execution();

            execution.Ctx = context;
            if (EvalHelper.Ctx == null)
            {
                EvalHelper.Ctx = context;
            }

            var result = FunctionHelper.CallFunctionInScript(context, execution, expr.Meta.Name, expr, null, argsList, false);

            return(result);
        }
        /// <summary>
        /// Converts from c# datatypes to fluentscript datatypes inside
        /// </summary>
        /// <param name="val"></param>
        public static LObject ConvertToLangLiteral(Token token)
        {
            if (token.Type == TokenTypes.Null)
            {
                return(LObjects.Null);
            }

            var type = token.Type;
            var kind = token.Kind;

            if (type == TokenTypes.LiteralNumber)
            {
                return(new LNumber(Convert.ToDouble(token.Value, CultureInfo.InvariantCulture))); //fix
            }
            if (type == TokenTypes.LiteralString)
            {
                return(new LString(Convert.ToString(token.Value)));
            }

            if (type == TokenTypes.LiteralDate)
            {
                return(new LDate(Convert.ToDateTime(token.Value)));
            }

            if (type == TokenTypes.LiteralTime)
            {
                return(new LTime((TimeSpan)token.Value));
            }

            if (type == TokenTypes.LiteralDay)
            {
                return(new LDayOfWeek((DayOfWeek)token.Value));
            }

            if (kind == TokenKind.LiteralBool)
            {
                return(new LBool(Convert.ToBoolean(token.Value)));
            }

            return(LangTypeHelper.ConvertToLangClass(token.Value));
        }
        /// <summary>
        /// Dynamically invokes a method call.
        /// </summary>
        /// <param name="ctx">Context of the script</param>
        /// <param name="obj">Instance of the object for which the method call is being applied.</param>
        /// <param name="datatype">The datatype of the object.</param>
        /// <param name="methodInfo">The method to call.</param>
        /// <param name="paramListExpressions">List of expressions representing parameters for the method call</param>
        /// <param name="paramList">The list of values(evaluated from expressions) to call.</param>
        /// <param name="resolveParams">Whether or not to resolve the parameters from expressions to values.</param>
        /// <returns></returns>
        private static object MethodCall(Context ctx, object obj, Type datatype, MethodInfo methodInfo, List <Expr> paramListExpressions, List <object> paramList, bool resolveParams, IAstVisitor visitor)
        {
            // 1. Convert language expressions to values.
            if (resolveParams)
            {
                ParamHelper.ResolveParametersForMethodCall(methodInfo, paramListExpressions, paramList, visitor);
            }

            // 2. Convert internal language types to c# code method types.
            object[] args = LangTypeHelper.ConvertArgs(paramList, methodInfo);

            // 3. Handle  params object[];
            if (methodInfo.GetParameters().Length == 1)
            {
                if (methodInfo.GetParameters()[0].ParameterType == typeof(object[]))
                {
                    args = new object[] { args }
                }
                ;
            }
            object result = methodInfo.Invoke(obj, args);

            return(result);
        }
        /// <summary>
        /// Converts arguments from one type to another type that is required by the method call.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="method">The method for which the parameters need to be converted</param>
        public static object[] ConvertArgs(List <object> args, MethodInfo method)
        {
            var hostLangArgs = new List <object>();
            var parameters   = method.GetParameters();

            if (parameters.Length == 0)
            {
                return(hostLangArgs.ToArray());
            }

            // REQUIREMENT: Number of values must match # of parameters in method.
            for (int ndx = 0; ndx < parameters.Length; ndx++)
            {
                var param     = parameters[ndx];
                var sourceArg = args[ndx] as LObject;

                // CASE 1: Null
                if (sourceArg == LObjects.Null)
                {
                    var defaultVal = LangTypeHelper.GetDefaultValue(param.ParameterType);
                    hostLangArgs.Add(defaultVal);
                }

                // CASE 2: int, bool, date, time
                else if (sourceArg.Type.IsPrimitiveType())
                {
                    var convertedVal = sourceArg.GetValue();
                    convertedVal = ConvertToCorrectHostLangValue(param.ParameterType, convertedVal);
                    hostLangArgs.Add(convertedVal);
                }
                // CASE 3: LArrayType and generic types.
                else if (sourceArg.Type == LTypes.Array)
                {
                    // Case 1: Array
                    if (param.ParameterType.IsArray)
                    {
                        if (param.ParameterType == typeof(string[]))
                        {
                            var convertedVal = ConvertToHostLangArray(param.ParameterType, (LArray)sourceArg);
                            hostLangArgs.Add(convertedVal);
                        }
                    }
                    else if (param.ParameterType.IsGenericType)
                    {
                        var gentype = param.ParameterType.GetGenericTypeDefinition();

                        // Case 2: Matching types IList<object>
                        if (gentype == typeof(IList <object>))
                        {
                            var convertedVal = sourceArg.GetValue();
                            hostLangArgs.Add(convertedVal);
                        }
                        // Case 3: Non-matching types List<object> to IList<Person>
                        else if (gentype == typeof(List <>) || gentype == typeof(IList <>))
                        {
                            //args[ndx] = ConvertToTypedList((List<object>) sourceArg.GetValue(), param.ParameterType);
                            var convertedArr = ConvertToTypedList((List <object>)sourceArg.GetValue(), param.ParameterType);
                            hostLangArgs.Add(convertedArr);
                        }
                    }
                }
            }
            return(hostLangArgs.ToArray());
        }
        /// <summary>
        /// Converts from c# datatypes to fluentscript datatypes inside
        /// </summary>
        /// <param name="val"></param>
        public static LObject ConvertToLangValue(object val)
        {
            if (val == null)
            {
                return(LObjects.Null);
            }

            var type = val.GetType();

            if (type == typeof(int))
            {
                return(new LNumber(Convert.ToDouble(val)));
            }

            if (type == typeof(double))
            {
                return(new LNumber((double)val));
            }

            if (type == typeof(decimal))
            {
                return(new LNumber(Convert.ToDouble(val)));
            }

            if (type == typeof(string))
            {
                return(new LString((string)val));
            }

            if (type == typeof(DateTime))
            {
                return(new LDate((DateTime)val));
            }

            if (type == typeof(TimeSpan))
            {
                return(new LTime((TimeSpan)val));
            }

            if (type == typeof(DayOfWeek))
            {
                return(new LDayOfWeek((DayOfWeek)val));
            }

            if (type == typeof(bool))
            {
                return(new LBool((bool)val));
            }

            var isGenType = type.IsGenericType;

            if (isGenType)
            {
                var gentype = type.GetGenericTypeDefinition();
                if (type == typeof(List <object>) || gentype == typeof(List <>) || gentype == typeof(IList <>))
                {
                    return(new LArray((IList)val));
                }

                if (type == typeof(Dictionary <string, object>))
                {
                    return(new LMap((Dictionary <string, object>)val));
                }
            }
            // object
            return(LangTypeHelper.ConvertToLangClass(val));
        }