#include <ctime>
#include "generic_individual.h"
#include "table_fitness.h"
#include "individual.h"
#include "individual_test.h"

using namespace std;

/**
 * compares two chromosomes of known length (w/o recursion :))
 */
bool individual_test::compare_chromosomes(int size,
    GENE *chr_1, GENE *chr_2) {
  for(int i = 0; i < size; i++)
    if(chr_1[i] != chr_2[i]) return false;

  return true;
}

/**
 * performs a series of tests and returns on the first error
 * with a corresponding error code
 */
int individual_test::test(char *p_table, int p_cells) {
  // firstly, test the static member accessors
  RANDOM_GENERATOR rg (time(0));

  int test_rules [] = {2, 60, 90, 240};
  int test_rule_cnt = 4;
  int test_rule_size = 2;

  table_fitness *rule_eval = new table_fitness (test_rules,
      test_rule_cnt, p_table, p_cells);

  individual::set_evaluator(rule_eval);

  if((individual::get_block_variants() != test_rule_cnt)
      || (individual::get_block_size() != test_rule_size))
    return TI_STATIC_ERROR;

  if((individual::set_vector_count(p_cells) != p_cells)
      || (individual::get_vector_count() != p_cells))
    return TI_STATIC_ERROR;

  if((individual::set_minimize(false) != false)
      || (individual::get_minimize() != false))
    return TI_STATIC_ERROR;

  // test the first constructor and the fundamental getters
  char test_type = TYPE_RULES_SEED;
  int test_size = (p_cells * (test_rule_size + 1));
  GENE tmp_chr [test_size];
  individual ind_1 (test_type, p_cells, &rg, 0.0); // an extremist

  if((ind_1.get_type() != test_type)
      || (ind_1.get_cells() != p_cells)
      || (ind_1.get_size() != test_size)
      || (ind_1.get_fitness() > 0.001)) // an extremist?
    return TI_INIT_ERROR;

  ind_1.get_chromosome(tmp_chr);

  for(int i = 0; i < test_size; i++)
    if(tmp_chr[i] != 0) return TI_INIT_ERROR; // an extremist?

  // test the second constructor
  float test_fitness = 0.999;

  GENE test_chr [test_size];
  for(int i = 0; i < test_size; i++) test_chr[i] = 0;
  test_chr[test_size - 1] = 1; // an LFSR with the seed 00...01

  individual ind_2 (test_type, p_cells, DEFAULT_FITNESS,
      test_chr);

  if((ind_2.get_type() != test_type)
     || (ind_2.get_cells() != p_cells)
     || (ind_2.get_size() != test_size)
     || (ind_2.get_fitness() < test_fitness)) // table covered?
    return TI_INIT_ERROR;

  ind_2.get_chromosome(tmp_chr);

  if(!compare_chromosomes(test_size, test_chr, tmp_chr))
    return TI_INIT_ERROR;

  // test the CA structure getters
  // (we'll make use of some of the structures defined earlier)
  int tmp_rules [p_cells];
  ind_2.get_rules(tmp_rules);

  for(int i = 0; i < p_cells; i++) // expecting an LFSR
    if(tmp_rules[i] != 0) return TI_GET_RULES_ERROR;

  for(int i = 0; i < test_size; i++) tmp_chr[i] = 0;
  ind_2.get_seed(tmp_chr);

  if(!compare_chromosomes(p_cells, test_chr
        + ((test_size - p_cells) * sizeof(GENE)), tmp_chr))
    return TI_GET_SEED_ERROR;

  // test for a cloning error
  // note: should also add the test whether the original ind.
  // and it's clone overlap in the memory
  individual ind_3 (&ind_2);
  if(!(ind_2.compare(&ind_3))) return TI_COPY_ERROR;

  // test for a comparison error
  individual ind_4 (test_type, p_cells, test_fitness, test_chr);
  if(!(ind_4.compare(&ind_2))) return TI_COMPARE_ERROR;

  return TI_OK;
}

