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



Plot :: Plot(Profile profile_) :
	profile(&profile_)
{
	for (int i = 0; i < profile->nProjs(); i++)
	{
		projection.push_back(new Projection(i, profile->argvComp(i)));
		for (int j = 0; j < profile->nComps(); j++)
		{
			projection[i]->addComp(profile->component(j));
		}
		projection[i]->geometry(profile->argvType(i));
		projection[i]->extractArgv();
		if ( profile->argvType(i) == TRIANGLE )
		{
			projection[i]->addCmd(new TriangCommand(projection[i]));
		}
	}
}


void Plot :: eventloop()
{
	if ( profile->verbose() )
	{
		int i;
		cout << endl << "Available projections:" << endl;
		for (i=0; i < projection.size(); i++)
		{
			cout << "    Proj[" << i << "]: " << projection[i]->argvComp() << endl;
			projection[i]->showComps();
		}
		cout << endl;

	}

	console::consolecolor(console::BLUE);
	optionMenu();
	console::consolecolor();

	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);
				optionMenu();
				break;
			case 98: // 'b' - border percentage
				float border;
				console::eraser();
				cout << "Entre border percentage: ";
				changemode(0);
				cin >> border;
				changemode(1);
				if ( cin )
				{
					profile->border(border/100);
					execute(new RangeCommand);
				}
				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 108: // 'l' - change legend position
				execute(new LegendPosCommand);
				replot = true;
				break;
			case 113: // 'q' - quit
				cont = false;
				replot = false;
				break;
			case 114: // 'r' - set range
				int proj;
				changemode(0);
				console::eraser();
				cout << "Enter projection number: ";
				cin >> proj;
				if ( proj >= projection.size() || proj < 0)
				{
					cout << "There's no projection " << proj << "!!" << endl;
					changemode(1);
					break;
				}
				if ( projection[proj]->sRange() )
				{
					projection[proj]->resetSrange();
					execute(new RangeCommand);
				}
				else
				{
					float xmin, xmax, ymin, ymax;
					console::eraser();
					cout << "Entre range [xmin, xmax, ymin, ymax]: ";
					cin >> xmin >> xmax >> ymin >> ymax;;
					if ( cin )
					{
						projection[proj]->setSrange(xmin, xmax, ymin, ymax);
						execute(new RangeCommand);
					}
				}
				replot = true;
				changemode(1);
				break;
			case 115: // 's' - print eps image
				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);
		projection[i]->projection()->cmd(command);
		command = "";
	}
}


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


}

#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);
 
}



