#include <Plot.h>
#include <console.h>
#include <command>
#include <sstream>


Plot :: Plot(Profile *profile_) :
	profile(profile_)
{
	for (int i = 0; i < profile->nProjs(); i++)
	{
                cout << "argvComp " << i << " : " << profile->argvComp(i) << endl;
                cout << "argvType " << i << " : " << profile->argvType(i) << endl;
		projection.push_back(new Projection(i, profile->argvComp(i), profile->argvType(i), profile->inputComps()));
	}
}


void Plot :: eventloop()
{

	optionMenu();

	bool plotting = false;
	bool replot = true;
	bool cont = true;
	int index = 0;
	int ch;
	int step = 1;
	int i, j;

	execute(new RangeCommand);
	execute(new SetDecorCommand);
	execute(new SetLinesCommand);


	changemode(1);

	while ( cont )
	{
		while ( !kbhit() ) 
		{ 
			if (replot) 
			{
				if (plotting) 
					index = index + step;
				else 
					replot = false;
					
				if (index >= profile->nSteps()-1)
				{
					index = profile->nSteps()-1;
					step = 1;
					plotting = false;
				}

				if (index <= 0)
				{
					index = 0;
					step = 1;
					plotting = false;
				}

				profile->index(index);

				if ( profile->decoration() )
					execute(new TitleCommand);

				execute(new PlotCommand);

				system ("sleep 0.05");
			}
		}
 
		ch = getchar();

		if ( ch == '\033' ) // Is key is a arrow skip extra characters
		{
			ch = getchar();
			ch = getchar();
		}

		switch (ch)
		{
			case 65: // arrow up
				plotting = true;
				replot = true;
				break;
			case 66: // arrow down
				if (plotting) plotting = false; else index = 0;
				step = 1;
				replot = true;
				break;
			case 67: // arrow right
				index = index + step;
				if (plotting)
				{
					step++;
					if (step == 0) step++;
				}
				replot = true;
				break;
			case 68: // arrow left
				if (plotting)
				{
					step--;
					if (step == 0) step--;
				}
				else
					index--;
				replot = true;
				break;
			case 77: // 'M' - print eps image
				execute(new MakeMovieCommand);
				console::consolecolor(console::BLUE);
				optionMenu();
				console::consolecolor();
				break;
/*
			case 82: // 'R' - reset range
				int p2;
				if ( projection[p2]->sRange() )
				{
					projection[p2]->resetSrange();
					execute(new RangeCommand);
				}
				replot = true;
				break;
*/
			case 82: // 'R' - reset range
				int p2;
				changemode(0);
				console::eraser();
				cout << "Enter projection number: ";
				cin >> p2;
				changemode(1);
				if ( projection[p2]->sRange() )
				{
					projection[p2]->resetSrange();
					execute(new RangeCommand);
				}
				replot = true;
				break;
			case 98: // 'b' - border percentage
				float border;
				changemode(0);
				console::eraser();
				cout << "Entre border percentage: ";
				cin >> border;
				changemode(1);
				if ( cin )
				{
					profile->border(border/100);
					execute(new RangeCommand);
				}
				replot = true;
				break;
			case 99: // 'c' - toggle ticmarks
				profile->toggleTicMarks();
				execute(new TicsCommand);
				replot = true;
				break;
			case 100: // 'd' - toggle decoration
				if ( profile->decoration() ) 
					execute(new UnsetDecorCommand);
				else
					execute(new SetDecorCommand);
				replot = true;
				break;
			case 103: // 'g' - toggle grid
				if ( profile->grid() ) 
					execute(new UnsetGridCommand);
				else
					execute(new SetGridCommand);
				replot = true;
				break;
			case 105: // 'i' - change index
				//int step;
				changemode(0);
				console::eraser();
				cout << "Enter step number: ";
				cin >> index;
				changemode(1);
				replot = true;
				break;
			case 108: // 'l' - change legend position
				profile->toggleLegend();
				execute(new LegendPosCommand);
				replot = true;
				break;
			case 113: // 'q' - quit
				cont = false;
				replot = false;
				break;
			case 114: // 'r' - change range
				int p1;
				changemode(0);
				console::eraser();
				cout << "Enter projection number: ";
				cin >> p1;
				changemode(1);
				if ( p1 >= projection.size() || p1 < 0)
				{
					cout << "There's no projection " << p1 << "!!" << endl;
					changemode(1);
					break;
				}
				else
				{
					float xmin, xmax, ymin, ymax;
					changemode(0);
					console::eraser();
					cout << "Entre range [xmin, xmax, ymin, ymax]: ";
					cin >> xmin >> xmax >> ymin >> ymax;;
					changemode(1);
					if ( cin )
					{
						projection[p1]->setSrange(xmin, xmax, ymin, ymax);
						execute(new TicsCommand);
						execute(new RangeCommand);
					}
				}
				replot = true;
				break;
			case 115: // 's' - print eps image
				float xdim, ydim, fontSize;
				string p_;
				changemode(0);
				console::eraser();
				cout << "Entre print info [xdim=(" << profile->printXdim() << "in), " \
							"ydim=(" << profile->printYdim() << "in), "\
							"font_size=(" << profile->fontSize() << "px)]: ";

				getline(cin, p_);
				changemode(1);
				if ( !p_.empty() )
				{
					istringstream stream (p_);
					stream >> xdim >> ydim >> fontSize;
					if ( xdim > 0 ) profile->printXdim(xdim);
					if ( ydim > 0 ) profile->printYdim(ydim);
					if ( fontSize > 0 ) profile->fontSize(fontSize);
				}
				console::eraser();
				execute(new PrintEpsCommand);
				break;
/*
			case 116: // 't' - draw triangle
				int in;
				cout << "Enter projection number: ";
				changemode(0);
				cin >> in;
				changemode(1);
				execute(new TriangCommand(projection[in]));
				break;
			case 117: // 'u' - print gnuplot command for debug
				//	DEBUG routine
				break;
*/
/*
			case 119: // 'w' - line width
				float linew;
				changemode(0);
				console::eraser();
				cout << "Entre line width (" << profile->lineWidth() << "): ";
				cin >> linew;
				changemode(1);
				if ( cin )
				{
					profile->lineWidth(linew);
					execute(new SetLinesCommand);
				}
				replot = true;
				break;
*/
		}
	}

	changemode(0);

}

void Plot :: execute(Command * cmd)
{
	string command;
	for (int i=0; i<projection.size(); i++)
	{
		command = cmd->execute(projection[i], profile);
	cout << "exec DEBUG 4" << endl;
		projection[i]->projection()->cmd(command);
	cout << "exec DEBUG 5" << endl;
		command = "";
	}
}


void Plot :: optionMenu()
{
	console::consolecolor(console::BLUE);
	cout << "\n" ;
	cout << "\n" ;
	cout << "==============================================================\n" ;
	cout << "  NPLOT  :  " << profile->fileName() << endl;
	cout << "==============================================================\n" ;
	cout << "  Keyboard commands:\n" ;
	cout << "---------------------------------------------------------------\n" ;
	cout << "     arrow up    -  start animation\n" ;
	cout << "     arrow down  -  stop animation or reset to step 0\n" ;
	cout << "     arrow right -  one step forward or speed up animation\n" ;
	cout << "     arrow left  -  one step backward or slow down animation\n" ;
	cout << "---------------------------------------------------------------\n" ;
	cout << "              b  -  change border percentage\n" ;
	cout << "              c  -  toggle tic marks\n" ;
	cout << "              d  -  toggle decoration\n" ;
	cout << "              g  -  toggle grid\n" ;
	cout << "              i  -  set step number\n" ;
	cout << "              l  -  change legend position\n" ;
	cout << "              M  -  make a movie (avi format)\n" ;
	cout << "              r  -  change range (zoom)\n" ;
	cout << "              R  -  reset range\n" ;
	cout << "              s  -  save image (eps format)\n" ;
	cout << "              w  -  set line width\n" ;
	cout << "              q  -  quit\n" ;
	cout << "==============================================================\n" ;
	cout << "\n" ;
	cout << "\n" ;
	console::consolecolor();


}

#include <termios.h>
#include <unistd.h>

void Plot :: changemode(int dir)
{
	static struct termios oldt, newt;
 
	if ( dir == 1 )
	{
		tcgetattr( STDIN_FILENO, &oldt);
		newt = oldt;
		newt.c_lflag &= ~( ICANON | ECHO );
		tcsetattr( STDIN_FILENO, TCSANOW, &newt);
	}
	else
		tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
 

int Plot :: kbhit (void)
{
	struct timeval tv;
	fd_set rdfs;
 
	tv.tv_sec = 0;
	tv.tv_usec = 0;
 
	FD_ZERO(&rdfs);
	FD_SET (STDIN_FILENO, &rdfs);
 
	select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
	return FD_ISSET(STDIN_FILENO, &rdfs);
 
}



