/* ga_iface.cc */

#include "ga_iface.h"
#include "EvStdMetric.hh"
#include "integer.h"
#include "root.h"
#include "function.h"
#include "element.h"

double steady_state_max_iters = 100;
double evaluation_max_iters = 100;

/******************************************************************************/

ga::ga( void ) {
  steady_state = exit_cond = nil;

  nIndividuals = nil;
  fitness = nil; 
  Algor = nil;
  
  generation = new dc_int( 0, generation_label, this );  

  pCrossover        = 0.3;
  pMut              = 0.5;
  mutVar            = 1.0;
  //  tau           = 0.1;
  int_acc           = 0.001;
  time_step         = 1.0;
  fBestPerformance  = minPerf; /* minPerf defined in EvPerformance.hh */
  nGens             = 10;

  open = false;
}

ga::~ga( void ) {
  if( open ) close();

  if( fitness ) delete( fitness );
  if( Algor ) delete( Algor );
}

void ga::set_fitness_fn( dc_func *f ) { 
  if( fitness ) delete( fitness ); 
  fitness = f;
  if( fitness ) fitness->set_owner( this );
}

bool ga::set_pCrossover( double d ) {
  if( d < 0 || d > 1 ) return true;
  pCrossover = d;
  return false;
}

bool ga::set_pMut( double d ) {
  if( d < 0 || d > 1 ) return true;
  pMut = d;
  return false;
}

bool ga::set_mutVar( double d ) {
  if( d < 0 ) return true;
  mutVar = d;
  return false;
}

bool ga::set_time_step( double d ) {
  if( d > 0 ) {
    time_step = d;
    return false;
  }
  return true;
}

bool ga::set_int_accuracy( double d ) { 
  if( d > 0 ) {
    int_acc = d;
    return false;
  }
  return true;
}

bool ga::set_nGens( int i ) {
  if( i > 0 ) {
    nGens = i;
    return false;
  }
  return true;
}

bool ga::execute( void ) {
  if( open ) close();

  if( init() ) { 
    dc_trace( TRACE_ERROR ) { 
      cerr << "ga::execute -- error initing " << full_type() << "\n";
    }
    cleanup();
    return true;
  }
  dc_trace( TRACE_FEW ) {
    cout << "ga::execute -- init of " << full_type() << " done\n";
  }
  if( run() ) {
    dc_trace( TRACE_ERROR ) { 
      cerr << "ga::execute -- error initing " << full_type() << "\n";
    }
    cleanup();
    return true;
  }
  dc_trace( TRACE_FEW ) {
    cout << "ga::execute -- run of " << full_type() << " done\n";
  }
  if( finish() ) { 
    dc_trace( TRACE_ERROR ) { 
      cerr << "ga::execute -- error initing " << full_type() << "\n";
    }
    cleanup();
    return true;
  }
  dc_trace( TRACE_FEW ) {
    cout << "ga::execute -- finish of " << full_type() << " done\n";
  }
  if( output() ) { 
    dc_trace( TRACE_ERROR ) { 
      cerr << "ga::execute -- error initing " << full_type() << "\n";
    }
    cleanup();
    return true;
  }
  dc_trace( TRACE_FEW ) {
    cout << "ga::execute -- execute of " << full_type() << " done\n";
  }
  //cleanup();
  open = true;
  return false;
}

bool ga::simulate( void ) {
  if( !open ) {
    cerr << "ga::simulate -- " << full_type() << " is not open\n";
    return true;
  }
  cerr << "Simulating " << best.Genome() << "\n";
  cerr << "Perf = " << Evaluate( best.Genome() ) << "\n";

  return false;
}

void ga::child_init( dc_label *child ) {
  dc_component::child_init( child ); 
  set_child_df( child );
}

/* to set status of children */
void set_child_a( dc_label *child ) {
  switch( child->sub_type() ) {
  case Component_t : case Modification_t : case GA_t :
    ( ( dc_component * )child )->set_dormant( false );
    ( ( dc_component * )child )->set_frozen( false );
    break;
  case Element_t :
    ( ( dc_element * )child )->set_dormant( false );
    ( ( dc_element * )child )->set_frozen( false );
    break;
  default :;
  }
}

void set_child_f( dc_label *child ) {
  switch( child->sub_type() ) {
  case Component_t : case Modification_t : case GA_t :
    ( ( dc_component * )child )->set_dormant( false );
    ( ( dc_component * )child )->set_frozen( true );
    break;
  case Element_t :
    ( ( dc_element * )child )->set_dormant( false );
    ( ( dc_element * )child )->set_frozen( true );
    break;
  default :;
  }
}

void set_child_df( dc_label *child ) {
  switch( child->sub_type() ) {
  case Component_t : case Modification_t : case GA_t :
    ( ( dc_component * )child )->set_dormant( true );
    ( ( dc_component * )child )->set_frozen( true );
    break;
  case Element_t :
    ( ( dc_element * )child )->set_dormant( true );
    ( ( dc_element * )child )->set_frozen( true );
    break;
  default :;
  }
}
