//---------------------------------------------------------------------------

#include "stdafx.h"

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

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

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

#include "defaults.h"
//#include "TimeStamp.h"
#include "BoomAlg.h"
//---------------------------------------------------------------------------

BoomOpts::BoomOpts(void)
{
	CD_FC = DEFAULT_CD_FC;
	iterations = DEFAULT_iterations;
	CD_mutations = DEFAULT_CD_MUTATIONS;
	CD_implcheck = DEFAULT_CD_IMPLCHECK;
	IE = DEFAULT_IE;
	IR = DEFAULT_IR;
	DF = DEFAULT_DF;
}

BoomAlg::BoomAlg(void)
{
	implpool = NULL;
	FC_pool = NULL;
	result = NULL;
}

BoomAlg::BoomAlg( PLA *_pla )
{
    source = _pla;
    result = NULL;
	implpool = new PLA( source->GetInputs(), source->GetOutputs(), PLA_type("f") );
	if ( implpool == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
    implpool->SetUnique();
	// implpool->KeepTT();		// slows it down (?)
	FC_pool = new PLA( source->GetInputs(), source->GetOutputs(), PLA_type("f") );
	if ( FC_pool == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
//    FC_pool->SetUnique();
//	FC_pool->KeepTT();
}

BoomAlg::~BoomAlg(void)
{
	delete implpool;
}

PLA *BoomAlg::Run(void)
{
    CD_Search *CDS_alg = NULL;
	FC_Min *FC_alg = NULL;
	Expand *IE_alg = NULL;
	Expand *IE_FC_alg = NULL;
	Reduce *IR_alg = NULL;
	Cover *CP_alg = NULL;
	unsigned int it;
	PLA *sol;

	// initialize algorithms
	if ( options.CD_FC != 100 ) {
		CDS_alg = new CD_Search( source, implpool );
		if ( CDS_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
	}
	if ( options.CD_FC != 0 ) {
		FC_alg = new FC_Min( source, FC_pool );
		if ( FC_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		FC_alg->SetDF(options.DF);
		IE_FC_alg = new Expand( source, FC_pool );
		if ( IE_FC_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		IE_FC_alg->SetMethod(scatter_IE);
	}
	if ( options.IE != no_IE ) {
		IE_alg = new Expand( source, implpool );
		if ( IE_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		IE_alg->SetMethod(options.IE);
	}
	if ( options.IR != no_IR ) {
		IR_alg = new Reduce( source, implpool );
		if ( IR_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );
		IR_alg->SetMethod(options.IR);
	}
	CP_alg = new Cover( source, implpool );
	if ( CP_alg == NULL) throw RuntimeException( "BoomAlg: Not enough memory" );

	// Run CD-S and FC-Min
	for ( it = 0; it < options.iterations; it++ ) {
		if ( rand() % 100 >= (int)options.CD_FC ) CDS_alg->Run();
		else {
			FC_alg->Run();
			IE_FC_alg->Run();
			implpool->Splice( *FC_pool );
		}
	}
//	implpool->SavePLA("implpool.pla");

	// Reductions, Expansions, CP
	if ( options.IE != no_IE ) IE_alg->Run();

	CP_alg->GenerateOM();
	implpool->RemoveAbsorbed();

	if ( options.IR != no_IR ) IR_alg->Run();

	CP_alg->RemoveAbsorbedByCover();

//	implpool->SavePLA( "implpool.pla" );
//	implpool->DumpOrigin( "pool_origin.csv" );

	sol = CP_alg->Run();
	CP_alg->Sparse_output(sol);

//	TS.DumpTimeStamps("timestamps.txt");

//	sol->DumpOrigin( "sol_origin.csv" );

	delete CP_alg;
	delete IR_alg;
	delete IE_alg;
	delete IE_FC_alg;
	delete FC_alg;
	delete CDS_alg;
    
	return sol;
}

