// BOOM.cpp : Defines the entry point for the console application.

#include "stdafx.h"

#include <time.h>

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

#include "../../Kernel/kernelincludes.h"

#include "Expand.h"
#include "Cover.h"
#include "Reduce.h"

#include "BoomAlg.h"
#include <ctime>

void Help()
{
	cout << "Syntax: boom [options] source.pla dest.[pla | vhdl]" << endl;
	cout << "Options:" << endl;
	cout << "   -i n      Define the number of iterations. 1 is default." << endl;
	cout << "   -CDFC n   Define CD/FC ratio (0-100). 0 is default (only CD-search is run)." << endl;
	cout << "   -CD_m n   Define CD-Search mutation ratio (0-100). 2% is default." << endl;
	cout << "   -DF n     Set FC-Min depth factor (0-99). 50% is default." << endl;
	cout << "   -IE n     Set implicant expansion method:" << endl;
	cout << "                0 - none" << endl;
	cout << "                1 - fast" << endl;
	cout << "                2 - multiple (default)" << endl;
	cout << "                3 - scatter" << endl;
	cout << "                4 - exhaustive (exact)" << endl;
	cout << "   -IR n     Set implicant reduction method:" << endl;
	cout << "                0 - none" << endl;
	cout << "                1 - fast (default)" << endl;
	cout << "                2 - multiple" << endl;
	cout << "                3 - exhaustive (exact)" << endl;
	cout << "   -CP n     Set covering problem solution method:" << endl;
	cout << "                0 - LCMC heuristic (default)" << endl;
	cout << "                1 - Aura-II (exact)" << endl;
	cout << "                2 - Lagrangean heuristic" << endl;
	cout << "                3 - B&B driven by Lagrangean heuristic (exact)" << endl;
	cout << "   -nomin    No minimization is performed, the function is just echoed" << endl;
	cout << "   -check    Perform the consistency check only" << endl; 
}

int main(int argc, char* argv[])
{
    PLA source;
    PLA *dest;
    int i;
	unsigned int j;
 //   time_t tim;
    float t1, t2;
	BoomOpts options;
	BoomAlg *boom;
	char *src_file = NULL;
	char *dest_file = NULL;
	bool nomin = false;
	bool check = false;
	string oformat;

    list<Term>::iterator ti;

	ofstream trialfile;

	cout << "Boom 3.0h, (c) September 2010 by Petr Fiser" << endl;
	if ( argc < 3 ) {
        Help();
        exit(1);
    }
 //   srand((unsigned) time(&tim));
    srand(3);

	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], "-i" ) == 0 ) {
				i++;
				options.SetIterations( atoi(argv[i]) );
			}
			else if ( strcmp( argv[i], "-CDFC" ) == 0 ) {
				i++;
				options.SetCD_FC( atoi(argv[i]) );
			}
			else if ( strcmp( argv[i], "-CD_m" ) == 0 ) {
				i++;
				options.SetCD_mutations( atoi(argv[i]) );
			}	
			else if ( strcmp( argv[i], "-DF" ) == 0 ) {
				i++;
				options.SetDF( atoi(argv[i]) );
			}	
			else if ( strcmp( argv[i], "-IE" ) == 0 ) {
				i++;
				j = atoi(argv[i]);
				switch (j) {
					case 0: options.SetIE(no_IE);
							  break;
					case 1: options.SetIE(fast_IE);
							  break;
					case 2: options.SetIE(multiple_IE);
							  break;
					case 3: options.SetIE(scatter_IE);
							  break;
					case 4: options.SetIE(exhaustive_IE);
							  break;
				}
			}
			else if ( strcmp( argv[i], "-IR" ) == 0 ) {
				i++;
				j = atoi(argv[i]);
				switch (j) {
					case 0: options.SetIR(no_IR);
							  break;
					case 1: options.SetIR(fast_IR);
							  break;
					case 2: options.SetIR(multiple_IR);
							  break;
					case 3: options.SetIR(exhaustive_IR);
							  break;
				}
			}
			else if ( strcmp( argv[i], "-CP" ) == 0 ) {
				i++;
				j = atoi(argv[i]);
				switch (j) {
					case 0: options.SetCP(LCMC);
							  break;
					case 1: options.SetCP(Aura);
							  break;
					case 2: options.SetCP(Lag);
							  break;
					case 3: options.SetCP(BBLag);
							  break;
				}
			}
			else if ( strcmp( argv[i], "-nomin" ) == 0 ) nomin = true;
			else if ( strcmp( argv[i], "-check" ) == 0 ) check = true;
			else {
				Help();
				exit(1);
			}
			i++;
		}
	} catch (...) {
        Help();
        exit(1);
    }

	if ( src_file == NULL || ( dest_file == NULL && !check ) ) {
        Help();
        exit(1);
    }
	if ( !check ) {
		oformat = GetExtension(dest_file);
		if ( stricmp(oformat.c_str(), "pla" ) != 0
			&& stricmp(oformat.c_str(), "vhd" ) != 0
			&& stricmp(oformat.c_str(), "vhdl" ) != 0 ) {
				Help();
				exit(1);
		}
	}

	t1 = GetMyCPUTime();
	
	try {
		source.LoadPLA(src_file);
	} catch (IOException e) {
		cerr << e.GetMsg() << endl;
		exit(1);
	} catch (bad_alloc e) {
		cerr << "Not enough memory" << endl;
		exit(1);
	}

//	source.SaveVHDL(dest_file);
//	exit(0);

	do {
		clock_t start, finish;
		if ( check ) {
			if ( source.isConsistent() ) cout << "PLA is consistent." << endl;
			else cout << "PLA is NOT consistent. OFF-set intersects the ON-set." << endl;
			return 0;
		}
		else if ( !nomin ) {
			boom = new BoomAlg(&source);
			boom->SetOpts(options);

			if ( boom == NULL) throw RuntimeException( "Boom: Not enough memory" );
			boom->SetOpts(options);

			t1 = GetMyCPUTime();
			start = clock();

			try {
				dest = boom->Run();
			} catch (RuntimeException e) {
					cerr << e.GetMsg() << endl;
					exit(1);
			} catch (BoomException e) {
					cerr << e.GetMsg() << endl;
					exit(1);
			} catch (bad_alloc e) {
				cerr << "Not enough memory" << endl;
				exit(1);
			}
		} else {
			dest = new PLA(source);
			boom = NULL;
		}

		t2 = GetMyCPUTime();
		finish = clock();
		
		cout << "CPU time: " << (t2-t1) << " s" << endl;
		cout << "Wall clock time: " << double(finish -start) / CLOCKS_PER_SEC << " s" << endl;
		cout << "Result terms: " << dest->getTerms() << endl;
		cout << "Result literals: " << dest->getLiterals() << endl;
		cout << "Result output cost: " << dest->getOC() << endl;
		cerr << (t2-t1) << "; " << dest->getTerms() << "; " << dest->getLiterals() << "; " << dest->getOC() << endl;
		trialfile.open("trials.csv", ios::app);
		trialfile << GetMyCPUTime()-t1 << "; ";
		trialfile << dest->getTerms() << endl;
		trialfile.close();
		
		if ( stricmp(oformat.c_str(), "pla" ) == 0 ) dest->SavePLA(dest_file);
		else if ( stricmp(oformat.c_str(), "vhd" ) == 0 || stricmp(oformat.c_str(), "vhdl" ) == 0 ) dest->SaveVHDL(dest_file);
		delete dest;
		delete boom;
	} while (false);
//	trialfile.close();

	return 0;
}
