using System;
using System.Collections.Generic;
using System.Text;

namespace math_net
{
    public static class Expression
    {
        // evals a function
        public static string Eval(string expression)
        {
            int openPos;
            int length;
            string[] signs = { "^""*""/""+" };

            expression = expression.Replace("."",");

            while (expression.Contains("("))
            {
                openPos = expression.IndexOf("(") + 1;
                length = expression.LastIndexOf(")") - (openPos);
                expression = expression.Substring(0, openPos - 1) +
                    Eval(expression.Substring(openPos, length)) +
                    expression.Substring(openPos + length + 1);
            }

            foreach (string sign in signs)
            {
                expression = MakeOperations(expression, sign);
            }

            return expression;
        }

        // gets the left value of a basic operation
        private static double GetLeftPart(string expression, int posSign)
        {
            int length = 1;
            double part;

            while (IsPartNumeric(expression, posSign - (length + 1), length + 1))
            {
                length++;
            }
            part = double.Parse(expression.Substring(posSign - length, length));

            return part;
        }

        // gets the right value of a basic operation
        private static double GetRightPart(string expression, int posSign)
        {
            int length = 1;
            double part;

            while (IsPartNumeric(expression, posSign + 1, length + 1))
            {
                length++;
            }
            part = double.Parse(expression.Substring(posSign + 1, length));

            return part;
        }

        // checks if a string has a numeric value
        private static bool IsNumeric(string expression)
        {
            Char[] chars = expression.ToCharArray();
            for(int i = 0; i < chars.Length; i++)
            {
                if (!char.IsNumber(chars[i]) && chars[i].ToString() != ",")
                {
                    if (chars[i].ToString() != "-" && i != 0)
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        // checks if a part of a string is numeric
        private static bool IsPartNumeric(string expression, int start, int length)
        {
            if ((start) < 0 || length > expression.Length - start)
            {
                return false;
            }

            return IsNumeric(expression.Substring(start, length));
        }

        // returns the specified basic operation
        private static double Operate(double firstValue, double secondValue,
            string sign)
        {
            switch (sign)
            {
                case "^":
                    if (!(IsInteger(secondValue)) && (firstValue < 0))
                    {
                        // i result
                        throw new ArgumentOutOfRangeException();
                    }
                    return Math.Pow(firstValue, secondValue);
                case "*":
                    return firstValue * secondValue;
                case "/":
                    if (secondValue == 0)
                    {
                        // infinite result
                        throw new ArgumentOutOfRangeException();
                    }
                    return firstValue / secondValue;
                case "+":
                    return firstValue + secondValue;
            }

            return 0;
        }

        //checks if a double var has a integer number
        private static bool IsInteger(double value)
        {
            return (double)((int)value) == value;
        }

        // makes all of the operations for the specified sign in a expression
        // whithout parenthesis
        private static string MakeOperations(string expression, string sign)
        {
            int signPos;
            double firstValue;
            double secondValue;
            double result;
            string operation;

            if (sign == "+")
            {
                // converts substractions into sums
                expression = expression.Replace("+-""-");
                expression = expression.Replace("-""+-");
                // if there's no value in front of the first + adds a 0
                if (expression.StartsWith("+"))
                {
                    expression = "0" + expression;
                }
            }

            // makes all of the operations for the specified sign
            while (expression.Contains(sign))
            {
                signPos = expression.IndexOf(sign);
                firstValue = GetLeftPart(expression, signPos);
                secondValue = GetRightPart(expression, signPos);
                operation = firstValue.ToString() + sign + secondValue.ToString();
                result = Operate(firstValue, secondValue, sign);
                expression = expression.Replace(operation, result.ToString());
            }

            return expression;
        }
    }
}