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

#include "stdafx.h"

using namespace std;

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

#include "../../Multilevel/Blif.h"
#include "../../Multilevel/Node.h"
#include "../../Multilevel/Signal.h"
#include "../../Multilevel/network.h"

int main(int argc, char* argv[])
{
    PLA source;
    PLA *dest;
	unsigned int i, j;
	TermList::iterator ti;
	Term t;
	string name, destname;
	char s[100];
	string ext;
	Blif blif_source;
	Network *net;
	Blif *bliffile;
	Network *dest_net;
	queue< list<Node>::iterator > node_queue;
	pair<bool, list<Signal>::iterator> findres;
	list<Node>::iterator ni;


    cerr << "Split Outputs 2.0, (c) July 2010 by Petr Fiser" << endl << endl;
    if ( argc != 2 ) {
		cout << "Syntax: split_outputs [source.pla | source.blif]" << endl;
		exit(1);
    }

	ext = GetExtension(argv[1]);
	if ( ext == "pla" ) {
		try {
			source.LoadPLA(argv[1]);
		} catch (IOException e) {
				cerr << e.GetMsg() << endl;
				exit(1);
		}
		name = string(argv[1]).substr(0, string(argv[1]).find_last_of(".", string(argv[1]).size()));
		
		for ( i = 0; i < source.outputs(); i++ ) {
			dest = new PLA( source.inputs(), 1, PLA_type("fd") );
			for ( ti = source.getData()->begin(); ti != source.getData()->end(); ti++ )
				if ( !(*ti).isOM_undef(i) ) {
					t.setCube((*ti).getCube());
					if ( ti->isOM_1(i) ) t.setOM("1");
					else t.setOM("-");
					dest->AppendTerm(t);
				}
			destname = name;
			_itoa_s(i, s, 10);
			destname += "_";
			destname += s;
			destname += ".pla";
			dest->SavePLA(destname.c_str());
			delete dest;
		}
	} else if ( ext == "blif" ) {
		try {
			blif_source.LoadBlif(argv[1]);
		} catch (IOException e) {
				cerr << e.GetMsg() << endl;
				exit(1);
		}
		net = new Network(blif_source);
		name = string(argv[1]).substr(0, string(argv[1]).find_last_of(".", string(argv[1]).size()));
		
		for ( i = 0; i < net->outputs(); i++ ) {
			dest_net = new Network();	
			findres = net->FindSignal(net->getOName(i));
			if ( !findres.first ) throw RuntimeException( "Output gate not found" );
			if ( findres.second->IsPI() ) continue;
			node_queue.push( findres.second->GetSource()->first );
			while ( !node_queue.empty() ) {
				ni = node_queue.front();
				node_queue.pop();
				if ( dest_net->IsGate( ni->getData()->getOName(0)) ) continue;
				dest_net->AddNode(*ni);
				for ( j = 0; j < ni->inputs(); j++ ) {
					findres = net->FindSignal( ni->getData()->getIName(j) );
					if ( !findres.first ) throw RuntimeException( "Gate not found" );
					if ( !findres.second->IsPI() ) node_queue.push( findres.second->GetSource()->first );
				}
			}
			dest_net->DerivePorts();

			destname = name;
			_itoa_s(i, s, 10);
			destname += "_";
			destname += s;
			destname += ".blif";
			bliffile = dest_net->ToBlif();
			bliffile->SaveBlif(destname.c_str());
			delete bliffile;
			delete dest_net;
		}
		delete net;
	}

    return 0;



}

