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

#include "stdafx.h"

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

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

void help()
{
	cout << "Syntax: GetInfo [-dual] options source.pla [source2.pla]" << endl;
	cout << "    -dual   Process two PLAs, merging duplicate terms" << endl;
	cout << "    -useful Computes number of terms and literals for usefull terms only (no all-output DC)" << endl;
	cout << "    PLA information will be shown in the order of specified options:" << endl;
	cout << "       n - source file name" << endl;
	cout << "       i - # of inputs" << endl;
	cout << "       o - # of outputs" << endl;
	cout << "       t - # of terms" << endl;
	cout << "       l - # of literals" << endl;
	cout << "       O - output cost" << endl;
	cout << "       g - gate equivalents" << endl;
	cout << "       s - shared terms (in case of -dual)" << endl;
	cout << endl;
	cout << "Syntax: GetInfo source.blif" << endl;
	cout << "    Blif information will be shown in the order of specified options:" << endl;
	cout << "       n - source file name" << endl;
	cout << "       i - # of inputs" << endl;
	cout << "       o - # of outputs" << endl;
	cout << "       g - # of nodes" << endl;
	cout << "       l - # of literals" << endl;
	cout << "       L - # of levels" << endl;
}

PLA *JoinPLAsByInputs( PLA &pla1, PLA &pla2 )
// Joins two PLAs. Input matrices are merged, the resulting output matrix is extended
{
	PLA *res;
	TermList::iterator ti, ti2;
	Term t;
	unsigned int i;
	string om;

	if ( pla1.inputs() != pla2.inputs() || pla1.getType() != pla2.getType() ) throw RuntimeException( "PLA_operations::JoinPLAsByInputs: incompatible PLAs" );

	res = new PLA(pla1.inputs(), pla1.outputs()*2, pla1.getType());
	if ( res == NULL) throw RuntimeException( "PLA_operations: Not enough memory" );
	for ( ti = pla1.getData()->begin(); ti != pla1.getData()->end(); ti++ ) {
		om = (*ti).getOM();
		for ( i = 0; i < pla2.outputs(); i++ ) om += '~';
		t.setCube(ti->getCube());
		t.setOM(om);
		res->AppendTerm(t);
	}
	for ( ti = pla2.getData()->begin(); ti != pla2.getData()->end(); ++ti ) {
		ti2 = res->FindTerm((*ti).getCube());
		if ( ti2 == res->getData()->end() ) {
			om.clear();
			for ( i = 0; i < pla1.outputs(); i++ ) om += '~';
			om += (*ti).getOM();
			t.setCube(ti->getCube());
			t.setOM(om);
			res->AppendTerm(t);
		}
		else 
			for ( i = 0; i < pla2.outputs(); i++ )
				(*ti2).setOM(pla1.outputs()+i, (*ti).getOM(i));
	}
	return res;
}

int main(int argc, char* argv[])
{
    PLA source1, source2;
	Blif blif;
	char options[100];
	unsigned int i;
	int j;
	unsigned int opts = 0;
	bool dual = false;
	bool flag;
	bool usefull = false;
	PLA *src2;
	string tmp, ext;

	cerr << "GetInfo 2.4, (c) October 2010 by Petr Fiser" << endl << endl;
    if ( argc < 3 ) {
		help(); 
		exit(1);
    }

	for ( i = 0; i < 5; i++ ) options[i] = 0;
	j = 1;
	do {
		if ( strcmp( argv[j], "-dual" ) == 0 ) {
			dual = true;
			j++;
		}
		else if ( strcmp( argv[j], "-useful" ) == 0 ) {
			usefull = true;
			j++;
		}
		else break;
	} while (true);

	for ( i = 0; i < strlen(argv[j]); i++ )
		switch (argv[j][i]) {
			case 'n': options[opts++] = 'n';
				break;
			case 't': options[opts++] = 't';
				break;
			case 'l': options[opts++] = 'l';
				break;
			case 'o': options[opts++] = 'o';
				break;
			case 'O': options[opts++] = 'O';
				break;
			case 'g': options[opts++] = 'g';
				break;
			case 'L': options[opts++] = 'L';
				break;
			case 'i': options[opts++] = 'i';
				break;
			case 's': if ( !dual ) {
						help();
						exit(1);
					  }
				options[opts++] = 's';
				break;
			default:
				help();
				exit(1);
		}
	
	tmp = argv[j+1];
	ext = tmp.substr(tmp.find_last_of("."), tmp.size() - tmp.find_last_of("."));
	if ( ext == ".pla" ) {
		try {
			source1.LoadPLA(argv[j+1]);
			if (dual) source2.LoadPLA(argv[j+2]);
		} catch (IOException e) {
				cerr << e.GetMsg() << endl;
				exit(1);
		}

		if (dual)
			src2 = JoinPLAsByInputs(source1, source2);
		else src2 = &source1;

		if (usefull) src2->RemoveUselessTerms();

		flag = false;
		for ( i = 0; i < opts; i++ ) {
			if (flag) cout << "; ";
			switch ( options[i] ) {
				case 'n': cout << argv[j+1];
					break;
				case 't': cout << src2->getTerms();
					break;
				case 'i': cout << src2->inputs();
					break;
				case 'o': cout << src2->outputs();
					break;
				case 'l': cout << src2->getLiterals();
					break;
				case 'O': cout << src2->getOC();
					break;
				case 'g': cout << src2->getGEs();
					break;
				case 's': cout << source1.getTerms()+source2.getTerms()-src2->getTerms();
					break;
				default:
					help();
					exit(1);
			}
			flag = true;
		}
	} else if ( ext == ".blif" ) {
		try {
			blif.LoadBlif(argv[j+1]);
		} catch (IOException e) {
				cerr << e.GetMsg() << endl;
				exit(1);
		}
		flag = false;
		for ( i = 0; i < opts; i++ ) {
			if (flag) cout << "; ";
			switch ( options[i] ) {
				case 'n': cout << argv[j+1];
					break;
				case 'i': cout << blif.inputs();
					break;
				case 'o': cout << blif.outputs();
					break;
				case 'g': cout << blif.GetNodes();
					break;
				case 'l': cout << blif.getLiterals();
					break;
				case 'L': cout << blif.GetLevels();
					break;
				default:
					help();
					exit(1);
			}
			flag = true;
		}	}

	cout << endl;


    return 0;
}
