#include "BistProblem.h"
#include "Logger.h"

const unsigned int BistProblem::ITERATIONS = 1000u;
const AlleleType BistProblem::NUM_ALLOWED_RULES = static_cast<AlleleType>( 4 );

BistProblem::BistProblem( std::string filename ) :
    ProblemDomain(), tv( filename ),
    fitnessFactor( static_cast<FloatType>( 1.0 ) / static_cast<FloatType>( tv.getRows() ) ),
    ruleLUT( NULL ) {
  if ( tv.isGood() ) {
    numberOfGenes = tv.getCols() * 2u;
    numberOfAlleles = new AlleleType[numberOfGenes];
    for ( unsigned int locus = 0u; locus < numberOfGenes; locus += 2u ) {
      numberOfAlleles[locus] = static_cast<AlleleType>( 2 );
      numberOfAlleles[locus+1u] = NUM_ALLOWED_RULES;
    }
    if ( NUM_ALLOWED_RULES < static_cast<AlleleType>( 256 ) ) {
      ruleLUT = new AlleleType[NUM_ALLOWED_RULES];
      ruleLUT[0] = static_cast<AlleleType>( 60 );
      ruleLUT[1] = static_cast<AlleleType>( 90 );
      ruleLUT[2] = static_cast<AlleleType>( 150 );
      ruleLUT[3] = static_cast<AlleleType>( 240 );
    }
  }
}

BistProblem::~BistProblem() {
  if ( ruleLUT )
    delete[] ruleLUT;
}

bool BistProblem::isGood() const {
  return tv.isGood();
}

void BistProblem::setInitialBias( IprocessConvergedAllele *pca ) {
  const AlleleType rule90 = static_cast<AlleleType>( 1 );
  const int timesRule90 = 1;
  const AlleleType rule150 = static_cast<AlleleType>( 2 );
  const int timesRule150 = 1;
  int i;
  for ( unsigned int locus = 1u;locus < numberOfGenes;locus += 2u ) {
    for ( i = 0;i < timesRule90;i++ )
      pca->processConvergedAllele( locus, rule90 );
    for ( i = 0;i < timesRule150;i++ )
      pca->processConvergedAllele( locus, rule150 );
  }
}

FloatType BistProblem::getFitness( const AlleleType *chromosome ) const {
  CellularAutomaton ca( chromosome, numberOfGenes, ruleLUT );
  unsigned int matches = tv.countMatches( &ca, ITERATIONS );
  return ( static_cast<FloatType>( matches ) * fitnessFactor );
}

void BistProblem::print() const {
  if ( tv.isGood() ) {
    LOG( Logger::LOGLEVEL_MEDIUM,
         "BIST Vector Problem\trows:%u,columns:%u\tgraph file <%s>",
         tv.getRows(), tv.getCols(), tv.getFilename().c_str() );
  } else
    LOG( Logger::LOGLEVEL_MEDIUM,
         "BIST Vector Problem\tINVALID graph file <%s>",
         tv.getFilename().c_str() );
}
