#include "func_test.h"
#include "func_array.h"
#include "func_endianness.h"
#include "func_factoriel.h"
#include "func_fibonnacci.h"
#include "func_hanoi.h"
#include "func_integrity.h"
#include "func_io.h"
#include "func_math.h"
#include "func_mm.h"
#include "func_parite.h"
#include "func_premier.h"
#include "func_test.h"
#include "func_test_io.h"


                      // mul_soft
                      // div_soft
                      // mul_hard
                      // div_hard
                      // modulo
#define PARAM_06 30   // fibonnacci    max : 43
#define PARAM_07 15   // n_premier     max : 30
#define PARAM_08 100  // tri_croissant max : unlimited (200)
#define PARAM_09 10   // hanoi         max : 12
#define PARAM_10 15   // mul matrix    max : unlimited (30)
#define PARAM_11 12   // factoriel_rec max : 12
#define PARAM_12 12   // factoriel_it  max : 12
#define PARAM_13 50   // parite        max : unlimited (200)

//----------------------------------
// TEST 1
// multiplication software
//----------------------------------
int test_01 ()
{
  int op1, op2, wait, res, test1;
#ifdef HAVE_LIBC  
  printf("Test_01 - mult_soft\n");
#else
  print(0xABCD0001);
#endif

  test1 = 1;
  {
#ifdef HAVE_LIBC  
    printf(" * Test_01a\n");
#else
    print(0xABCD001A);
#endif

    op1     = 40;
    op2     = 17;
    wait    = 680; // 0x2a8
    res     = mul_soft(op1,op2);

    print(res);     
    test1 &= (wait == res);
  }
  {
#ifdef HAVE_LIBC  
    printf(" * Test_01b\n");
#else
    print(0xABCD001B);
#endif

    op1     = 1569;
    op2     = 9835;
    wait    = 15431115; // 0xEB75CB
    res     = mul_soft(op1,op2);

    print(res);     
    test1 &= (wait == res);
  }
  
  return test1;
}

//----------------------------------
// TEST 2
// division       software
//----------------------------------
int test_02 ()
{
  int op1, op2, wait, res, test2;
#ifdef HAVE_LIBC
  printf("Test_02 - div_soft\n");
#else
  print(0xABCD0002);
#endif
  
  test2 = 1;
  {
#ifdef HAVE_LIBC  
    printf(" * Test_02a\n");
#else
    print(0xABCD002A);
#endif

    op1     = 680;
    op2     = 40;
    wait    = 17; // 0x11
    res     = div_soft(op1,op2);

    print(res);     
    test2 &= (wait == res);
 }
 {
#ifdef HAVE_LIBC  
    printf(" * Test_02b\n");
#else
    print(0xABCD002B);
#endif
   
    op1     = 15431115; // eb75cb
    op2     = 9835;     //   266b
    wait    = 1569;     //    621
    res     = div_soft(op1,op2);
    
    print(res);     
    test2 &= (wait == res);
 }
  
  return test2;
}

//----------------------------------
// TEST 3
// multiplication hardware (*)
//----------------------------------
int test_03 ()
{
  int op1, op2, wait, res;
#ifdef HAVE_LIBC
  printf("Test_03 - mul_hard\n");  
#else
  print(0xABCD0003);
#endif
  
  op1     = 1569;
  op2     = 9835;
  wait    = 15431115; // 0xEB75CB
  res     = mul_hard(op1,op2);

  print(res);     
  return (wait == res);
}

//----------------------------------
// TEST 4
// division       hardware (/)
//----------------------------------
int test_04 ()
{
  int op1, op2, wait, res;
#ifdef HAVE_LIBC
  printf("Test_04 - div_hard\n");  
#else
  print(0xABCD0004);
#endif
  
  op1     = 15431115;
  op2     = 9835;
  wait    = 1569; // 0x621
  res     = div_hard(op1,op2);

  print(res);     
  return (wait == res);
}


//----------------------------------
// TEST 5
// modulo
//----------------------------------
int test_05 ()
{
  int op1, op2, wait, res;
#ifdef HAVE_LIBC
  printf("Test_05 - modulo\n");  
#else
  print(0xABCD0005);
#endif
  
  op1     = 16834;
  op2     = 563;
  wait    = 507; // 0x1fb
  res     = modulo(op1,op2);

  print(res);     
  return (wait == res);
}

//----------------------------------
// TEST 6
// fibonnacci
//----------------------------------
int test_06 ()
{
  int it, test;
  int x     = PARAM_06;
  int x_max = 43;

  int res  [x_max+1];
  int wait [x_max+1];
#ifdef HAVE_LIBC
  printf("Test_06 - fibonnacci\n");
#else
  print(0xABCD0006);
#endif
  wait [0]  = 1;          // 1
  wait [1]  = 2;          // 2
  wait [2]  = 3;          // 3
  wait [3]  = 5;          // 5
  wait [4]  = 8;          // 8
  wait [5]  = 13;         // d
  wait [6]  = 21;         // 15
  wait [7]  = 34;         // 22
  wait [8]  = 55;         // 37
  wait [9]  = 89;         // 59
  wait [10] = 144;        // 90
  wait [11] = 233;        // e9
  wait [12] = 377;        // 179
  wait [13] = 610;        // 262
  wait [14] = 987;        // 3db
  wait [15] = 1597;       // 63d
  wait [16] = 2584;       // a18
  wait [17] = 4181;       // 1055
  wait [18] = 6765;       // 1a6d
  wait [19] = 10946;      // 2ac2
  wait [20] = 17711;      // 452f
  wait [21] = 28657;      // 6ff1
  wait [22] = 46368;      // b520
  wait [23] = 75025;      // 12511
  wait [24] = 121393;     // 1da31
  wait [25] = 196418;     // 2ff42
  wait [26] = 317811;     // 4d973
  wait [27] = 514229;     // 7d8b5
  wait [28] = 832040;     // cb228
  wait [29] = 1346269;    // 148add
  wait [30] = 2178309;    // 213d05
  wait [31] = 3524578;    // 35c7e2
  wait [32] = 5702887;    // 5704e7
  wait [33] = 9227465;    // 8cccc9
  wait [34] = 14930352;   // e3d1b0
  wait [35] = 24157817;   // 1709e79
  wait [36] = 39088169;   // 2547029
  wait [37] = 63245986;   // 3c50ea2
  wait [38] = 102334155;  // 6197ecb
  wait [39] = 165580141;  // 9de8d6d
  wait [40] = 267914296;  // ff80c38
  wait [41] = 433494437;  // 19d699a5
  wait [42] = 701408733;  // 29cea5dd
  wait [43] = 1134903170; // 43a53f82
  
  for (it = 0; it <= x ; it ++)
    {
      res [it] = fibonnacci (it);
    }
  
  test = 1;
  
  for (it = 0; it <= x ; it ++)
    test &= (res [it] == wait [it]);

  print(test);
  return (test);
}

//----------------------------------
// TEST 7
// n_premier
// *
//----------------------------------
int test_07 ()
{
  unsigned int it, test;
  unsigned int x     = PARAM_07;  
  unsigned int x_max = 30;
  unsigned int res  [x_max+1];
  unsigned int wait [x_max+1];
#ifdef HAVE_LIBC
  printf("Test_07 - n_premier\n");  
#else
  print(0xABCD0007);
#endif

  wait [0] = 1; // 1
  wait [1] = 2; // 2
  wait [2] = 3; // 3
  wait [3] = 5; // 5
  wait [4] = 7; // 7
  wait [5] = 11; // b
  wait [6] = 13; // d
  wait [7] = 17; // 11
  wait [8] = 19; // 13
  wait [9] = 23; // 17
  wait [10] = 29; // 1d
  wait [11] = 31; // 1f
  wait [12] = 37; // 25
  wait [13] = 41; // 29
  wait [14] = 43; // 2b
  wait [15] = 47; // 2f
  wait [16] = 53; // 35
  wait [17] = 59; // 3b
  wait [18] = 61; // 3d
  wait [19] = 67; // 43
  wait [20] = 71; // 47
  wait [21] = 73; // 49
  wait [22] = 79; // 4f
  wait [23] = 83; // 53
  wait [24] = 89; // 59
  wait [25] = 97; // 61
  wait [26] = 101; // 65
  wait [27] = 103; // 67
  wait [28] = 107; // 6b
  wait [29] = 109; // 6d
  wait [30] = 113; // 71

  for (it = 0; it <= x ; it ++)
    {
      res [it] = n_premier(it);
      print (res [it]);
    }
    
  test = 1;
  
  for (it = 0; it <= x ; it ++)
    test &= (res [it] == wait [it]);

  print(test);
  return (test);
}

//----------------------------------
// TEST 8
// tri_croissant (tableau d'int)
// tri_croissant (tableau de short)
// tri_croissant (tableau de char)
// *
//----------------------------------
#include <string.h>
#include <stdlib.h>

int test_08 ()
{
  int       x           = PARAM_08;
  const int size        = x;
  const int nb_algo_max = 4;
  
  int       array_ref [size];
  int       array     [nb_algo_max][size];  
  int       it;
  int       nb_algo;
  
  /* 
   * PHASE 1 : Initialisation
   */
  
  // Remplir le tableau
  
  srand(0);
  
  for (it = 0; it < size ; it++)
    {
      array_ref [it] = rand();
      for (nb_algo = 0; nb_algo < nb_algo_max; nb_algo ++)
	array[nb_algo][it] = array_ref [it];
    }
  
  {
#ifdef HAVE_LIBC
  printf("Test_08 - tri_croissant\n");  
#else
    print(0xABCD0008);
#endif

    for (nb_algo = 0; nb_algo < nb_algo_max; nb_algo ++)
      {
//	  for (it = 0; it < size ; it++)
//	    printf("%d ",array [it]);
//	  printf("\n");
	  	      
	  /*
	   * PHASE 2 : Exécution
	   */
#ifdef HAVE_LIBC
	  printf(" * tri_croissant - algo %d\n",nb_algo);  
#endif
	  print(0xABCD08a0 | nb_algo);
	  array_tri_croissant   (array[nb_algo]  ,size,nb_algo);
	  print(0xABCD08b0 | nb_algo);

//	  for (it = 0; it < size ; it++)
//	    printf("%d ",array [it]);
//	  printf("\n");
      }
  }

  /* 
   * PHASE 3 : Vérification des résultats
   */
  
  // Vérifier le résultat : compte le nombre de case identique par algoritme
  for (it = 0; it < size ; it++)
    {
      int val = array[0][it];
      
      for (nb_algo = 1; nb_algo < nb_algo_max; nb_algo ++)
	if (val != array[nb_algo][it])
	  return 0;
    }

  return (1);
}

//----------------------------------
// TEST 9 - hanoi
// 
//----------------------------------
int test_09 ()
{
  unsigned int it, test;
  unsigned int x     = PARAM_09;
  unsigned int x_max = 12;
  
  unsigned int res  [x_max+1];
  unsigned int wait [x_max+1];
#ifdef HAVE_LIBC
  printf("Test_09 - hanoi\n");  
#else
  print(0xABCD0009);
#endif
  
  wait [1] = 1; // 1
  wait [2] = 3; // 3
  wait [3] = 7; // 7
  wait [4] = 15; // f
  wait [5] = 31; // 1f
  wait [6] = 63; // 3f
  wait [7] = 127; // 7f
  wait [8] = 255; // ff
  wait [9] = 511; // 1ff
  wait [10] = 1023; // 3ff
  wait [11] = 2047; // 7ff
  wait [12] = 4095; // fff
  
  for (it = 1; it <= x ; it ++)
    {
      res [it] = hanoi (it);

      print(res [it]);
    }
  
  test = 1;
  
  for (it = 1; it <= x ; it ++)
    test &= (res [it] == wait [it]);

  print(test);
  return (test);
  
}

//----------------------------------
// TEST 10
// multiplication de matrice
// *
//----------------------------------
int test_10 ()
{
  int op1, op2, res;
  int x     = PARAM_10;
#ifdef HAVE_LIBC
  printf("Test_10 - multiplication de matrice\n");  
#else
  print(0xABCD0010);
#endif
  
  op1     = x;
  op2     = 1;
  res     = mm(op1,op2);

  print(res);     
  return (res);
}

//----------------------------------
// TEST 11
// factoriel_recursif
//----------------------------------
int test_11 ()
{
  unsigned int it, test;
  unsigned int x     = PARAM_11;
  unsigned int x_max = 12;
  
  unsigned int res  [x_max+1];
  unsigned int wait [x_max+1];
#ifdef HAVE_LIBC
  printf("Test_11 - factoriel recursif\n");  
#else
  print(0xABCD0011);
#endif

  wait[0]  = 1;         // 1
  wait[1]  = 1;         // 1
  wait[2]  = 2;         // 2
  wait[3]  = 6;         // 6
  wait[4]  = 24;        // 18
  wait[5]  = 120;       // 78
  wait[6]  = 720;       // 2d0
  wait[7]  = 5040;      // 13b0
  wait[8]  = 40320;     // 9d80
  wait[9]  = 362880;    // 58980
  wait[10] = 3628800;   // 375f00
  wait[11] = 39916800;  // 2611500
  wait[12] = 479001600; // 1c8cfc00

  for (it = 0; it <= x ; it ++)
    res [it] = fact_recursif (it);
  
  test = 1;
  
  for (it = 0; it <= x ; it ++)
    test &= (res [it] == wait [it]);

  print(test);
  return (test);
}

//----------------------------------
// TEST 12
// factoriel_iteratif
//----------------------------------
int test_12 ()
{
  unsigned int it, test;
  
  unsigned int x     = PARAM_12;
  unsigned int x_max = 12;
  
  unsigned int res  [x_max+1];
  unsigned int wait [x_max+1];
#ifdef HAVE_LIBC
  printf("Test_12 - factoriel_iteratif\n");  
#else
  print(0xABCD0012);
#endif

  wait[0]  = 1;         // 1
  wait[1]  = 1;         // 1
  wait[2]  = 2;         // 2
  wait[3]  = 6;         // 6
  wait[4]  = 24;        // 18
  wait[5]  = 120;       // 78
  wait[6]  = 720;       // 2d0
  wait[7]  = 5040;      // 13b0
  wait[8]  = 40320;     // 9d80
  wait[9]  = 362880;    // 58980
  wait[10] = 3628800;   // 375f00
  wait[11] = 39916800;  // 2611500
  wait[12] = 479001600; // 1c8cfc00

  for (it = 0; it <= x ; it ++)
    res [it] = fact_iteratif (it);
  
  test = 1;
  
  for (it = 0; it <= x ; it ++)
    test &= (res [it] == wait [it]);

  print(test);
  return (test);
}

//----------------------------------
// TEST 13
// parite
//----------------------------------
int test_13 ()
{
  unsigned int it;
  unsigned int x     = PARAM_13;
  unsigned int pair,test;
  
#define TEST(a,b) ( ( (a) ^ (b) ) == 0)?1:0
#ifdef HAVE_LIBC
  printf("Test_13 - parite\n");  
#else
  print(0xABCD0013);
#endif
  
  test = 1;

  pair = 1;
  srand(0);
  for (it = 0; (it < x) && (test == 1); it ++)
    {
      unsigned int val = (unsigned int) rand();
      unsigned int val1 = parite1(val,pair);
      unsigned int val2 = parite2(val,pair);
      test &= TEST(val1,val2); // Test if 2 implementation produced the same result
    }
  print(test);

  pair ^= 1;
  for (it = 0; (it < x) && (test == 1); it ++)
    {
      unsigned int val = (unsigned int) rand();
      unsigned int val1 = parite1(val,pair);
      unsigned int val2 = parite2(val,pair);
      test &= TEST(val1,val2); // Test if 2 implementation produced the same result
    }
  print(test);
  return (test);
}
