//Coded entirely by Terence Cox
#include <iostream> 
#include <string>
#include <cstdlib> 
#include <math.h>
#include <iomanip>

using namespace std;

string substitute(double,double,string);
string simplify(bool,char, string);
double** fill2Ddyrow(int, int, double, double, double, double**);

double evaluator(string p_equ,bool debug)
	{
	start1:
	int fp=-1, lp=-1;
	//Search for Paraenthesis
	for (int c = 0; c < p_equ.size(); c++)
		{
		if (p_equ.at(c) == '(')
			fp = c;
		if (p_equ.at(c) == ')')
			{
			lp = c;
			break;
			}
		}
		//if parenthesis exist extract the expression within them
	if (fp < 0 && lp < 0)
		{
		if (debug == true)
			cout << "no more parentheses" << endl;
		}

	else
		{
		//extract from parenthesis and start the evauluation with the rest, then replaces solution in primary equ
		string s_equ (p_equ,fp+1, (lp-1) - fp);
		//solves what's in the parenthesis and eliminates the ()'s
		p_equ.replace(fp, (lp+1) - fp, to_string(evaluator(s_equ,debug)));
		goto start1;
		}
	//perform PEMDAS
	p_equ= simplify(debug,'-', simplify(debug,'+', simplify(debug,'*', simplify(debug,'/', simplify(debug,'^', p_equ)))));

	//string fsresult(p_equ, fp + 1, lp - fp);
   	double fresult = stod(p_equ);
	return fresult;
	}
	
	
string simplify(bool debug,char oper, string expr)
{
start2:
	int p, fnfp = -1, snlp = -1, reader = 1, runs = 0;
	double num1, num2, result;
	bool single_neg = false;

	p = -1;
	for (int c = 0; c < expr.size(); c++)
	{
		if (expr.at(c) == oper)
		{
			if (c>0) //prevents error when a negative number is first in the expression
				{
				//assigns the position of the operator to p
				p = c;
				break;
				}
		
		}
	}
	if (p < 0)
		{
		if (debug == true)
			cout << "no " << oper << endl;
		}

	else
	{
		runs++;
		while (expr.at(p - reader) == '-' ||expr.at(p - reader) == '.' || isdigit(expr.at(p - reader)))
		{
			fnfp = p - reader;
			reader++;
			if (p - reader < 0) //handles exception where this reads outside of memory
				break;
			if (expr.at(fnfp) == '-')//hnadles a runtime error which causes negative numbers to be omitted
				{
				break;
				}
		}
		reader = 1;
		while (expr.at(p + reader) == '-' || expr.at(p + reader) == '.' || isdigit(expr.at(p + reader)))
		{
			snlp = p + reader;
			//This code checks to make sure only one negative symbol is allowed, will break if another is found.
			if (expr.at(snlp) == '-')
			{
				if (single_neg == true)
					break;
				else
					single_neg=true;
			}
			reader++;
			if (p + reader > expr.size() - 1) //handles exception where this reads outside of memory
				break;
		}
		string strnum1(expr, fnfp, p - fnfp);
		string strnum2(expr, p + 1, snlp - p);
		double num1 = stod(strnum1);
		double num2 = stod(strnum2);


		switch (oper)
		{
		case '^':
			result = pow(num1, num2);
			break;
		case '/':
			result = num1 / num2;
			break;
		case '*':
			result = num1*num2;
			break;
		case '+':
			result = num1 + num2;
			break;
		case '-':
			result = num1 - num2;
			break;
		}
		//result = (int)(result * 10000.0) / 10000.0;
		if (debug==true)
			cout << "after performing " << oper << " the result is " << result << endl;
		//replace the solve part of the expression into the entire expression
		expr.replace(fnfp, (snlp + 1) - fnfp, to_string(result));
		goto start2;
	}
	if(debug==true)
		cout << "solved " << runs << " " << oper << " operations" << endl;
	return expr;
}

string substitute(double X,double Y,string equ)
{
	//checks each character for X or Y to replace them with actual values
	for (int c = 0; c < equ.size(); c++)
	{
		if (equ.at(c) == 'X'||equ.at(c)=='x')
			equ.replace(c, 1, to_string(X));
		if (equ.at(c) == 'Y' || equ.at(c) == 'y')
			equ.replace(c, 1, to_string(Y));
	}
	return equ;
}



int main()
{
Begin:
	cout.precision(5);
	string equation;
	int steps;
	float X1, X2, Y1, K, h, d;
	double change;
	bool debug = false, use_table = true, userres;
	cout << "What is the differential equation you want to use Euler's method on?\ny'= ";
	cin >> equation;
	cout << "Fill this in\n (y(x) = ___)\n    |     \n    v     \nx= ";
	cin >> X1;
	cout << "and this\n (y(" << X1 << ") = __)\n           |\n           v\n        y= ";
	cin >> Y1;
	cout << "How many steps of accuracy do you want to use: ";
	cin >> steps;
	cout << "Last question, what is the value of X you want to use to solve Y" << endl;
	cin >> X2;
	h = (X2 - X1) / steps;
	cout << "The size of h is " << h << "." << endl;

	//create a new 2D Dynamic Array
	double** table = new double*[steps + 1];
	for (int i = 0; i < steps + 1; ++i)
		table[i] = new double[4];

	//fill in table with obtained information
	table = fill2Ddyrow(0,0,X1,Y1,0,table);

		//perform the Euler's process for the inputted amount of steps
		for (int t = 0; t < steps; t++)
		{
			K = evaluator(substitute(table[t][1], table[t][2], equation),debug);
			table[t][3] = K;
			d = K * h;
			table=fill2Ddyrow(t + 1, t + 1,X1+(h*(t + 1)),d + (table[t][2]),0,table);
		}

	//outputs the values in the table into the console
		cout << left << setw(11) << "step i" << setw(11) << "X1" << setw(11) << "Y1" << setw(11) << "K" << endl;
		for (int row = 0; row < steps + 1; row++)
		{
			cout << endl;
			for (int column = 0; column < 4; column++)
			{
				cout << setw(11) << table[row][column];
			}
		}
	cout << endl;
	cout << "The Final Answer is " << table[steps][2] << endl;
	cout << "Done" << endl;
	cout << "Do you want to enter another Diffy-Q?, 1(True) or 0(False)" << endl;
	cin >> userres;
	if (userres == 1)
		goto Begin;
	system("pause");
}

double** fill2Ddyrow(int row,int step, double X, double Y, double K,double** tablef)
	{
	tablef[row][0] = step;
	tablef[row][1] = X;
	tablef[row][2] = Y;
	tablef[row][3] = K;
	return tablef;
	}