#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdlib.h>
#include <Profile.h>
#include <getopt.h>
#include <string.h>


Profile :: Profile(int argc, char **argv)
{
	int opt;

	fileName_ = "";
	title_ = "";

	nComps_ = 0;
	nSteps_ = 0;
	gridSize_ = 0;

	index_ = 0;
	legendPos_ = 0;
	decoration_ = true;
	grid_ = false;
	verbose_ = false;
	debug_ = false;
	border_ = 0.00;
	lineWidth_ = 1.5;

	while ((opt = getopt (argc, argv, "i:p:t:c:vdh")) != EOF)
	{
		switch (opt)
		{
		case 'i':			// input file
			fileName_ = optarg;
			break;
		case 'p':			// projection
			argvComps_.push_back(optarg);
			argvTypes_.push_back(PROJECTION);
			break;
		case 't':			// triangular projection
			argvComps_.push_back(optarg);
			argvTypes_.push_back(TRIANGLE);
			break;
		case 'c':			// color
			extractColors(optarg);
			break;
		case 'v':			// verbose
			verbose_ = true;
			break;
		case 'd':			// debug
			debug_ = true;
			break;
		case 'h':			// help
			printUsage (EXIT_SUCCESS);
			break;
		case '?':
			if (optopt == 'i' || optopt == 'p' || optopt == 'm' || isprint (optopt))
			{
				printUsage (EXIT_FAILURE);
			}
		}
	}

	if ( argvComps_.size() == 0 )
	{
		cerr << "Please, enter at least on projection to plot." << endl;
		printUsage(EXIT_FAILURE);
	}

	if ( argvColors_.size() == 0 )
	{
		extractColors("green:blue:red:purple:yellow:pink:lightblue");
	}

	if ( readFile() )
	{
		cerr << "Wrong file format - '" << fileName_ << "'" << endl;
		printUsage(EXIT_FAILURE);
	}

	if ( verbose_ )
	{
		cout << endl;
		cout << "Input data file name: " << fileName_ << endl;
		cout << "Title: " << title_ << endl;
		cout << "Grid size: " << gridSize_ << endl;
		cout << "No components: " << nComps_ << endl;
		cout << "No projection: " << argvComps_.size() << endl;
		for ( int i = 0; i < argvComps_.size(); i++ )
		{
			cout << "    Projection components " << i << ": " << argvComps_[i] << endl;
		}
		cout << endl;
		cout << endl;
	}
}


int Profile :: extractComponents (void)
{
	FILE *inputFile = fopen ( fileName_.c_str(), "r" );

	bool reading = true;
	char ch, buffer[1024], title[50];
	char *line, *str;
	int info = 0, value, i;


	if ( inputFile != NULL )
	{
		while (reading)
		{
			ch = fgetc (inputFile);
			if (ch == 10) // return character
			{
				ch = fgetc (inputFile);
				if (ch == 10) reading = false; // if return character again stop reading
			}

			// Extract plot informations: components, number of plots and grid dimension
			if ( ch == 58 && info < 5 ) // ':' character
			{
				if ( info == 0 )
					fscanf (inputFile, "%s", title);
				else
					fscanf (inputFile, "%d", &value);
				switch (info) 
				{
				case 0: // Physics name
					info++;
					//strcpy (title_, title);
					title_ = title;
					break;
				case 1: // Componentes
					info++;
					nComps_ = value;
					break;
				case 2: // Plot steps
					info++;
					nSteps_ = value;
					break;
				case 3: // Grid size
					info++;
					gridSize_ = value;
					break;
				case 4: // Line that preceds the list of component informations
					info++;
					break;
				}
			}
		
			// Extract component informations
			if ( ch == 58 && info == 5 ) // start reading component informations
			{
				for (i = 0; i < nComps_; i++)
				{
					line = fgets (buffer, sizeof (buffer), inputFile);
					str = strtok (line, ":");		// first entry is an unused comment 
					str = strtok (NULL, ":");		// component name

					string compName(str);
					float min = atof (strtok (NULL, ":"));
					float max = atof (strtok (NULL, ":"));

					inputComps_.push_back(new Component(compName, min, max, argvColors_[i]));
				}
			}
		}

		fclose ( inputFile );
	}
	else
	{
		cout << "ERROR opening file: " <<  fileName_ << endl; 
	}

	if ( verbose_ ) 
	{
		cout << "Title: " << title_ << endl;
		cout << "Componentes:  " << nComps_ << endl;
		cout << "Plot steps: " << nSteps_ << endl;
		cout << "Grid size: " << gridSize_ << endl << endl;

		for (i = 0; i < nComps_; i++)
		{
			cout << "Component Object " << i+1 << endl;
			cout << "   Name: " << inputComps_[i]->name() << endl;
			cout << "   Min: " << inputComps_[i]->min() << endl;
			cout << "   Max: " << inputComps_[i]->max() << endl;
		}
		cout << endl;
	}

	return 0;
}


void Profile :: extractColors(string c)
{
	// Strip color names
	stringstream ss (c);

	while ( ss.good() )
	{
		string substr;
		getline (ss, substr, ':');
		argvColors_.push_back(substr);
	}
}


//-------------------------------------------


int Profile :: readFile()
{
	vector <string> fileStr;
	string str;

	extractComponents();

/* 
	THIS CODE WILL BE USED TO READ THE ROLE CONTENT OF THE INPUT FILE SO
	GNUPLOT WILL RECEIVE THE CURVE COORDS NOT THE INPUT FILE ITSELF.

	ifstream In(fileName_.c_str());

	while ( ! In.eof() )
	{
		getline (In, str);
		fileStr.push_back(str);
	}
*/

	return 0;
}


string Profile :: fileName()
{
	return fileName_;
}


string Profile :: title()
{
	return title_;
}


string Profile :: argvComp(int i)
{
	return argvComps_[i];
}


argvOpt Profile :: argvType(int i)
{
	return argvTypes_[i];
}


int Profile :: nProjs()
{
	return argvComps_.size();
}


vector <Component *> & Profile :: inputComps(void)
{
	return inputComps_;
}


Component * Profile :: inputComp(int i)
{
	return inputComps_[i];
}


int Profile :: nComps()
{
	return nComps_;
}


int Profile :: nSteps()
{
	return nSteps_;
}


int Profile :: gridSize()
{
	return gridSize_;
}


int Profile :: index()
{
	return index_;
}


int Profile :: legendPos()
{
	return legendPos_;
}


string Profile :: legend()
{
	switch (legendPos_) {
	case 0:
		return "right";
		break;
	case 1:
		return "left";
		break;
	case 2:
		return "off";
		break;
	}
}


bool Profile :: decoration()
{
	return decoration_;
}


bool Profile :: grid()
{
	return grid_;
}


bool Profile :: verbose()
{
	return verbose_;
}


bool Profile :: debug()
{
	return debug_;
}


float Profile :: border()
{
	return border_;
}


float Profile :: lineWidth()
{
	return lineWidth_;
}


void Profile :: index(int i_)
{
	index_ = i_;
}


void Profile :: decoration(bool d_)
{
	decoration_ = d_;
}


void Profile :: grid(bool g_)
{
	grid_ = g_;
}


void Profile :: border(float b_)
{
	border_ = b_;
}


void Profile :: lineWidth(float b_)
{
	lineWidth_ = b_;
}


void Profile :: toggleLegend()
{
	legendPos_ += 1;
	if ( legendPos_ > 2 )
		legendPos_ = 0;
}


void Profile :: toggleDecoration()
{
	if ( decoration_ )
		decoration_ = false;
	else
		decoration_ = true;
}


void Profile :: toggleGrid()
{
	if ( grid() ) 
	{
		cout << "- GRID ON()" << endl;
	}
	else
	{
		cout << "- GRID OFF()" << endl;
	}


	if ( grid_ )
		grid_ = false;
	else
		grid_ = true;
}


void Profile :: toggleVerbose()
{
	if ( verbose_ )
		verbose_ = false;
	else
		verbose_ = true;
}


void Profile :: printUsage(int exitCode = -1)
{
	cerr << "\n    Usage: %s -i <data-file> [-p <components>] [-t <components>] [...] \n\n";

	if ( exitCode != -1 )
		exit(exitCode);

}


string Profile :: frame(int i)
{
	return frame_[i];
}


