
#include "RobboLito.h"
#include "RobboTotalBase.h"

void InitRandom32 (uint64 x) {} /* HACK */

#include <time.h>
void NANO_SLEEP (int x)
{
#ifdef WINDOWS
  Sleep (x / 1000000);
#else
  struct timespec TS[1];
  TS->tv_sec = 0;
  TS->tv_nsec = x;
  nanosleep (TS, NULL);
#endif
}

void SAVE_RTB (RobboTotalBase* Tot, uint8** ptr, uint64 sz, char* str)
{
  char NOME_FILE[1024];
  FILE* TEMP;
  sprintf (NOME_FILE, "%s%s.%s", Tot->DIR_NOME, str, Tot->string);
  TEMP = fopen (NOME_FILE, "w");
  fwrite (*ptr, 1, (Tot->PEDONE ? 1806 : 462) * sz, TEMP);
  fclose (TEMP);
  free (*ptr);
  *ptr = NULL;
}

static void LOAD_RTB (RobboTotalBase* Tot, uint8** ptr, uint64 sz, char* str)
{
  char NOME_FILE[1024];
  FILE* TEMP;
  sprintf (NOME_FILE, "%s%s.%s", Tot->DIR_NOME, str, Tot->string);
  TEMP = fopen (NOME_FILE, "rb");
  *ptr = malloc ((Tot->PEDONE ? 1806 : 462) * sz);
  fread (*ptr, 1, (Tot->PEDONE ? 1806 : 462) * sz, TEMP);
  fclose (TEMP);
}

static void DELETE_RTB (RobboTotalBase* Tot, uint8** ptr, char* str)
{
  char NOME_FILE[1024];
  if (DISK_SWAP)
    {
      sprintf (NOME_FILE, "%s%s.%s", Tot->DIR_NOME, str, Tot->string);
      remove (NOME_FILE);
    }
  free (*ptr);
  *ptr = NULL;
}

void popolare (RobboTotalBase *);
static void fine_rtb_memoria (RobboTotalBase *);

static void FINALIZE (RobboTotalBase* Tot)
{
  uint64 i, num_locks =
    (Tot->PawnMult8 * 8 * (Tot->PEDONE ? 1806 : 462)
     + (1 << Tot->shift) - 1) >> Tot->shift;
  fine_rtb_memoria (Tot);
  DELETE_RTB (Tot, &Tot->VIT, "VIT");
  DELETE_RTB (Tot, &Tot->data, "DATA");
  for (i = 0; i < num_locks; i++)
    ROBBO_LOCK_DESTROY (&(Tot->locks)[i]);
  free (Tot->locks);
}

static void TotalBaseBuild (RobboTotalBase * Tot1, RobboTotalBase * Tot2)
{
  int num;
  uint64 t;
  Tot1->is_uno = TRUE;
  Tot2->is_uno = FALSE;
  Tot1->simm = Tot2->simm = FALSE;
  popolare (Tot1);
  popolare (Tot2);
  t = GetClock ();
  if (DISK_SWAP)
    {
      LOAD_RTB (Tot1, &Tot1->MAR, Tot1->PawnMult8, "MAR");
      LOAD_RTB (Tot1, &Tot1->VIT, Tot1->PawnMult8, "VIT");
      printf ("Reload MAR/VIT %.2fs\n", (GetClock() - t) / 1000000.0);
    }
  for (num = 0;; num++)
    {
      if (!fareRIMA (Tot2, num, Tot1) && 0)
	break;
      if (!fareMARCO (Tot1, num, Tot2))
	break;
    }
  t = GetClock();
  DELETE_RTB (Tot1, &Tot1->MAR, "MAR");
  DELETE_RTB (Tot2, &Tot2->PER, "PER");
  if (DISK_SWAP)
    {
      SAVE_RTB (Tot1, &Tot1->VIT, Tot1->PawnMult8, "VIT");
      SAVE_RTB (Tot2, &Tot2->data, Tot2->PawnMult, "DATA");
      LOAD_RTB (Tot2, &Tot2->MAR, Tot2->PawnMult8, "MAR");
      LOAD_RTB (Tot2, &Tot2->VIT, Tot2->PawnMult8, "VIT");
      LOAD_RTB (Tot1, &Tot1->data, Tot1->PawnMult, "DATA");
      LOAD_RTB (Tot1, &Tot1->PER, Tot1->PawnMult8, "PER");
      printf ("Disk interchange %.2fs\n", (GetClock() - t) / 1000000.0);
    }
  for (num = 0;; num++)
    {
      if (!fareRIMA (Tot1, num, Tot2) && 0) /* 0 ? */
	break;
      if (!fareMARCO (Tot2, num, Tot1))
	break;
    }
  DELETE_RTB (Tot1, &Tot1->PER, "PER");
  DELETE_RTB (Tot2, &Tot2->MAR, "MAR");
  t = GetClock ();
  if (DISK_SWAP)
    {
      LOAD_RTB (Tot1, &Tot1->VIT, Tot1->PawnMult8, "VIT");
      printf ("Reload VIT %.2fs\n", (GetClock() - t) / 1000000.0);  
    }
  FINALIZE (Tot1);
  t = GetClock ();
  if (DISK_SWAP)
    {
      LOAD_RTB (Tot2, &Tot2->data, Tot2->PawnMult, "DATA");  
      printf ("Reload DATA %.2fs\n", (GetClock() - t) / 1000000.0);  
    }
  FINALIZE (Tot2);
}

static void RobboBUILD_stesso (RobboTotalBase * Tot)
{
  int num;
  Tot->simm = TRUE;
  popolare (Tot);
  for (num = 0;; num++)
    {
      if (!fareRIMA (Tot, num, Tot) && 0)
	break;
      if (!fareMARCO (Tot, num, Tot))
	break;
    }
  free (Tot->PER);
  free (Tot->MAR);
  fine_rtb_memoria (Tot);
  free (Tot->data);
  free (Tot->VIT);
}

static boolean eVIT (RobboTotalBase * tb, int fetta, uint64 PositionNumber)
{
  return emarco (tb->VIT, fetta * tb->PawnMult8 * 8 + PositionNumber);
}

#define ZOB_VAL(rf, PositionNumber) \
  ( ( (rf) * 123456789 + (PositionNumber) * 98764321 + \
      ( (rf) * (PositionNumber) ) ) & EMASK)

uint64 *RICERCA, EMASK;

static void nuovo_archivio (uint64 ip, uint64 wK)
{
  int ok = ZOB_VAL ((ip >> 32), (ip & 0xffffffff)), k = ok;
  while (RICERCA[k])
    {
      k++;
      if (k == (EMASK + 1))
	k = 0;
    }
  RICERCA[k] = ip | (wK << 48);
}

static void iniz_supp (FILE * F, uint64 pro)
{
  uint64 i;
  uint64 wK = 0, ip;
  pro = 3 * (pro + 10) / 2;
  pro = (1 << (1 + BSR (pro)));
  EMASK = pro - 1;
  RICERCA = malloc (pro * 8);
  for (i = 0; i < pro; i++)
    RICERCA[i] = 0;
  for (i = 0; ; i++)
    {
      if (!fread (&ip, 8, 1, F))
	break;
      if (BSR (ip) > 56)
	{
	  wK = (ip >> 32) & 65535;
	  continue;
	}
      nuovo_archivio (ip, wK);
    }
}

static int ric (int rf, int PositionNumber)
{
  int k = ZOB_VAL (rf, PositionNumber);
  uint64 n = PositionNumber + (((uint64) rf) << 32);
  while (1)
    {
      uint64 v = RICERCA[k];
      if ((v & 0xffffffffffff) == n)
	return (v >> 48);
      if (v == 0)
	{
	  printf ("MALATO (supp)\n");
	  exit (1);
	}
      k = k + 1;
      if (k == (EMASK + 1))
	k = 0;
    }
}

#define BLOCCO_PRO 65536
#define uBWT 5

static void supp_42_iniz (RobboTotalBase * tb, uint64 * supp_conto)
{
  uint64 n = ftell (tb->Fsupp) >> 3;
  uint64 ip;
  FILE *file[42];
  int i, j, L = tb->PEDONE ? 43 : 11;
  char NOME_FILE[1024];
  char FN[1024];
  fclose (tb->Fsupp);
  sprintf (FN, "%sSUPP.%s", tb->DIR_NOME, tb->string);
  tb->Fsupp = fopen (FN, "rb");
  for (j = 0; j < 42; j++)
    {
      sprintf (NOME_FILE, "%sSUPP%d.%s", tb->DIR_NOME, j, tb->string);
      file[j] = fopen (NOME_FILE, "w");
      supp_conto[j] = 0;
    }
  for (i = 0; i < n; i++)
    {
      fread (&ip, 8, 1, tb->Fsupp);
      if (BSR (ip) > 56)
	{
	  for (j = 0; j < 42; j++)
	    fwrite (&ip, 8, 1, file[j]);
	  continue;
	}
      fwrite (&ip, 8, 1, file[(ip >> 32) / L]);
      supp_conto[(ip >> 32) / L]++;
    }
  for (j = 0; j < 42; j++)
    fclose (file[j]);
  fclose (tb->Fsupp);
  sprintf (NOME_FILE, "%sSUPP.%s", tb->DIR_NOME, tb->string);
  remove (NOME_FILE);
}

static volatile uint64 U;
static volatile uint64 V;
static uint64 M;
static RobboTotalBase* TB;
void* compress_thread (void* A)
{
  uint64 u, v;
  while (TRUE)
    {
      LOCK (RB_SMP);
      u = U;
      U += BLOCCO_PRO;
      v = ++V;
      UNLOCK (RB_SMP);
      if (u >= M)
        break;
      TB->indici[v] = compressa (TB->data + u, MIN (BLOCCO_PRO, M - u), uBWT);
    }
  return NULL;
}

static boolean HYPER_INDEXING, DTR;
static void hyper_index (FILE* F, uint32 J, RobboTotalBase* tb)
{
   uint32* p;
   uint8* Z;
   int by, j, k;
   uint32 n;
   sint32 w; /* sint ? */
   char NOME_FILE[1024];
   printf ("Using hyperindexing %d\n", J);
   by = 2 + ((J - 1) >> 4);
   p = tb->indici;
   /* watermark */
   fputc (0xca, F);
   fputc (0x7f, F);
   fputc (0x0b, F);
   fputc (0xaa, F);
   /* Header block size */
   n = (0x100000) | (uBWT << 28);
   fputc (n & 255, F);
   fputc ((n >> 8) & 255, F);
   fputc ((n >> 16) & 255, F);
   fputc ((n >> 24) & 255, F);
   /* Header 4 null bytes */
   fputc (0, F);
   fputc (0, F);
   fputc (0, F);
   fputc (0, F);
   /* Header indici count */
   fputc (by & 255, F);
   fputc ((by >> 8) & 255, F);
   fputc ((by >> 16) & 255, F);
   fputc ((by >> 24) & 255, F);
   w = 0;
   for (j = 0; j + 0x10 < J; j += 0x10)
     {
       fwrite (&w, 4 , 1, F);
       w += p[j + 0x10] - p[j] + 128;
     }
   fwrite (&w, 4, 1, F);
   w += p[J] - p[j] + 128;
   fwrite (&w, 4, 1, F);
   fclose (F); /* index */
   sprintf (NOME_FILE, "%s%s%s",
	    tb->DIR_NOME, COMPRESSA_PREFISSO + 1, tb->string);
   F = fopen (NOME_FILE, "w");
   for (j = 0; j + 0x10 < J; j += 0x10)
     {
       for (k = 0; k < 0x10; k++)
	 {
	   w = 128 + p[j + k] - p[j];
	   fwrite (&w, 4, 1, F);
	   w = p[j + k + 1] - p[j + k];
	   fwrite (&w, 4, 1, F);
	 }
       for (k = 0; k < 0x10; k++)
	 {
	   w = p[j + k + 1] - p[j + k];
	   Z = tb->data + (((uint64) (j + k)) * BLOCCO_PRO); /* BUG */
	   fwrite (Z, 1, w, F);
	 }
     }
   for (k = 0; k < 0x10; k++)
     {
       if (j + k >= J)
	 w = 0;
       else
	 w = 128 + p[j + k] - p[j];
       fwrite (&w, 4, 1, F);
       if (j + k >= J)
	 w = 0;
       else
	 w = p[j + k + 1] - p[j + k];
       fwrite (&w, 4, 1, F);
     }
   for (k = 0; k < 0x10; k++)
     {
       if (j + k < J)
	 {
	   w = p[j + k + 1] - p[j + k];
	   Z = tb->data + (((uint64) (j + k)) * BLOCCO_PRO); /* BUG */
	   fwrite (Z, 1, w, F);
	 }
     }
   fclose (F); /* BUG */
}

static int THIS_RF, MAX_RF;
static RobboTotalBase* TB;
void* realign_thread (void* A)
{
  uint64 u, PositionNumber;
  int rf;
  while (TRUE)
    {
      LOCK (RB_SMP);
      rf = THIS_RF++;
      UNLOCK (RB_SMP);
      if (rf >= MAX_RF)
	break;
      PositionNumber = ((uint64) (rf)) * (TB->PawnMult);
      for (u = 0; u < TB->PawnMult; u++, PositionNumber++)
	{
	  if (TB->data[PositionNumber] == VALU_ROTTO)
	    TB->data[PositionNumber] = dROTT;
	  else if (eVIT (TB, rf, u)) /* rf HACK */
	    TB->data[PositionNumber] = dVITT;
	  else if (TB->data[PositionNumber] <= MASSIMO_RIMA)
	    TB->data[PositionNumber] = dPATT;
	  else if (TB->data[PositionNumber] == PERD_FINE) /* max 0xFA in compressa */
	    TB->data[PositionNumber] = ric (rf, u) + dPERD0;
	  else
	    TB->data[PositionNumber] -= PRIMERA_PERDITA - dPERD0;
	}
    }
  return NULL;
}
static void fine_rtb_memoria (RobboTotalBase * tb)
{
   uint64 u = 0;
   int USE_CPUS, cpu, rf, RF = tb->PEDONE ? 1806 : 462;
   FILE *F;
   uint64 LIMITE = RF * tb->PawnMult;
   uint32 v = 0;
   char NOME_FILE[1024];
   uint32 n;
   int L = tb->PEDONE ? 43 : 11;
   uint64 supp_conto[42];
   boolean SUPP = (tb->Fsupp != NULL);
   uint64 cl = GetClock();
   if (SUPP)
     supp_42_iniz (tb, supp_conto);
   LOCK_INIT (RB_SMP);
   USE_CPUS = MIN (L, (tb->p[2] ? RB_CPUS : 1));
   TB = tb;
   for (rf = 0; rf < RF; rf += L)
   {
     if (SUPP)
       { 
	 sprintf (NOME_FILE, "%sSUPP%d.%s", tb->DIR_NOME, rf / L, tb->string);
	 F = fopen (NOME_FILE, "rb");
	 if (rf != 0)
	   free (RICERCA);
	 iniz_supp (F, supp_conto[rf / L]);
	 fclose (F);
	 remove (NOME_FILE);
       }
     THIS_RF = rf;
     MAX_RF = rf + L;
     for (cpu = 0; cpu < USE_CPUS; cpu++)
       PTHREAD_CREATE (&PTHREAD[cpu], NULL, realign_thread, NULL);
     for (cpu = 0; cpu < USE_CPUS; cpu++)
       PTHREAD_JOIN (PTHREAD[cpu]); /* dispel nanosleep in WINDOWS */
   }
   if (SUPP)
     free (RICERCA);
   printf ("Realign(%d) %s %.2fs\n",
	   USE_CPUS, tb->string, (GetClock () - cl) / 1000000.0);
   cl = GetClock ();
   tb->indici = malloc (sizeof (uint32) * (2 + LIMITE / BLOCCO_PRO));
   U = V = 0;
   M = LIMITE;
   TB = tb;
   for (cpu = 0; cpu < RB_CPUS; cpu++)
     PTHREAD_CREATE (&PTHREAD[cpu], NULL, compress_thread, NULL);
   for (cpu = 0; cpu < RB_CPUS; cpu++)
     PTHREAD_JOIN (PTHREAD[cpu]);
   LOCK_DESTROY (RB_SMP);
   v = (LIMITE + 65535) / BLOCCO_PRO;
   printf ("Compress %s %.2fs CPUS %d\n",
	   tb->string, (GetClock () - cl) / 1000000.0, RB_CPUS);
   cl = GetClock ();
   tb->indici[0] = 0;
   for (u = 0; u < v; u++)
     tb->indici[u + 1] += tb->indici[u];
   sprintf (NOME_FILE, "%s%s%s", tb->DIR_NOME, COMPRESSA_PREFISSO, tb->string);
   F = fopen (NOME_FILE, "w");
   HYPER_INDEXING = (tb->p[3] != 0);
   if (HYPER_INDEXING)
     {
       hyper_index (F, v, tb);
       goto FINI;
     }
   v++;
   /* Header 4 bytes 0xca 0x7f 0x0b 0xaa */
   fputc (0xca, F);
   fputc (0x7f, F);
   fputc (0x0b, F);
   fputc (0xaa, F);
   /* Header block size */
   n = BLOCCO_PRO | (uBWT << 28);
   fputc (n & 255, F);
   fputc ((n >> 8) & 255, F);
   fputc ((n >> 16) & 255, F);
   fputc ((n >> 24) & 255, F);
   /* Header 4 null bytes */
   fputc (0, F);
   fputc (0, F);
   fputc (0, F);
   fputc (0, F);
   /* Header indici count */
   fputc (v & 255, F);
   fputc ((v >> 8) & 255, F);
   fputc ((v >> 16) & 255, F);
   fputc ((v >> 24) & 255, F);
   fwrite (tb->indici, sizeof (uint32), v, F); /* ENDIAN */
   fclose (F);
   v = 0;
   sprintf (NOME_FILE, "%s%s%s",
	    tb->DIR_NOME, COMPRESSA_PREFISSO + 1, tb->string);
   F = fopen (NOME_FILE, "w");
   for (u = 0; u < LIMITE; u += BLOCCO_PRO, v++)
     fwrite (tb->data + u, 1, tb->indici[v + 1] - tb->indici[v], F);
   fclose (F); /* BUG */
 FINI:
   free (tb->indici);
   tb->indici = NULL;
}

static void TotalBaseMake (RobboTotalBase * Tot1, RobboTotalBase * Tot2)
{
  Tot1->DTR = Tot2->DTR = DTR;
  if (Tot1 == Tot2)
    RobboBUILD_stesso (Tot1);
  else
    TotalBaseBuild (Tot1, Tot2);
}

void NOME_INVERSO (char *I, char *O)
{
  int i;
  boolean x;
  for (i = 0; i < 4; i++)
    O[i] = (I[i] == '0' || !I[i] || (I[i] >= 'U' && I[i] <= 'Z'))
      ? I[i] : I[i] ^ 32;
  nome_canonico (O, &x);
}

#include <string.h>
#define EFGH_BUILD TRUE
#define IsZPp(x) (((x) == 'Z') || ((x) == 'P') || ((x) == 'p'))
void RTBfare (char *nome_in, boolean simm)
{
  int n, i, rt1, rt2;
  char inverso_nome[64], DIRECTORY[1024], NOME[64], nome[16];
  char* Z;
  char* p;
  char* P;
  uint64 Clock = GetClock ();
  boolean x;
  for (i = 0; i < 8; i++)
    NOME[i] = nome[i] = 0;
  strcpy (nome, nome_in);
  n = nome_canonico (nome, &x);
  RobboTotal_sott (nome); /* close EFGHij also */
  strcpy (NOME, nome);
  if (NOME[0] == 'K' || NOME[0]=='k')
    un_windows (NOME);
  for (i = 0; i < 4; i++)
    if (NOME[i] == '0')
      NOME[i] = 0;
  for (i = 3; NOME[i - 2]; i++);
  sprintf (DIRECTORY, "%s/%d/", TOTAL_BASE_DIRECTORY, i);
  while (NOME[3] && EFGH_BUILD) /* HACK */
    {
      if (NOME[3] && strchr ("EFGHefghUVWXijIJ", NOME[3]))
	break;
      if (NOME[2] && strchr ("EFGHefghUVWXijIJ", NOME[2]))
	break;
      if (NOME[1] && strchr ("EFGHefghUVWXijIJ", NOME[1]))
	break;
      if (NOME[0] && strchr ("EFGHefghUVWXijIJ", NOME[0]))
	break;
      if (NOME[3] && NOME[3] == NOME[2] && IsZPp (NOME[3]))
	break;
      if (NOME[2] && NOME[2] == NOME[1] && IsZPp (NOME[2]))
	break;
      if (NOME[1] && NOME[1] == NOME[0] && IsZPp (NOME[1]))
	break;
      if (NOME[3] && NOME[3] == NOME[1])
	break;
      if (NOME[2] && NOME[2] == NOME[0])
	break;
      if (!IsZPp (NOME[0]) && !IsZPp (NOME[1]) &&
	  !IsZPp (NOME[2]) && !IsZPp (NOME[3]))
	break;
      Z = strchr (NOME, 'Z');
      if (Z)
	{
	  Z[0] = 'U';
	  RTBfare (NOME, simm);
	  Z[0] = 'V';
	  RTBfare (NOME, simm);
	  Z[0] = 'W';
	  RTBfare (NOME, simm);
	  Z[0] = 'X';
	  RTBfare (NOME, simm);
	  Z[0] = 'U';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  Z[0] = 'V';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  Z[0] = 'W';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  return;
	}
      P = strchr (NOME, 'P');
      p = strchr (NOME, 'p');
      if (P && !p)
	{
	EXPAND_P:
	  P[0] = 'E';
	  RTBfare (NOME, FALSE);
	  P[0] = 'F';
	  RTBfare (NOME, FALSE);
	  P[0] = 'G';
	  RTBfare (NOME, FALSE);
	  P[0] = 'H';
	  RTBfare (NOME, FALSE);
	  P[0] = 'E';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  P[0] = 'F';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  P[0] = 'G';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  return;
	}
      if (!P && p)
	{
	EXPAND_p:
	  p[0] = 'e';
	  RTBfare (NOME, FALSE);
	  p[0] = 'f';
	  RTBfare (NOME, FALSE);
	  p[0] = 'g';
	  RTBfare (NOME, FALSE);
	  p[0] = 'h';
	  RTBfare (NOME, FALSE);
	  p[0] = 'e';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  p[0] = 'f';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  p[0] = 'g';
	  RobboTotal_registro (NOME, DIRECTORY);
	  NOME_INVERSO (NOME, inverso_nome);
	  n = nome_canonico (inverso_nome, &x);
	  RobboTotal_registro (inverso_nome, DIRECTORY);
	  return;
	}
      if (simm)
	{
	  P[0] = 'I';
	  p[0] = 'i';
	  RTBfare (NOME, TRUE);
	  p[0] = 'j';
	  RTBfare (NOME, FALSE); /* inversion iJ */
	  P[0] = 'J';
	  RTBfare (NOME, TRUE);
	  P[0] = 'I';
	  RobboTotal_registro (NOME, DIRECTORY);
	  p[0] = 'i';
	  RobboTotal_registro (NOME, DIRECTORY);
	  P[0] = 'J';
	  RobboTotal_registro (NOME, DIRECTORY);
	  return;
	}
      if (P - NOME == 0)
	goto EXPAND_p;
      if (p - NOME == 3)
	goto EXPAND_P;
      if (strchr (NOME, 'Q'))
	goto EXPAND_P;
      if (strchr (NOME, 'q'))
	goto EXPAND_p;
      if (strchr (NOME, 'R'))
	goto EXPAND_P;
      if (strchr (NOME, 'r'))
	goto EXPAND_p;
      if (strchr (NOME, 'B'))
	goto EXPAND_P;
      if (strchr (NOME, 'b'))
	goto EXPAND_p;
      if (strchr (NOME, 'N'))
	goto EXPAND_P;
      if (strchr (NOME, 'n'))
	goto EXPAND_p;
    }
  RobboTotal_add (TABLE_TOTAL_BASES + NUM_TOTAL_BASES, nome, DIRECTORY);
  NOME_INVERSO (nome, inverso_nome);
  inverso_nome[n] = 0;
  if (!simm)
    {
      nome_canonico (inverso_nome, &x);
      RobboTotal_sott (inverso_nome);
      RobboTotal_add (TABLE_TOTAL_BASES + NUM_TOTAL_BASES, inverso_nome, DIRECTORY);
    }
  rt2 = NUM_TOTAL_BASES - 1;
  if (simm)
    rt1 = NUM_TOTAL_BASES - 1;
  else
    rt1 = NUM_TOTAL_BASES - 2;
  TotalBaseMake (TABLE_TOTAL_BASES + rt1, TABLE_TOTAL_BASES + rt2);
  RobboTotal_sott (nome);
  if (!simm)
    RobboTotal_sott (inverso_nome);
  RobboTotal_registro (nome, DIRECTORY);
  if (!simm)
    RobboTotal_registro (inverso_nome, DIRECTORY);
  printf ("Fine %s: %.2fs\n", nome,
	  ((double) (GetClock () - Clock)) / 1000000.0);
  fflush (stdout);
}

static int CACHE_SIZE;
void TotalBaseInit ()
{
  int pi1, pi2, pi3, pi4;
  int i;
  InitTotalBaseUtility (TRUE);
  NUM_TOTAL_BASES = 0;
  for (pi1 = 0; pi1 < 16; pi1++)
    for (pi2 = 0; pi2 < 16; pi2++)
      for (pi3 = 0; pi3 < 16; pi3++)
	for (pi4 = 0; pi4 < 16; pi4++)
	  TotalBaseTable[pi1][pi2][pi3][pi4] = -1;
  TABLE_TOTAL_BASES = malloc (MAX_TABLES * sizeof (RobboTotalBase));
  for (i = 0; i < MAX_TABLES; i++)
    (TABLE_TOTAL_BASES + i)->Fdata = NULL;
  InitInitTotalBaseCache (CACHE_SIZE);
}

#include <strings.h>
#define MAX_NUM 4

static void simmetria (char *C, char *SIM)
{
  int i;
  for (i = 0; C[i]; i++)
    SIM[i] = C[i] ^ 32;
  for (i = 0; C[i]; i++)
    if (SIM[i] == 'z')
      SIM[i] ^= 32;
  SIM[i] = 0;
}

#define RECURSE(C, B) \
 if (RobboTotal_scop (C) == -1) \
  { if (B) { printf ("Recursing %s\n", C); TotalBasePrepare (C, B); } \
    else { printf ("Needed dependency %s unavailable\n", C); return; } }

static void TotalBasePrepare (char *AB, boolean B)
{
  int i, j, n;
  boolean simm = FALSE;
  char A[16], C[16], SIM[16], PEZb[8] = "QRBN", PEZn[8] = "qrbn";
  strcpy (A, AB);
  if (A[0] == 'K' || A[0] == 'k')
    un_windows (A);
  n = nome_canonico (A, &simm);
  strcpy (C, A);
  for (i = 0; i < n; i++)
    {
      if (C[i] == 'P')
	{
	  for (j = 0; j < 4; j++)
	    {
	      C[i] = PEZb[j];
	      RECURSE (C, B);
	      simmetria (C, SIM);
	      RECURSE (SIM, B);
	    }
	  C[i] = 'P';
	}
      if (C[i] == 'p')
	{
	  for (j = 0; j < 4; j++)
	    {
	      C[i] = PEZn[j];
	      RECURSE (C, B);
	      simmetria (C, SIM);
	      RECURSE (SIM, B);
	    }
	  C[i] = 'p';
	}
      if (C[i] == 'Z')
	{
	  C[i] = 'P';
	  RECURSE (C, B);
	  simmetria (C, SIM);
	  RECURSE (SIM, B);
	  for (j = 0; j < n; j++)
	    {
	      char u = C[j];
	      if (i == j || (C[j] >= 'A' && C[j] <= 'Z'))
		continue;
	      C[j] = 'p';
	      RECURSE (C,B);
	      simmetria (C, SIM);
	      RECURSE (SIM, B);
	      C[j] = u;
	    }
	  C[i] = 'p';
	  RECURSE (C, B);
	  simmetria (C, SIM);
	  RECURSE (SIM, B);
	  for (j = 0; j < n; j++)
	    {
	      char u = C[j];
	      if (i == j || (C[j] >= 'a' && C[j] <= 'z'))
		continue;
	      C[j] = 'P';
	      RECURSE (C,B);
	      simmetria (C, SIM);
	      RECURSE (SIM, B);
	      C[j] = u;
	    }
	  C[i] = 'Z';
	}
    }
  for (i = 0; i < n; i++)
    {
      C[i] = A[n - 1];
      C[n - 1] = 0;
      RECURSE (C, B);
      simmetria (C, SIM);
      RECURSE (SIM, B);
      C[i] = A[i];
    }
  RTBfare (A, simm);
}

void reindici (char*); /* hiperindici */
void stats (char*); /* fail hiperindici compatible */
void zugzwang (char*);
void MakeBlockIndex (char*);

void argomenti_lavora (int n, char **A)
{
  int i, b = 0;
  char STRUT[1024][16], OTT[1024];
  boolean LOAD3 = TRUE, LOAD4 = TRUE, LOAD5 = TRUE, LOAD6 = TRUE,
    LOAD = TRUE, RECURSE = FALSE, ZUGZWANG = FALSE;
  boolean STATS = FALSE, REINDICI = FALSE;
  if (!strcmp (A[1], "--BlockIndex"))
    {
      MakeBlockIndex (A[2]);
      return;
    }
  for (i = 1; i < n; i++)
    {
      if (!strcmp (A[i], "--cpus"))
	{
	  RB_CPUS = atoi(A[++i]);
	  continue;
	}
#if 0
      if (!strcmp (A[i], "--dtr")) /* now in the unworked */
	{
	  DTR = TRUE;
	  continue;
	}
#endif
      if (!strcmp (A[i], "--cache"))
	{
	  CACHE_SIZE = atoi(A[++i]);
	  continue;
	}
      if (!strcmp (A[i], "--verboso"))
	{
	  TOTAL_VERBOSO = 1;
	  continue;
	}
      if (!strcmp (A[i], "--reindici"))
	{
	  REINDICI = TRUE;
	  continue;
	}
      if (!strcmp (A[i], "--noswap"))
	{
	  DISK_SWAP = FALSE;
	  continue;
	}
      if (!strcmp (A[i], "--zugzwang"))
	{
	  ZUGZWANG = TRUE;
	  LOAD = FALSE;
	  continue;
	}
      if (!strcmp (A[i], "--stats"))
	{
	  STATS = TRUE;
	  LOAD = FALSE;
	  continue;
	}
      if (!strcmp (A[i], "--recurse"))
	{
	  RECURSE = TRUE;
	  continue;
	}
      if (!strcmp (A[i], "--noload"))
	{
	  LOAD = FALSE;
	  continue;
	}
      if (!strcmp (A[i], "--noload3"))
	{
	  LOAD3 = FALSE;
	  continue;
	}
      if (!strcmp (A[i], "--noload4"))
	{
	  LOAD4 = FALSE;
	  continue;
	}
      if (!strcmp (A[i], "--noload5"))
	{
	  LOAD5 = FALSE;
	  continue;
	}
      if (!strcmp (A[i], "--noload6"))
	{
	  LOAD6 = FALSE;
	  continue;
	}
      strcpy (STRUT[b++], A[i]);
    }
  if (LOAD)
    {
      if (LOAD3)
	{
	  sprintf (OTT, "%s/3", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	}
      if (LOAD4)
	{
	  sprintf (OTT, "%s/4", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	}
      if (LOAD5)
	{
	  sprintf (OTT, "%s/5", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	}
      if (LOAD6)
	{
	  sprintf (OTT, "%s/6", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	  sprintf (OTT, "%s/51", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	  sprintf (OTT, "%s/42", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	  sprintf (OTT, "%s/33", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	  sprintf (OTT, "%s/Z", TOTAL_BASE_DIRECTORY);
	  GetTotalBase (OTT);
	}
    }
  if (STATS)
    {
      GLOBAL_STATS_INIT ();
      for (i = 0; i < b; i++)
	stats (STRUT[i]);
      if (b <= 1)
	return;
      GLOBAL_STATS_EMIT ();
      return;
    }
  if (ZUGZWANG)
    {
      for (i = 0; i < b; i++)
	zugzwang (STRUT[i]);
      return;
    }
  if (REINDICI)
    {
      for (i = 0; i < b; i++)
	reindici (STRUT[i]);
      return;
    }
  for (i = 0; i < b; i++)
    TotalBasePrepare (STRUT[i], RECURSE);
}


void ResetHistory () {}
void ResetPositionalGain() {}
int InitMaterialValue() { return 0; }
void InitStatic() {} /* HACK */

/* Copyright (c) Roberto Pescatore plus Decembrists (all), PUBLICDOMAIN (workers) */

int main (int argc, char **argv)
{
  RB_CPUS = 1;
  CACHE_SIZE = 64; /* more with 6 pezzo? */
  LIST_SIZE = (1 << 20); /* 8MB per cpu, 5+ pezzo */ /* 64M with 6 pezzo? */
  HYPER_INDEXING = FALSE;
  DISK_SWAP = TRUE;
  TRY_LARGE_PAGES = FALSE;
  TOTAL_VERBOSO = 0;
  DTR = FALSE;
  InitSlab (4);
  TotalBaseInit ();
  iniz_vario ();
  strcpy (TOTAL_BASE_DIRECTORY, "RobboTotalBase");
  strcpy (TRIPLE_DIR, "RobboTripleBase");
  /*  INIT_TRIPLE_BASE (); */
  LOCK_INIT (FWRITE_LOCK);
  argomenti_lavora (argc, argv);
  LOCK_DESTROY (FWRITE_LOCK);
  exit (0);
  return 0;
}
