#include <iostream>
#include <fstream>
#include <Solver.hpp>

#define WIDTH 500.
#define HEIGHT 400.

#define ARC_RADIUS 150.

//#define SQUARE_X 355.
//#define SQUARE_Y 155.
//#define SQUARE_SIDE 100.

#define HOLE_X 355.
#define HOLE_Y 155.
#define HOLE_RADIUS 50.

void visualize(std::ofstream& file, std::string filename, int time_end) {
	file << "set cbrange [" << 0 << ":" << 100 << "]" << std::endl;
	file << "set size ratio " << float(400) / 500 << "\nunset key\n" << "\nset palette defined (0 0 0 1, 0.25 0 1 1, 0.5 0 1 0, 0.75 1 1 0, 1 1 0 0)\n" << std::endl;
	file << "do for [i=0:" << time_end - 1 << "]{" << std::endl;
	file << "plot '" << filename << "' u 1:2:3 index i w points pt 5 palette" << std::endl;
	file << "pause " << 0.000000001 << "}" << std::endl;
	file << "pause mouse";
}

int main()
{
	int l = 3; //Bound conditions
	int t = 3;
	int r = 1;
	int b = 3;
	int r2 = 4;
	int s = 3;

	double step = 10; // Mesh step
	double step2 = 5; // Mesh step

	double time_step = 1;
	double time_end = 100;

	double C = 50.; // Material props

	std::map<std::string, double> plate{ 
		{"a", WIDTH / 2}, {"b", HEIGHT / 2}, {"h_x", 1 / WIDTH}, {"h_y", 1 / HEIGHT} 
	};
	std::map<std::string, double> arc{
		{"a", WIDTH - ARC_RADIUS}, {"b", HEIGHT - ARC_RADIUS}, {"h_x", 1 / ARC_RADIUS}, {"h_y", 1 / ARC_RADIUS} 
	};
	std::map<std::string, double> circle{
		{"a", HOLE_X}, {"b", HOLE_Y}, {"h_x", 1 / HOLE_RADIUS}, {"h_y", 1 / HOLE_RADIUS}
	};

	Object obj;
	obj.Add_Form("Circle", circle, true, s);
	obj.Add_Form("Arc", arc, true, r2);
	obj.Add_Form("Rectangle", plate, false, 1);

	System explicit10(obj, step, C);
	explicit10.DefineBounds(l, t, r, b);

	System explicit5(obj, step2, C);
	explicit5.DefineBounds(l, t, r, b);

	System implicit10(obj, step, C);
	implicit10.DefineBounds(l, t, r, b);

	System implicit5(obj, step2, C);
	implicit5.DefineBounds(l, t, r, b);


	Solver slv10("explicit10.txt", "implicit10.txt", time_step);
	slv10.SolveExplicit(explicit10, time_end);
	slv10.SolveImplicit(implicit10, time_end);

	Solver slv5("explicit5.txt", "implicit5.txt", time_step);
	slv5.SolveExplicit(explicit5, time_end);
	slv5.SolveImplicit(implicit5, time_end);
	std::ofstream script("es10.plt");
	visualize(script, "explicit10.txt", time_end);
	script.close();

	script.open("is10.plt");
	visualize(script, "implicit10.txt", time_end);
	script.close();

	script.open("es5.plt");
	visualize(script, "explicit5.txt", time_end);
	script.close();

	script.open("is5.plt");
	visualize(script, "implicit5.txt", time_end);
	script.close();
	return 0;
}

//std::map<std::string, double> square{ 
	//	{"a", SQUARE_X}, {"b", SQUARE_Y}, {"h_x", 1 / SQUARE_SIDE}, {"h_y", 1 / SQUARE_SIDE} 
	//};