#ifndef CALCULATOR_H
#define CALCULATOR_H
#include <QString>
#include <QVector>
#include <math.h>

#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <stdexcept>
#include <math.h>

using namespace std;

class Calculator
{
public:
    static void SplitMath(const QString& math,QStringList &list,QString& format,bool &ismath){
        QString node;
        int index = 1;
        for(int i = 0;i<math.size();i++)
        {
            QChar c = math[i];
            switch(c.toLatin1()){
            case '+':
            case '-':
            case '*':
            case '/':
            case '(':
            case ')':
                ismath = true;
                if(!node.isEmpty())
                {
                    list.append(node);
                    node.clear();
                    format.append(QString("%%1").arg(QString::number(index++)));
                }
                format.append(math[i]);
                break;
            default:
                node.append(math[i]);
            }
            if(i==(math.size()-1)&&!node.isEmpty())
            {
                list.append(node);
                format.append(QString("%%1").arg(QString::number(index++)));
                node.clear();
            }
        }
    }

    static double parenth_final(const string &s)
        {
            if(!check_format(s))
                return 0;

            string  s_final;
            for (string::size_type i = 1; i != s.size() - 1; i++) {
                if (s[i] != '(') {
                    while (i != s.size() - 1 && s[i] != '(') {
                        s_final.push_back(s[i]);
                        i++;
                    }
                    i--;
                }
                else {
                    string s0;
                    int n = 0;
                    while (s[i] != ')' || n != 1) {
                        if (s[i] == ')')
                            n--;
                        if (s[i] == '(')
                            n++;
                        s0.push_back(s[i]);
                        i++;
                    }
                    s0.push_back(s[i]);
                    char tem[100];
                    sprintf(tem, "%lg", parenth_final(s0));
                    s_final += tem;
                }
            }

            return calc_final(s_final);
        }

        static bool check_format(const string &s)
        {
            int i = 0;
            bool iszkh = false;
            bool isykh = false;
            bool isysf = false;
            bool isxsd = false;
            bool ispf = false;
            bool isnum = false;
            bool isd = false;

            int flag = 0;

            while(i < s.size())
            {

                bool upiszkh = false;
                bool upisykh = false;
                bool upisysf = false;
                bool upisxsd = false;
                bool upispf = false;
                bool upisnum = false;
                bool upisd = false;

                if(s[i] == ' ')
                {
                    ++ i;
                    continue;
                }

                if(s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/')
                {
                    if(isysf || isd || ispf)
                        return false;

                    if((s[i] == '*' || s[i] == '/') && iszkh)
                        return false;

                    upisysf = true;
                }
                else
                {
                    upisysf = false;
                }

                if(s[i] == '^')
                {
                    if(isysf || iszkh || ispf || isd)
                        return false;
                    upispf = true;
                }
                else
                {
                    upispf = false;
                }

                if(s[i] == '(')
                {
                    ++flag;
                    if(isnum || ispf || isd || isykh || isnum)
                        return false;
                    upiszkh = true;
                }
                else
                {
                    upiszkh = false;
                }

                if(s[i] == ')')
                {
                    -- flag;
                    if(isysf || isd)
                        return false;
                    upisykh = true;
                }
                else
                {
                    upisykh = false;
                }

                if(s[i] == '.')
                {
                    if(ispf || isd || isysf || isykh || iszkh)
                        return false;
                    upisd = true;
                }
                else
                {
                    upisd= false;
                }

                if(s[i] >= '0' && s[i] <= '9')
                {
                    if(isykh)
                        return false;
                    upisnum= true;
                }
                else
                {
                    upisnum= false;
                }

                if(s[i] != '+' && s[i] != '-'   && s[i] != '.' && s[i] != '*' && s[i] != ' ' && s[i] != '/' && s[i] != '^'  && s[i] != '('  && s[i] != ')' &&  !(s[i] >= '0' && s[i] <= '9'))
                    return false;

                if(flag < 0)
                    return false;

                iszkh = upiszkh;
                isykh = upisykh;
                isysf = upisysf;
                isxsd = upisxsd;
                ispf = upispf;
                isnum = upisnum;
                isd = upisd;

                ++i;
            }

            if(flag != 0)
                return false;
            return true;
        }

        static double calc_final(const string &s)
        {
            Calculator suanshi(s);
            return suanshi.treat();
        }

    private:
        Calculator(const string &s)
        {
            string tem;
            string::size_type i = 0;
            int state = 0; //state = 0 则上一个标号是符号
            for (; i != s.size(); i++) {
                tem.clear();
                while (s[i] == ' ')
                    i++;
                if (s[i] == '-' && state == 0) {
                    tem.push_back(s[i]);
                    i++;
                    while( isdigit(s[i]) || s[i] == '.') {
                        tem.push_back(s[i]);
                        i++;
                    }
                    val.push_back(atof(tem.c_str()));
                    i--;
                    state = 1;
                }
                else if (isdigit(s[i]) || s[i] == '.') {
                    while( isdigit(s[i]) || s[i] == '.') {
                        tem.push_back(s[i]);
                        i++;
                    }
                    val.push_back(atof(tem.c_str()));
                    //if (i == s.size())
                    //return val.back();
                    i--;
                    state =1;
                }
                else {
                    sign.push_back(s[i]);
                    state = 0;
                }
            }
        }

        int calc_precede(char c)
        {
            switch (c) {
            case '+': case '-':
                return 1;
            case '*': case '/': case '%':
                return 2;
            case '^':
                return 3;
            }
        }

        double calc_single(double lhs, double rhs, char sign)
        {
            switch (sign) {
            case '+':
                return lhs + rhs;
            case '-':
                return lhs - rhs;
            case '*':
                return lhs * rhs;
            case '/':
                if (rhs == 0)
                    throw logic_error("chushu is 0");
                return lhs / rhs;
            case '%':
                if (rhs == 0)
                    throw logic_error("chushu is 0");
                return (int)lhs % (int)rhs;
            case '^':
                return pow(lhs, rhs);
            }
        }

        double treat()
        {
            double lhs, rhs;
            vector<double>::size_type i = 0;
            vector<char>::size_type j = 0;
            val_stack.push_back(val[i++]);
            //sign_stack.push_back(sign[j++]);
            //val_stack.push_back(val[i++]);
            if (sign.size() == 0){
                return val_stack.back();
            }

            for(; j != sign.size(); j++) {
                while (sign_stack.size() != 0 && calc_precede(sign[j]) <= calc_precede(sign_stack.back())) {
                    rhs = val_stack.back();
                    val_stack.pop_back();
                    lhs = val_stack.back();
                    val_stack.pop_back();
                    lhs = calc_single(lhs, rhs, sign_stack.back());
                    val_stack.push_back(lhs);
                    sign_stack.pop_back();
                }
                sign_stack.push_back(sign[j]);
                val_stack.push_back(val[i++]);
            }
            while (sign_stack.size() !=0 ){
                rhs = val_stack.back();
                val_stack.pop_back();
                lhs = val_stack.back();
                val_stack.pop_back();
                lhs = calc_single(lhs, rhs, sign_stack.back());
                val_stack.push_back(lhs);
                sign_stack.pop_back();
            }
            return lhs;
        }

    private:
        vector<double> val;
        vector<double> val_stack;
        vector<char> sign;
        vector<char> sign_stack;
};

#endif // CALCULATOR_H
