#include "CellularAutomatonTest.h"
#include "../CellularAutomaton.h"
#include <cstdio>
#include <cstring>

unit_test::CellularAutomatonTest::CellularAutomatonTest() :
    UnitTest(), chromosome( NULL ) { /* Empty */ }
unit_test::CellularAutomatonTest::~CellularAutomatonTest() {
  if ( chromosome )
    delete[] chromosome;
}

unsigned int unit_test::CellularAutomatonTest::setChromosomeRule30() {
  if ( chromosome )
    delete[] chromosome;
  unsigned int n = 31u * 2u;
  unsigned int middle = ( n / 2u ) - 1u;
  chromosome = new AlleleType[n];
  for ( unsigned int i = 0u; i < n; i += 2u ) {
    chromosome[i] = ( i == middle ) ?
                    static_cast<AlleleType>( 1 ) : static_cast<AlleleType>( 0 );
    chromosome[i+1u] = static_cast<AlleleType>( 30 );
  }
  return n;
}

bool unit_test::CellularAutomatonTest::verifyChromosomeRule30( const char *bits ) const {
  const char *correct = "1101111001101001011111001111111";
  return ( std::strcmp( correct, bits ) == 0 );
}

unsigned int unit_test::CellularAutomatonTest::setChromosomeRule86() {
  if ( chromosome )
    delete[] chromosome;
  unsigned int n = 31u * 2u;
  unsigned int middle = ( n / 2u ) - 1u;
  chromosome = new AlleleType[n];
  for ( unsigned int i = 0u; i < n; i += 2u ) {
    chromosome[i] = ( i == middle ) ?
                    static_cast<AlleleType>( 1 ) : static_cast<AlleleType>( 0 );
    chromosome[i+1u] = static_cast<AlleleType>( 86 );
  }
  return n;
}

bool unit_test::CellularAutomatonTest::verifyChromosomeRule86( const char *bits ) const {
  const char *correct = "1111111001111101001011001111011";
  return ( std::strcmp( correct, bits ) == 0 );
}

unsigned int unit_test::CellularAutomatonTest::setChromosomeRule170() {
  if ( chromosome )
    delete[] chromosome;
  unsigned int n = 6u * 2u;
  chromosome = new AlleleType[n];
  chromosome[ 0] = static_cast<AlleleType>( 1 );
  chromosome[ 1] = static_cast<AlleleType>( 170 );
  chromosome[ 2] = static_cast<AlleleType>( 0 );
  chromosome[ 3] = static_cast<AlleleType>( 170 );
  chromosome[ 4] = static_cast<AlleleType>( 0 );
  chromosome[ 5] = static_cast<AlleleType>( 170 );
  chromosome[ 6] = static_cast<AlleleType>( 1 );
  chromosome[ 7] = static_cast<AlleleType>( 170 );
  chromosome[ 8] = static_cast<AlleleType>( 1 );
  chromosome[ 9] = static_cast<AlleleType>( 170 );
  chromosome[10] = static_cast<AlleleType>( 0 );
  chromosome[11] = static_cast<AlleleType>( 170 );
  return n;
}

bool unit_test::CellularAutomatonTest::verifyChromosomeRule170( const char *bits ) const {
  const char *correct = "100110";
  return ( std::strcmp( correct, bits ) == 0 );
}

int unit_test::CellularAutomatonTest::run( int argc, char *argv[] ) {
  unsigned int n;
  bool pass = true;
  {
    n = setChromosomeRule30();
    CellularAutomaton ca( chromosome, n );
    std::printf( "%3d |%s|\n", 0, ca.getStorage() );
    while ( ca.getIteration() < 15u ) {
      ca.createVector();
      std::printf( "%3d |%s|\n", ca.getIteration(), ca.getStorage() );
    }
    bool result = verifyChromosomeRule30( ca.getStorage() );
    std::printf( "---Rule 30 test %s\n", result ? "PASSED" : "FAILED" );
    pass = pass && result;
  }
  {
    n = setChromosomeRule86();
    CellularAutomaton ca( chromosome, n );
    std::printf( "%3d |%s|\n", 0, ca.getStorage() );
    while ( ca.getIteration() < 15u ) {
      ca.createVector();
      std::printf( "%3d |%s|\n", ca.getIteration(), ca.getStorage() );
    }
    bool result = verifyChromosomeRule86( ca.getStorage() );
    std::printf( "---Rule 86 test %s\n", result ? "PASSED" : "FAILED" );
    pass = pass && result;
  }
  {
    n = setChromosomeRule170();
    CellularAutomaton ca( chromosome, n );
    std::printf( "%3d |%s|\n", 0, ca.getStorage() );
    while ( ca.getIteration() < 18u ) {
      ca.createVector();
      std::printf( "%3d |%s|\n", ca.getIteration(), ca.getStorage() );
    }
    bool result = verifyChromosomeRule170( ca.getStorage() );
    std::printf( "---Rule 86 test %s\n", result ? "PASSED" : "FAILED" );
    pass = pass && result;
  }
  return pass ? 0 : 1;
}

int main( int argc, char *argv[] ) {
  unit_test::CellularAutomatonTest test;
  return test.run( argc, argv );
}
