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

#include "stdafx.h"

#include <time.h>

using namespace std;

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

void help()
{
  fprintf( stderr, "syntax: swap options source destination\n" );
  fprintf( stderr, "Options:\n" );
  fprintf( stderr, "    -onoff: Swap on-set and off-set of PLA f[d]r type\n" );
  fprintf( stderr, "    -onoffgr: Swap on-set and off-set of PLA f[d]r type. The swapped off-set is appended to the function\n" );
}

PLA *SwapOnOff( PLA *src )
{
	PLA *dest;
	TermList::iterator ti;
	Term newterm;
	unsigned int i;

	dest = new PLA( src );
	if ( dest == NULL) throw RuntimeException( "Swap: Not enough memory" );
	for ( ti = src->getData()->begin(); ti != src->getData()->end(); ti++ ) {
		newterm.setCube( (*ti).getCube() );
		newterm.setOM( ti->getOM() );
		for ( i = 0; i < src->outputs(); i++ )
			if ( newterm.isOM_0(i) ) newterm.setOM_1(i);
			else if ( newterm.isOM_1(i) ) newterm.setOM_0(i);
			dest->AppendTerm(newterm);
	}
	return dest;
}

PLA *SwapOnOffGr( PLA *src )
{
	PLA *dest;
	TermList::iterator ti;
	Term newterm;
	string oterm;
	unsigned int i;

	dest = new PLA( src->inputs(), src->outputs()*2, src->getType() );
	if ( dest == NULL) throw RuntimeException( "Swap: Not enough memory" );
	for ( ti = src->getData()->begin(); ti != src->getData()->end(); ti++ ) {
		newterm.setCube( (*ti).getCube() );
		oterm.resize(src->outputs()*2);
		for ( i = 0; i < src->outputs(); i++ ) {
			oterm[i] = (*ti).getOM(i);
			oterm[src->outputs()+i] = (*ti).getOM(i);
		}
		newterm.setOM(oterm);
		for ( i = 0; i < src->outputs(); i++ )
			if ( (*ti).isOM_0(i) ) newterm.setOM_1(src->outputs()+i);
			else if ( (*ti).isOM_1(i) ) newterm.setOM_0(src->outputs()+i);
			else newterm.setOM(src->outputs()+i, (*ti).getOM(i));
			dest->AppendTerm(newterm);
	}
	return dest;
}



int main(int argc, char* argv[])
{
    PLA source;
    PLA *dest;
	unsigned int op;

    list<Term>::iterator ti;

    cerr << "PLA Swap 2.1, (c) January 2009 by Petr Fiser" << endl << endl;
    if ( argc != 4 ) {
      help();
      exit(1);
    }
    if ( strcmp(argv[1], "-onoff" ) == 0 ) op = 1;
    else if ( strcmp(argv[1], "-onoffgr" ) == 0 ) op = 2;
    else {
      help();
      exit(1);
    }

    try {
        source.LoadPLA(argv[2]);
    } catch (IOException e) {
            cerr << e.GetMsg() << endl;
            exit(1);
    }

	switch (op) {
      case 1: dest = SwapOnOff( &source );
              break;
      case 2: dest = SwapOnOffGr( &source );
              break;
	  default: dest = NULL;
    }
	dest->SavePLA(argv[3]);
    delete dest;

    return 0;



}

