/// <summary>
        /// Takes a string and evaluates it as a mathematical expression, replacing any variables "ie, [X]" with the provided values
        /// </summary>
        /// <param name="identifier">An identifier for the string</param>
        /// <param name="input">The string to evaluate</param>
        /// <param name="variables">The Dictionary containing the variables and their values</param>
        /// <returns>The result of the evaluation</returns>
        public static double ParseMath(string identifier, string input, Dictionary <string, string> variables)
        {
            double currentVal = 0;
            string stack      = "";

            try
            {
                if (identifier != null) //recursive calls will pass null to avoid firing the events
                {
                    input = ReplaceMathVariables(identifier, input, variables);
                }

                string   lastOp    = "+";
                string[] ops       = { "+", "-", "*", "/", "%", "^", "(", "e", "E" };
                string[] functions = { "min", "max", "l", "ln", "L", "log", "abs", "sign", "if" }; //if (a < b ? stuff : other stuff)
                for (int i = 0; i < input.Length; ++i)
                {
                    string ch = input[i].ToString();
                    bool   isOp = false, isFunction = false;
                    foreach (string op in ops)
                    {
                        if (op == ch)
                        {
                            isOp = true;
                            break;
                        }
                    }
                    if (!isOp)
                    {
                        foreach (string fun in functions)
                        {
                            if (fun[0] == input[i])
                            {
                                isFunction = true;
                                break;
                            }
                        }
                    }

                    if (isOp)
                    {
                        if (ch == "-" && (stack.Trim() == ""))
                        {
                            stack += ch;
                        }
                        else if (ch == "e" || ch == "E")
                        {
                            int index;
                            for (index = i + 2; index < input.Length; ++index)
                            {
                                string ch2 = input[index].ToString();
                                if (ops.Contains(ch2))
                                {
                                    break;
                                }
                            }
                            string sub    = input.Substring(i + 1, index - i - 1);
                            double exp    = ParseMath(null, sub, null);
                            double newVal = double.Parse(stack) * Math.Pow(10, exp);
                            currentVal = DoMath(currentVal, lastOp, newVal.ToString());
                            stack      = "0";
                            lastOp     = "+";
                            i          = index - 1;
                        }
                        else if (ch == "(")
                        {
                            int    j   = FindEndParenthesis(input, i)[0];
                            string sub = input.Substring(i + 1, j - i - 1);
                            string val = ParseMath(null, sub, null).ToString();
                            input = input.Substring(0, i) + val + input.Substring(j + 1);
                            --i;
                        }
                        else
                        {
                            currentVal = DoMath(currentVal, lastOp, stack);
                            lastOp     = ch;
                            stack      = "";
                        }
                    }
                    else if (isFunction)
                    {
                        int    subStart   = input.IndexOf('(', i) + 1;
                        string function   = input.Substring(i, subStart - i - 1);
                        int[]  parenComma = FindEndParenthesis(input, subStart - 1);
                        int    j          = parenComma[0];
                        int    comma      = parenComma[1];
                        string sub        = input.Substring(subStart, j - subStart);
                        double val        = 0.0;

                        if (function == "if")
                        {
                            val = DoIfStatement(sub);
                        }
                        else if (function == "l" || function == "ln")
                        {
                            val = ParseMath(null, sub, null);
                            val = Math.Log(val);
                        }
                        else if (function == "L" || function == "log")
                        {
                            val = ParseMath(null, sub, null);
                            val = Math.Log10(val);
                        }
                        else if (function == "max" || function == "min")
                        {
                            string[] parts = new string[2];
                            parts[0] = input.Substring(subStart, comma - subStart);
                            parts[1] = input.Substring(comma + 1, j - comma - 1);
                            double sub1 = ParseMath(null, parts[0], null);
                            double sub2 = ParseMath(null, parts[1], null);
                            if (function == "max")
                            {
                                val = Math.Max(sub1, sub2);
                            }
                            else if (function == "min")
                            {
                                val = Math.Min(sub1, sub2);
                            }
                        }
                        else if (function == "sign")
                        {
                            val = ParseMath(null, sub, null);
                            if (val >= 0)
                            {
                                val = 1;
                            }
                            else
                            {
                                val = -1;
                            }
                        }
                        else if (function == "abs")
                        {
                            val = ParseMath(null, sub, null);
                            val = Math.Abs(val);
                        }

                        input = input.Substring(0, i) + val.ToString() + input.Substring(j + 1);
                        i--;
                    }
                    else
                    {
                        stack += ch;
                    }
                }
                currentVal = DoMath(currentVal, lastOp, stack);
            }
            catch (Exception ex)
            {
                MagiCore.LogException(ex, string.Format("Exception encountered while parsing '{0}' : '{1}'. Current value: '{2}' Stack: {3}", identifier, input, currentVal, stack));
                currentVal = 0;
            }
            return(currentVal);
        }
        /// <summary>
        /// Performs parsing of inline if statements
        /// </summary>
        /// <param name="statement">The statement string to act on</param>
        /// <returns>The result of the if statement</returns>
        private static double DoIfStatement(string statement)
        {
            //At this point "statement" would look something like a < b ? stuff : other stuff
            //We need to grab the conditional and the two possible values, then do the conditional and evaluate the correct value
            string[] mathConditionals   = { "<", ">", "<=", ">=", "==", "!=" }; //do we want to support && and ||, too? Ideally yes, but it's way tougher
            string[] stringConditionals = { " seq ", " sneq " };

            string[] conditionals = mathConditionals.Concat(stringConditionals).ToArray();
            double   val          = 0.0;

            try
            {
                // Debug.Log("MagiCore: Statement = " + statement);

                int    indexOfQMark       = statement.IndexOf("?");
                string conditionalSection = statement.Substring(0, indexOfQMark);
                //string[] condSides = conditionalSection.Split(conditionals, StringSplitOptions.RemoveEmptyEntries);
                foreach (string conditional in conditionals)
                {
                    conditionalSection = conditionalSection.Replace(conditional, ";" + conditional + ";");
                }
                string[] parts = conditionalSection.Split(';');
                //this is a kind of horrible method that I got from here, but avoided excessive regex: http://stackoverflow.com/a/2484982

                //lets assume there are only three elements
                if (parts.Length < 3)
                {
                    return(0.0);
                }

                //check that we aren't doing string comparisons, if so then we don't parse math on val1 or val2

                string condition = parts[1].Trim();
                double val1      = 0;
                double val2      = 0;

                string val1S = parts[0].Trim();
                string val2S = parts[1].Trim();

                if (mathConditionals.Contains(condition))
                {
                    //do math on part one
                    //do math on part two
                    //compare them
                    val1 = ParseMath(null, parts[0], null);
                    val2 = ParseMath(null, parts[2], null);
                }
                // Debug.Log("MagiCore: val1 = " + val1);
                // Debug.Log("MagiCore: val2 = " + val2);

                int indexOfColon = indexOfQMark;
                int depth        = 0;
                for (int i = indexOfQMark + 1; i < statement.Length; i++)
                {
                    char s = statement[i];
                    if (s == '(')
                    {
                        depth++;
                    }
                    if (s == ')')
                    {
                        depth--;
                    }

                    if (s == ':' && depth == 0)
                    {
                        indexOfColon = i;
                    }

                    if (depth < 0)
                    {
                        break;
                    }
                }

                string leftOption  = statement.Substring(indexOfQMark + 1, indexOfColon - indexOfQMark - 1); //starts at "?" and ends at last ":" for this depth
                string rightOption = statement.Substring(indexOfColon + 1);                                  //starts at last ":" and ends at end of statment

                // Debug.Log("MagiCore: left option = " + leftOption);
                // Debug.Log("MagiCore: right option = " + rightOption);

                string selectedOption = "";

                switch (condition)
                {
                case "<": selectedOption = val1 < val2 ? leftOption : rightOption; break;

                case ">": selectedOption = val1 > val2 ? leftOption : rightOption; break;

                case "<=": selectedOption = val1 <= val2 ? leftOption : rightOption; break;

                case ">=": selectedOption = val1 >= val2 ? leftOption : rightOption; break;

                case "==": selectedOption = val1 == val2 ? leftOption : rightOption; break;

                case "!=": selectedOption = val1 != val2 ? leftOption : rightOption; break;

                case "seq": selectedOption = string.Equals(val1S, val2S, StringComparison.Ordinal) ? leftOption : rightOption; break;

                case "sneq": selectedOption = !string.Equals(val1S, val2S, StringComparison.Ordinal) ? leftOption : rightOption; break;

                default: selectedOption = leftOption; break;
                }

                val = ParseMath(null, selectedOption, null);
            }
            catch (Exception ex)
            {
                MagiCore.LogException(ex, string.Format("Exception while performing if statement. Statement: '{1}'", statement));
                val = 0;
            }
            return(val);
        }