#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include "include/CosiGlobal.h"
#include "include/onchipcommunication/cosi.h"
#include "io/onchipcommunication/ConfigParser.h"

using namespace std;
using namespace cosi::commstruct::onchipcommunication;
using namespace cosi::platforms::onchipcommunication;
using namespace cosi::io::onchipcommunication;
using namespace cosi::environment::onchipcommunication;
using namespace cosi::algorithms::onchipcommunication;

string CosiRoot;
ofstream CosiLog;
ConfigParser* Configuration;

void PrintBanner(ConfigParser* pC, ProjectParser* pP);

int main(int argc, char* argv[]) {

	double ComputationVerificationTime;
	
	if (argc == 1) {
		cout << "Use: "<< endl;
		cout << "CosiNoc.x <projectfile.xml>"<< endl;
		exit(1);
	} else {
	
		clock_t start, finish;
		CosiLog.open("cosilog.txt");
	
		CosiRoot = string(getenv("COSI_ROOT") );
		//Parse configuration
		Configuration = new ConfigParser( CosiRoot + "\\cosiconfig.xml" );
		Configuration->Parse();
	
		//Parse the project
		ProjectParser* Project = new ProjectParser( string( argv[1] ) );
		Project->Parse();
	
		//Parse constraints
		ConstraintParser* Constraints = new ConstraintParser( Project->GetConstraintFileName( ) );
		Constraints->Parse();

		PlacementParser* Placement;

		if (Project->UsePlacement() ) {
	
			Placement = new PlacementParser( Project->GetPlacementFileName( ) , Project->GetSpareArea( ) );
			Placement->Parse();
		} else {
			if ( !Constraints->AllPlaced() ) {
				//Generate Parquet input files
				ParquetBlocksFile(Configuration->GetTmp() + "\\Soc.blocks",
						Constraints->GetIpCore() ,
						Constraints->GetPlacedIpCore() );
				ParquetPlFile(Configuration->GetTmp() + "\\Soc.pl",
						Constraints->GetIpCore() ,
						Constraints->GetPlacedIpCore() );
				ParquetNetsFile(Configuration->GetTmp() + "\\Soc.nets",
						Constraints->GetConstraints() ,
						Constraints->GetPlacedIpCore() );
				ParquetWightsFile(Configuration->GetTmp() + "\\Soc.wts",
						Constraints->GetConstraints() ,
						Constraints->GetPlacedIpCore());

				string ParquetCmdLine;
				//ParquetCmdLine = "export LD_LIBRARY_PATH=";
				//ParquetCmdLine+= Configuration->GetParquetRoot();
				//ParquetCmdLine+=";";
				ParquetCmdLine+= Configuration->GetParquetRoot();
				ParquetCmdLine+="\\" + Configuration->GetParquetExec();
				ParquetCmdLine += " -f " + Configuration->GetTmp() + "\\Soc";
				ParquetCmdLine+=" -minWL -takePl -compact "
						+ Configuration->GetTmp() + "\\Soc.pl -soft -savePl "
						+ Configuration->GetTmp()
						+ "\\Soc_placed > parquetlog.txt";
				system(ParquetCmdLine.c_str() );
			} else {
				Constraints->WritePlacement(Configuration->GetTmp()
						+ "\\Soc_placed.pl");
			}

			Placement = new PlacementParser( Configuration->GetTmp( ) + "\\Soc_placed.pl" , Project->GetSpareArea( ) );
			Placement->Parse();
		}

		Specification* PtP;
		PtP = ToPtPGraph(Constraints , Placement );

		Platform* Plt = new Platform( Placement->GetIpGeometry(), Placement->GetChipGeometry(), 10 , 5e8,32,T90);

		//To Build a star network
		//StarTopologyGeneration* Syn = new StarTopologyGeneration(PtP,Plt) ;
		//Syn->Run() ;

		//PlacementParser* NewPlacement = Syn->GetPlacement();
		//Implementation* I = Syn->GetImplementation() ;

		//This is needed only for the heuristic algorithm
		NocPlatformInterface* NocPlt = Plt->Abstract() ;
		NocPlt->PowerVsArea(Project->GetPowerVsArea() ) ;
		NocPlt->AllowPtP(Project->AllowPtP() ) ;
		NocPlt->AllowTwoHops(Project->AllowTwoHops() ) ;
		NocPlt->AvoidDeadlock(Project->RunTimeDeadlockCheck() ) ;

		//To Build a hierarchical start network
//		HierarchicalNetwork* Hn = new HierarchicalNetwork(PtP,Plt) ;
//		Hn->Run();
//		Implementation* Hi = Hn->GetImplementation() ;
//		PlacementParser* NewPlacement = Hn->GetPlacement();
//		NetworkCost* Nc = new NetworkCost;
//		Nc->Initialize(Hi, NocPlt, Plt) ;
//		Nc->Verify(PtP);
//		Nc->Run();
//
//		AppendRow(Project->GetTabAppendFileName() , Project , NocPlt , Nc ) ;

		//To use the heuristic algorithm in the TCAD paper
//		MFDg* Syn1 = new MFDg;
//		Syn1->Initialize(PtP, NocPlt);
//		Syn1->Run() ;
//		Implementation* MFDg1I = Syn1->GetImplementation(Plt) ;
//
//		MFDg* Syn2 = new MFDg;
//		Syn2->Initialize(PtP, NocPlt);
//		Syn2->Run_2() ;
//		Implementation* MFDg2I = Syn2->GetImplementation(Plt) ;
//

		//To build an optimized mesh
		MeshTopology* Syn3 = new MeshTopology(PtP, Plt);
		Syn3->Run() ;
		PlacementParser* NewPlacement = Syn3->GetPlacement();
		Implementation* MeshI = Syn3->GetImplementation() ;
//
//		NetworkCost* Nc = new NetworkCost;
//		Nc->Initialize(MFDg1I, NocPlt, Plt) ;
//		Nc->Verify(PtP);
//		Nc->Run();
//		AppendRow(Project->GetTabAppendFileName() , Project , NocPlt , Nc ) ;
//		delete Nc;
//		Nc = new NetworkCost;
//		Nc->Initialize(MFDg2I, NocPlt, Plt) ;
//		Nc->Verify(PtP);
//		Nc->Run();
//		AppendRow(Project->GetTabAppendFileName() , Project , NocPlt , Nc ) ;
//		delete Nc;
//		Nc = new NetworkCost;
//		Nc->Initialize(MeshI, NocPlt, Plt) ;
//		Nc->Verify(PtP);
//		Nc->Run();
//		AppendRow(Project->GetTabAppendFileName() , Project , NocPlt , Nc ) ;

		InkscapeCodeGenerator* Ink = new InkscapeCodeGenerator( Project->GetSvgFileName( ) , NewPlacement->GetChipW()*1e6 , NewPlacement->GetChipH()*1e6 );
		Ink->AddForbidden( NewPlacement ) ;
		Ink->PlotCommStruct(MeshI) ;
		Ink->Close() ;

		CosiLog.close();
		exit( 0);

	}
}

