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

#include "stdafx.h"

using namespace std;

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

int main(int argc, char* argv[])
{
    PLA source;
    PLA *dc = NULL, *dc1 = NULL, *dc2 = NULL, *res = NULL;
	unsigned int i, j, p;
	TermList::iterator ti;
	unsigned int method;

    cerr << "Strip_udc 1.1, (c) January 2009 by Petr Fiser" << endl << endl;
    if ( argc < 4 ) {
		cout << "Syntax: Strip_udc [-keep] source.pla stripped.pla dc.pla" << endl;
		cout << "Syntax: Strip_udc [-off] source.pla stripped.pla dc.pla" << endl;
		cout << "Syntax: Strip_udc [-on] source.pla stripped.pla dc.pla" << endl;
		exit(1);
    }

	if ( strcmp(argv[1], "-off") == 0 ) method = 2;
	else if ( strcmp(argv[1], "-on") == 0 ) method = 3;
	else if ( strcmp(argv[1], "-keep") == 0 ) method = 1;
	else method = 0;
	if ( method > 0 ) p = 2; else p = 1;

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

	if ( !source.getType().f || !source.getType().d || !source.getType().r ) {
		cout << "PLA must be type fdr" << endl;
		exit(1);
	}

	source.setType(PLA_type("fr"));
	dc = new PLA( source.inputs(),  source.outputs(), PLA_type("fd") );
	if ( dc == NULL) throw RuntimeException( "Strip_udc: Not enough memory" );
	dc1 = new PLA( source.inputs(),  source.outputs(), PLA_type("fd") );
	if ( dc1 == NULL) throw RuntimeException( "Strip_udc: Not enough memory" );
	dc2 = new PLA( source.inputs(),  source.outputs(), PLA_type("fd") );
	if ( dc2 == NULL) throw RuntimeException( "Strip_udc: Not enough memory" );

	if ( method < 2 ) {
		for ( ti = source.getData()->begin(); ti != source.getData()->end(); ti++ ) {
			for ( i = 0; i < source.outputs(); i++ )
				if ( !(*ti).isOM_dc(i) ) break;
			if ( i == source.outputs() ) {
				if ( method != 1 ) (*ti).setUnwanted();
				dc->AppendTerm(*ti);
			}
		}
		if ( method != 1 ) source.Purge();
		source.SavePLA(argv[p+1]);
	}
	else {
		for ( ti = source.getData()->begin(); ti != source.getData()->end(); ti++ ) {
			for ( i = 0; i < source.outputs(); i++ )
				if ( !(*ti).isOM_dc(i) ) break;
			if ( i == source.outputs() ) {
				dc->AppendTerm(*ti);
				for ( j = 0; j < source.outputs(); j++ )
					(*ti).setOM_0(j);
				dc1->AppendTerm(*ti);
				for ( j = 0; j < source.outputs(); j++ )
					(*ti).setOM_1(j);
				dc2->AppendTerm(*ti);
				(*ti).setUnwanted();
			}
		}
		source.Purge();
		res = PLA_op().Sharp(source, *dc2);
		if ( method == 2) res->Splice(*dc1);
		else if ( method == 3) res->Splice(*dc2);
		res->SavePLA(argv[p+1]);
	}
	
	dc->SavePLA(argv[p+2]);

	delete dc;
	delete dc1;
	delete dc2;
	delete res;

    return 0;
}
