#include "stdafx.h"

#include <time.h>

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

#include "../../Kernel/kernelincludes.h"
#include "../../Multilevel/Blif.h"
#include "../../Multilevel/Node.h"
#include "../../Multilevel/Signal.h"
#include "../../Multilevel/Network.h"

#include "Resynthesis.h"

void Help()
{
	cout << "Syntax: Multilevel_resynth source.blif dest.blif" << endl;
	cout << "Options:" << endl;
	cout << "  -m x        Select the window selection method:" << endl;
	cout << "                  0 = random (default)" << endl;
	cout << "                  1 = minimize fanin" << endl;
	cout << "                  2 = minimize fanout" << endl;
	cout << "                  3 = minimize sum of fanin and fanout" << endl;
	cout << "                  4 = radius select" << endl;
	cout << "                  5 = imfs-like windowing" << endl;
	cout << "  -size n     How large windows are resynthesized (for -m 4 and 5). Infinity is default" << endl;
	cout << "  -sizelimit  The window size limit. Constant number of nodes, if >1, percentage of the circuit otherwise. 1 is default" << endl;
	cout << "  -impr x     Only better results are accepted. Opt. crit.: 0 = nodes (default), 1 = literals" << endl;
	cout << "  -c n        Number of cycles (infinite is default)" << endl;
}

int main(int argc, char* argv[])
{
    Blif source;
    Blif *dest;
    int i;
	char *src_file = NULL;
	char *dest_file = NULL;
	time_t tim;
	Network *net;
	float t, t1, t2;
	Resynthesis *engine;
	ofstream dump;
	bool impr = false;
	float sizelimit = 1;
	unsigned int method = 0;
	unsigned int cycles = UINT_MAX;
	unsigned int optcrit = 0;
	unsigned int cyc;
	unsigned int size = UINT_MAX;

	cout << "Multilevel-Resynth 2.1, (c) October 2010 by Petr Fiser" << endl;
	if ( argc < 3 ) {
        Help();
        exit(1);
    }
//    srand((unsigned) time(&tim));
    srand(3);

	t = GetMyCPUTime();
	t2 = 0;
	t1 = 0;

	try {
		i = 1;
		while ( i != argc ) {
			if ( argv[i][0] != '-' && src_file == NULL ) src_file = argv[i];
			else if ( argv[i][0] != '-' ) dest_file = argv[i];

			else if ( strcmp( argv[i], "-m" ) == 0 ) {
				i++;
				method =  atoi(argv[i]);
			}
			else if ( strcmp( argv[i], "-sizelimit" ) == 0 ) {
				i++;
				sizelimit =  (float)atof(argv[i]);
			}
			else if ( strcmp( argv[i], "-size" ) == 0 ) {
				i++;
				size =  atoi(argv[i]);
			}
			else if ( strcmp( argv[i], "-c" ) == 0 ) {
				i++;
				cycles =  atoi(argv[i]);
			}
			else if ( strcmp( argv[i], "-impr" ) == 0 ) {
				impr = true;
				i++;
				optcrit =  atoi(argv[i]);
			}

			else {
				Help();
				exit(1);
			}
			i++;
		}
	} catch (...) {
        Help();
        exit(1);
    }

	if ( src_file == NULL || dest_file == NULL ) {
        Help();
        exit(1);
    }

	try {
		source.LoadBlif(src_file);
	} catch (IOException e) {
			cerr << e.GetMsg() << endl;
			exit(1);
	}

	net = new Network(source);

	engine = new Resynthesis( net );
	engine->SetMethod(method);
	engine->SetImpr(impr);
	engine->SetOptCrit(optcrit);
	engine->SetSize(size);
	engine->SetSizeLimit(sizelimit);

	
	dump.open("debug.csv");
	cyc = 0;
	dump << "cycle; nodes; literals; levels; cut_fanin; cut_fanout; real_fanin_radius; real_fanout_radius; cut_nodes; resyn_cut_nodes; accepted; time" << endl;
//	try {

		do {
			dump << cyc++ << "; " << net->GetNodes() << "; " << net->getLiterals() << "; " << net->GetLevels() << "; "<< engine->GetFanin() << "; " << engine->GetFanout() << "; " << engine->GetRealFaninRadius() << "; " << engine->GetRealFanoutRadius() << "; " << engine->GetCutSize() << "; " << engine->GetResynthSize() << "; " << engine->GetAccept() << "; " << t2-t1 << endl;
			t1 = GetMyCPUTime();
	        engine->Run();
			net = engine->GetNetwork();
	//		net->SaveMBlif( "o_multi.mblif" );
	//		net->ToSingleOutput();
	//		net->SaveMBlif( "o.mblif" );
			dest = net->ToBlif();
			dest->SaveBlif(dest_file);
			delete dest;
			t2 = GetMyCPUTime();
		} while (cycles--);
		dump.close();
/*	} catch (IOException e) {
			cerr << e.GetMsg() << endl;
			exit(1);
	} catch (RuntimeException e) {
			cerr << e.GetMsg() << endl;
			exit(1);
	}
*/
//	net->SaveMBlif( "o.mblif" );
	

	cout << GetMyCPUTime() - t << " s" << endl;

	return 0;
}
