#include <sstream>
#include <fstream>
#include <time.h>

#include "interface.h"
#include "lexan.h"
#include "plalexan.h"

static bool printvals = false;

//==========================================================
//funkce jsou serazeny tak jak by mely byt volany

//incializace - zavolat jednou na zacatku
void init()
{
	measure = false;
	absorbtion = true;
	autoprint = false;
	added_formulas = 0;
	command_str = "";
	treeArray = new TreeArray();
	treeArray->symbNames = new STable();
}


//nacteni PLA - zavolat jednou na vstupni stream
void readpla (istream * input)
{
	 while (analyzepla(input)) {}
	 for (int i=0;i<treeArray->outvars;i++)
	 {
	 	elem = treeArray->find(i);
	 	if (elem == NULL) continue;
	 	if (elem->root == NULL) {elem->root = new VectNode(0,1);}
		symbTable = new STable();
	 	elem->root->createSTable();
	 	elem->symbTable = symbTable;
	 }
}


//nacteni VHDL - zavolat jednou na vstupni stream
void readvhdl (istream * input)
{
	 while (true)
	 {
	 	root = analyze (input);
	 	if (root == NULL) {break;}
	 	treeArray->add(root, symbTable, l_name);
	 }

}

//provedeni operace - lze volat opakovane, parametr option udava typ operace
//druhy parametr je vystupni stream pro ulozeni vysledku
void performOp (int option, ostream * output, int pos, int num, bool val)
{
	 //pro kofaktor
	 /*int pos;
	 int num;
	 bool val;*/
	 
	 istringstream * in_str;
	
	 if ((option > EXIT-1) or (option < 1)) {return;}
	 
	 if (option != SAVEVHDL) {printvals = false;}
	 if (option == SAT) {printvals = true;}
	 
	 //operace mezi vice formulemi
	 if (option == ADDF)
	 {
		cin.ignore();
	 	cout<<"Input command string:";
	 	
	 	command_str = "";
	 	getline(cin,command_str);

	 	//if (isinline) cout<<command_str<<endl;
	 	in_str = new istringstream(&command_str[0]);
	 	root = analyze(in_str);
	 	delete in_str;
	 	
	 	if (root != NULL)
	 	{
	 		symbTable = new STable();
	 		root->createSTable();
	 		treeArray->add(root, symbTable, l_name);
	 		added_formulas++;
	 	}
	 	
	 	return;
	 }
	 
	 
	 if (option == SAVEVHDL)
	 {
	 	printvhdl(output, printvals);
	 	delete output;
	 	output = new ofstream(NULL);
	 	//cout<<"Data saved";
	 	//cout<<endl;
		return;
	 }
	 
	 if (option == SAVEBLIF)
	 {
	 	printblif(*output);
	 	delete output;
	 	output = new ofstream(NULL);
	 	//cout<<"Data saved";
	 	//cout<<endl;
	 	return;
	 }
	 
	 if (option == ABS)
	 {
	 	absorbtion = !absorbtion;
	 	if (absorbtion == true) cout<<"Absorption enabled";
	 	else cout<<"Absorption disabled";
	 	cout<<endl;
		return;
	 }
	 
	 if ( (option == COF) && (num == -1) )
	 {
	 	 cout<<"Enter output variable number:";
	 	 cin>>pos;
	 	 cout<<endl;
		 
	 	 cout<<"Enter input variable number:";
	 	 cin>>num;
	 	 cout<<endl;
	 		   	 		    
	 	 cout<<"Enter input variable value:";
	 	 cin>>val;
	 	 cout<<endl;
	 }
	 
	 
	 //operace se stromem
	 {
		 cout<<endl<<"Operation started"<<endl;
		 gt1 = clock();
		 
		 for (int i=0;i<treeArray->outvars;i++)
		 { 	
		  		elem = treeArray->find(i);
		   		root = elem->root;
		   		symbTable = elem->symbTable;
		   		
		   		if (root == NULL) continue;
		
		   	 	switch (option)
		   	 	{
		   	 		
		   	 		case NEG:
		   	 		{
		   	 			root = root->negate();
		   	 			break;
		   	 		}
		   	 
		   			case AON:
		   			{
		   				root = root->AndOrNot();
		   				root = root->elimNot();
		   				break;
		   			}
		   			
		   			/*case CNF:
		   	 		{
		   	 			root = root->AndOrNot();
		   	 			root = root->elimNot();
		   	 			root = root->simplify();
		   	 			root = root->elimOp(S_OR);
		   	 			break;
		   	 		}*/
		   			
		   	 		case CNF:
		   	 		{
		   	 			root = root->AndOrNot();
		   	 			root = root->elimNot();
		   	 			root = root->simplify();
		   	 		    
		   	 			root = root->negate();
		   	 			root = root->minimize();
		   	 			root = minimalization(root);
		   	 		    elem->terms = treeArray->terms;
		   	 		    root = root->negate();
		   	 			break;
		   	 		}
		   	 
		   	 		case SAVEPLA:
		   	 		case DNF:
		   	 		case SAT:
		   	 		{
		   	 			root = root->AndOrNot();
		   	 			root = root->elimNot();
		   	 			root = root->simplify();
		   	 			//if (root != NULL) root->print(cout);
		   	 			//cout<<endl;
		   	 			root = root->minimize();
		   	 			root = minimalization(root);
		   	 			//root = minimalization(root);
		   	 			elem->terms = treeArray->terms;
		   	 			break;
		   	 		}
		   	 		
		   	 		case NANDF:
		   	 		{
		   	 			root = root->AndOrNot();
		   	 			root = root->simplify();
		   	 			root = root->nandForm();
		   	 			break;
		   	 		}
		   	 		
		   	 		case NORF:
		   	 		{
		   	 			root = root->AndOrNot();
		   	 			root = root->simplify();
		   	 			root = root->norForm();
		   	 			break;
		   	 		}
		   	 		
		   	 		case COF:
		   	 		{
		   	 			if (i == pos) root = root->cofactor(num, val);
		   	 		}
		   	 		//case x:
		   	 		//{
		   	 		//	root = root->rootEval();
		   	 		//	break;
		   	 		//}
		   	 
		   	 		default: {break;}
		   	 		
		   		}//endswitch
		   	 	
		   	 	//if (root != NULL) root->print(cout);
		   	 	//cout<<endl;
		   	 	
		   		elem->root = root; 		
		 }//endfor
	 }
	 gt2 = clock();
	 cout<<"Operation took "<<(difftime(gt2, gt1)/CLOCKS_PER_SEC)<<" seconds"<<endl;
	 cout<<"Operation finished"<<endl<<endl;
	 
	 if (option == SAVEPLA)
	 {
	 	printpla(*output);
	 	delete output;
	 	output = new ofstream(NULL);
	 	//cout<<"Data saved";
	 	//cout<<endl;
	 	return;
	 }
	 
}

//provedeni skriptu
void performScript (istream * script)
{
	added_formulas = treeArray->outvars;
	readvhdl(script);
	added_formulas = treeArray->outvars - added_formulas;
}

//smazani objektu - zavolat na konci
void clean()
{
	delete treeArray;
}
