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

static uint64 GLOBAL_STATS[256];
void reindici (char *A) /* hiperindici */ /* obsolete */
{
  char C[16], NOME[64], DIRECTORY[1024], STR[1024], NI_STR[1024], ND_STR[1024];
  boolean B = FALSE;
  int i, k, v, j, J;
  RobboTotalBase *rtb;
  uint64 rf, pr, PR;
  uint8* Z;
  uint32* p;
  uint32 by;
  sint32 w;
  FILE* NEW_INDEX;
  FILE* NEW_DATA;
  strcpy (C, A);
  if (C[0] == 'K' || C[0] == 'k')
    un_windows (C);
  nome_canonico (C, &B);
  strcpy (NOME, C);
  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);
  RobboTotal_registro (C, DIRECTORY);
  v = RobboTotal_scop (C);
  if (v == -1)
    {
      printf ("File not found %s\n", A);
      return;
    }
  rtb = (TABLE_TOTAL_BASES + v);
  if (rtb->BLOCCO_pro == 0x100000)
    {
      printf ("Done already reindici %s\n", A);
      return;
    }

  rf = rtb->PEDONE ? 1806 : 462;
  pr = rtb->PawnMult;
  PR = pr * rf;
  Z = malloc(65536);
  J = (PR && 65535) + (PR >> 16);

  p = rtb->indici;
  sprintf (STR, "%s%s%s", rtb->DIR_NOME, COMPRESSA_PREFISSO + 1, rtb->string);
  rtb->Fdata = fopen (STR, "rb");

  sprintf (NI_STR, "%sNEW%s%s", rtb->DIR_NOME, COMPRESSA_PREFISSO, rtb->string);
  NEW_INDEX = fopen (NI_STR, "w");
  sprintf (ND_STR, "%sNEW%s%s", rtb->DIR_NOME, COMPRESSA_PREFISSO + 1, rtb->string);
  NEW_DATA = fopen (ND_STR, "w");

  fputc (0xca, NEW_INDEX);
  fputc (0x7f, NEW_INDEX);
  fputc (0x0b, NEW_INDEX);
  fputc (0xaa, NEW_INDEX);
  by = (rtb->BWT << 28) | 0x100000; /* hiperindici */
  fputc (by & 0xff, NEW_INDEX);
  fputc ((by >> 8) & 0xff, NEW_INDEX);
  fputc ((by >> 16) & 0xff, NEW_INDEX);
  fputc ((by >> 24) & 0xff, NEW_INDEX);
  fputc (0, NEW_INDEX);
  fputc (0, NEW_INDEX);
  fputc (0, NEW_INDEX);
  fputc (0, NEW_INDEX);
  J--;
  by = 2 + (J >> 4); /* num_indici */
  printf ("Force (%d+1) indici to (%d+1)\n", J, by - 1);
  fputc (by & 0xff, NEW_INDEX);
  fputc ((by >> 8) & 0xff, NEW_INDEX);
  fputc ((by >> 16) & 0xff, NEW_INDEX);
  fputc ((by >> 24) & 0xff, NEW_INDEX);
  w = 0;
  for (j = 0; j + 0x10 < J; j += 0x10)
    {
      fwrite (&w, 4 , 1, NEW_INDEX);
      w += p[j + 0x10] - p[j] + 128;
    }
  fwrite (&w, 4, 1, NEW_INDEX);
  w += p[J] - p[j] + 128;
  fwrite (&w, 4, 1, NEW_INDEX);

  fclose (NEW_INDEX);
  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, NEW_DATA);
	  w = p[j + k + 1] - p[j + k];
	  fwrite (&w, 4, 1, NEW_DATA);
	}
      for (k = 0; k < 0x10; k++)
	{
	  w = p[j + k + 1] - p[j + k];
	  fread (Z, 1, w, rtb->Fdata);
	  fwrite (Z, 1, w, NEW_DATA);
	}
    }
  for (k = 0; k < 0x10; k++)
    {
      if (j + k >= J)
	w = 0;
      else
	w = 128 + p[j + k] - p[j];
      fwrite (&w, 4, 1, NEW_DATA);
      if (j + k >= J)
	w = 0;
      else
	w = p[j + k + 1] - p[j + k];
      fwrite (&w, 4, 1, NEW_DATA);
    }
  for (k = 0; k < 0x10; k++)
    {
      if (j + k < J)
	{
	  w = p[j + k + 1] - p[j + k];
	  fread (Z, 1, w, rtb->Fdata);
	  fwrite (Z, 1, w, NEW_DATA);
	}
    }
  fclose (NEW_DATA);
  fclose (rtb->Fdata);
}

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

static void BlockIndexAdd (char* DIR, char* NOME, FILE* F)
{
  char A[1024];
  FILE* iF;
  int i, num_indici = 0;
  if (NOME[0] != 'i')
    return; /* not index */
  sprintf (A, "%s/%s", DIR, NOME);
  NOME += strlen ("iCOMP.");
  if (NOME[0] == 'K' || NOME[0] == 'k')
    un_windows (NOME);
  i = 0;
  while (NOME[i])
    i++;
  while (i <= 4)
    NOME[i++] = 0;
  fputc (0xee, F);
  fputc (0x63, F);
  fputc (0x70, F);
  fputc (0x41, F);
  fwrite (NOME, 1, 4, F);
  iF = fopen (A, "rb");
  fread (A, 1, 4, iF); /* mask */
  fread (A, 1, 4, iF); /* block size + compression */
  fwrite (A, 1, 4, F);
  fread (A, 1, 4, iF); /* empty */
  fread (A, 1, 4, iF); /* index counting */
  fwrite (A, 1, 4, F);
  for (i = 0; i < 4; i++)
    num_indici |= A[i] << (8 * i);
  for (i = 0; i < num_indici; i++)
    {
      fread (A, 1, 4, iF);
      fwrite (A, 1, 4, F);
    }
  fclose (iF);
}

#ifdef WINDOWS /* HACK */
void MakeBlockIndex (char* A)
{
  char B[1024], NOME[1024];
  WIN32_FIND_DATA ffd;
  HANDLE hFind = INVALID_HANDLE_VALUE;
  FILE* F;
  
  SEND ("info string Reading directory %s\n", A);
  strcpy (B, A);
  strcat (B, "\\*");
  hFind = FindFirstFile (B, &ffd);
  if (hFind == INVALID_HANDLE_VALUE)
    {
      SEND ("info string Directory %s not found\n", A);
      return;
    }
  sprintf (NOME, "%s/BLOCK.INDEX", A);
  F = fopen (NOME, "wb");
  if (!F)
    {
      SEND ("Cannot write to %s\n", NOME);
      return;
    }
  do
    {
      if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) /* recurse ? */
        BlockIndexAdd (A, ffd.cFileName, F);
    }
  while (FindNextFile (hFind, &ffd));
  FindClose (hFind);
  fclose (F);
}
#else
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
void MakeBlockIndex (char* A)
{
  DIR *dir;
  struct dirent *DE;
  char NOME[1024];
  FILE* F;
  SEND ("info string Reading directory %s\n", A);
  dir = opendir (A);
  if (!dir)
    {
      SEND ("info string Directory %s not found\n", A);
      return;
    }
  sprintf (NOME, "%s/BLOCK.INDEX", A);
  F = fopen (NOME, "w");
  if (!F)
    {
      SEND ("Cannot write to %s\n", NOME);
      return;
    }
  while ((DE = readdir (dir)))
    BlockIndexAdd (A, DE->d_name, F);
  closedir (dir);
  fclose (F);
}
#endif

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

static char* Name (int j, char* S)
{
  if (j == dROTT)
    strcpy (S, "Broken: ");
  if (j == dVITT)
    strcpy (S, "Win: ");
  if (j == dPATT)
    strcpy (S, "Draw: ");
  if (j >= dPERD0)
    sprintf (S, "Loss in %d: ", j - dPERD0);
  return S;
}

static void ZUG (char* A, tipo_fPOS* fpos, int r1, int r2, char* S)
{
  int k;
  char PI[16][4] = {"", "wP", "wN", "wK", "wB", "wB", "wR", "wQ",
		    "", "bP", "bN", "bK", "bB", "bB", "bR", "bQ"};
  printf("%s - wK%c%c bK%c%c ", A,
	 'a' + FILE (fpos->wK), '1' + RANK (fpos->wK),
	 'a' + FILE (fpos->bK), '1' + RANK (fpos->bK));
  for (k = 0; fpos->pi[k] && k < 4 ;k++)
    if (fpos->pi[k] == BlockedPawn)
      printf("wP%c%c bP%c%c ",
	     'a' + FILE (fpos->sq[k]), '1' + RANK (fpos->sq[k]),
	     'a' + FILE (fpos->sq[k]), '2' + RANK (fpos->sq[k]));
    else
      printf("%s%c%c ", PI[fpos->pi[k]],
	     'a' + FILE (fpos->sq[k]), '1' + RANK (fpos->sq[k]));
  printf("%d %d %s\n", r1, r2, S);
}

void FORZA_POS (RobboTotalBase *, uint64, tipo_fPOS *, boolean);
void stats (char *A) /* fail hiperindici compatible */ /* SMP? */
{
  char C[16], NOME[64], DIRECTORY[1024], STR[1024], STR2[32];
  boolean B = FALSE, b;
  int i, k ,v, j, t;
  uint64 c[256], S, yw;
  uint8* Y;
  uint8* Z;
  uint32* p;
  RobboTotalBase* TB;
  uint8 ARR[128], y;
  strcpy (C, A);
  if (C[0] == 'K' || C[0] == 'k')
    un_windows (C);
  nome_canonico (C, &B);
  strcpy (NOME, C);
  for (i = 0; i < 4; i++)
    if (NOME[i] == '0')
      NOME[i] = 0;
  NOME[4] = 0;
  for (i = 3; NOME[i - 2]; i++);
  sprintf (DIRECTORY, "%s/%d/", TOTAL_BASE_DIRECTORY, i);
  b = RobboTotal_registro (C, DIRECTORY);
  if (b)
    goto SEARCH;
  if (i == 6)
    {
      sprintf (DIRECTORY, "%s/42/", TOTAL_BASE_DIRECTORY);
      b = RobboTotal_registro (C, DIRECTORY);
      if (b)
	goto SEARCH;
      sprintf (DIRECTORY, "%s/33/", TOTAL_BASE_DIRECTORY);
      b = RobboTotal_registro (C, DIRECTORY);
      if (b)
	goto SEARCH;
      sprintf (DIRECTORY, "%s/51/", TOTAL_BASE_DIRECTORY);
      b = RobboTotal_registro (C, DIRECTORY);
      if (b)
	goto SEARCH;
    }
  sprintf (DIRECTORY, "%s/Z/", TOTAL_BASE_DIRECTORY);
  b = RobboTotal_registro (C, DIRECTORY);
 SEARCH:
  v = RobboTotal_scop (C);
  if (!b || v == -1)
    {
      printf ("File not found %s\n", A);
      return;
    }
  for (i = 0; i < 256; i++)
    c[i] = 0;
  TB = (TABLE_TOTAL_BASES + v);
  Y = malloc (65536);
  Z = malloc (1048576 + 4096);
  p = TB->indici;
  sprintf (STR, "%s%s%s", TB->DIR_NOME, COMPRESSA_PREFISSO + 1, TB->string);
  TB->Fdata = fopen (STR, "rb");
  y = dPERD0;
  yw = -1;
  if (TB->BLOCCO_pro == 0x10000)
    for (j = 0; j < TB->num_indici - 1; j++)
      {
	int d, w = p[j+1] - p[j];
	fread (Z, 1, w, TB->Fdata);
	d = blocco_decompressa (Y, Z, w, TB->TYPE);
	for (k = 0; k < d; k++)
	  {
	    c[Y[k]]++;
	    if (Y[k] > y)
	      {
		y = Y[k];
		yw = j * 0x10000 + k;
	      }
	  }
      }
  else
    for (j = 0; j < TB->num_indici - 1; j++)
      {
	int d, w = p[j+1] - p[j];
	fread (ARR, 1, 128, TB->Fdata);
	fread (Z, 1, w - 128, TB->Fdata);
	for (t = 0; t < 0x10; t++)
	  {
	    if (!((uint32*) ARR)[2 * t])
	      continue;
	    d = blocco_decompressa (Y, Z - 128 + ((uint32*) ARR)[2 * t],
				    ((uint32*) ARR)[2 * t + 1], TB->TYPE);
	    for (k = 0; k < d; k++)
	      {
		c[Y[k]]++;
		if (Y[k] > y)
		  {
		    y = Y[k];
		    yw = (16 * j + t) * 0x10000 + k;
		  }
	      }
	  }
      }
  for (j = 0; j < 256; j++)
    if (c[j])
      printf ("%s %lld\n", Name (j, STR2), c[j]);
  S = 0;
  for (j = 0; j < 256; j++)
    S += c[j];
  for (j = 0; j < 256; j++)
    GLOBAL_STATS[j] += c[j];
  printf ("Total %lld\n", S);
  if (yw != -1)
    {
      tipo_fPOS fpos[1];
      FORZA_POS (TB, yw, fpos, TRUE);
      ZUG ("maximal loss", fpos, y - dPERD0, 0, NOME);
    }
  free (Y);
  free (Z);
  fclose (TB->Fdata);
}

void NOME_INVERSO (char *, char *);
void zugzwang (char* nome)
{
  char C[64], B[64], DIRECTORY[1024], STR[1024];
  boolean simm = FALSE, b;
  int i, v2, v, rf;
  uint64 sz, ind;
  RobboTotalBase* TB;
  RobboTotalBase* TB2;
  tipo_fPOS fpos[1];
  uint8 r1, r2;

  nome[4] = 0;
  for (i = 0; nome[i]; i++);
  if (i == 0)
    i = 1;
  sprintf (DIRECTORY, "%s/%d/", TOTAL_BASE_DIRECTORY, i + 2);
  strcpy(C, nome);
  nome_canonico (C, &simm);
  b = RobboTotal_registro (C, DIRECTORY);
  if (b)
    goto SEARCH;
  if (i == 4)
    {
      sprintf (DIRECTORY, "%s/42/", TOTAL_BASE_DIRECTORY);
      b = RobboTotal_registro (C, DIRECTORY);
      if (b)
	goto SEARCH;
      sprintf (DIRECTORY, "%s/33/", TOTAL_BASE_DIRECTORY);
      b = RobboTotal_registro (C, DIRECTORY);
      if (b)
	goto SEARCH;
      sprintf (DIRECTORY, "%s/51/", TOTAL_BASE_DIRECTORY);
      b = RobboTotal_registro (C, DIRECTORY);
      if (b)
	goto SEARCH;
    }
  sprintf (DIRECTORY, "%s/Z/", TOTAL_BASE_DIRECTORY);
  b = RobboTotal_registro (C, DIRECTORY);
 SEARCH:
  v = RobboTotal_scop (C);
  if (!b || v == -1 || v == 0xffff)
    {
      printf ("File Mal\n");
      return;
    }
  TB = (TABLE_TOTAL_BASES + v);
  TB->simm = simm;
  sprintf (STR, "%s%s%s", TB->DIR_NOME, COMPRESSA_PREFISSO + 1, TB->string);
  TB->Fdata = fopen (STR, "rb");
  if (!simm)
    {
      NOME_INVERSO (C, B);
      nome_canonico (B, &simm);
      RobboTotal_registro (B, DIRECTORY);
      v2 = RobboTotal_scop (B);
    }
  else v2 = v;
  TB2 = (TABLE_TOTAL_BASES + v2);
  if (!b)
    {
      sprintf (STR, "%s%s%s", TB2->DIR_NOME, COMPRESSA_PREFISSO + 1, TB2->string);
      TB2->Fdata = fopen (STR, "rb");
    }
  rf = TB->PEDONE ? 1806 : 462;
  sz = TB->PawnMult;
  for (ind = 0; ind < sz * rf; ind++)
    {
      r1 = tot_valu (TB2, ind);
      if (r1 == dROTT)
	continue;
      FORZA_POS (TB2, ind, fpos, FALSE);
      r2 = tot_valu (TB, fpos->ind + fpos->re_fetta * sz);
      if (r1 >= dPERD0 && r2 >= dPERD0)
	ZUG ("0:1 1:0", fpos, r1 - dPERD0, r2 - dPERD0, "");
      if (r1 >= dPERD0 && r2 == dPATT)
	ZUG ("DRAW 1:0", fpos, 0, r1 - dPERD0, "");
      if (r1 == dPATT && r2 >= dPERD0)
	ZUG ("0:1 DRAW", fpos, r2 - dPERD0, 0, "");
    }
}

void GLOBAL_STATS_INIT ()
{
  int u;
  for (u = 0; u < 256; u++)
    GLOBAL_STATS[u] = 0;
}

void GLOBAL_STATS_EMIT ()
{
  int j;
  char STR2[64];
  printf ("GLOBAL STATS\n");
  for (j = 0; j < 256; j++)
    if (GLOBAL_STATS[j])
      printf ("%s %lld\n", Name (j, STR2), GLOBAL_STATS[j]);
}
