// Copyright 1995 by Jon Dart
// Stand-alone console executable to build "ecodata.h" file
// from "eco" text file.

#include "stdafx.h"
#include "board.h"
#include "rmove.h"
#include "notation.h"
#include "movearr.h"
#include "movegen.h"
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>

char *programPath;

#define INVALID 0x3f

void charout(unsigned char c)
{
    if (c == '"')
    {
        cout << '\\' << '"';
    }
    else if (c == '\\')
    {
        cout << '\\' << '\\';
    }
    else if (c >= ' ' && (int)c < 127)
    {
        cout << c;
    }
    else
    {
        cout << '\\';
	cout.fill('0');
	int oldwidth = cout.width();
	cout.width(3);
	cout << (oct) << (unsigned)c;
	cout.width(oldwidth);
	cout.fill(' ');
    }
}

static void write_64(char *buf, hash_t h)
{
    struct llong
    {
       int32 lo;
       int32 hi;
    };
    union
    {
        llong split;
        hash_t i64;
    } x;

    x.i64 = h;
    sprintf(buf,"%0x%0x",x.split.hi,x.split.lo);
}

static int skip_space(ifstream &eco_file)
{
    char c;
    while (!eco_file.eof())
    {
       c = eco_file.get();
       if (!isspace(c) && (c!='\n'))
       {
	   break;
       }
    }
    return c;
}

static BOOL legal_move(const Board &board, const Square &start,
  const Square &dest)
{
	// do a little basic sanity checking:
	  if (!start.OnBoard() || !dest.OnBoard() || board[start].IsEmpty())
	      return FALSE;

	  ExtendedMove emove(board,start,dest);
	  static Move possible_moves[Move_Generator::MaxMoves];
	  Move_Generator mg( board, 0, Move::NullMove() );
	  int found = 0;
          int n = mg.Generate_Moves(possible_moves, FALSE);

	  for (int i = 0; i < n; i++)
          {
	      if (possible_moves[i].StartSquare() == emove.StartSquare() &&
	      	  possible_moves[i].DestSquare() == emove.DestSquare())
	      {
		     found++;
		     break;
	      }
	  }
	  if (!found)
	      return FALSE;
          else	      
	  {
	      // check for king en prise
	      Board board_copy(board);
	      const ColorType side = board.Side();
	      board_copy.MakeMove(emove);
	      return board_copy.num_attacks(
	      	board_copy.KingPos(side),OppositeColor(side)) == 0;
	      
	  }
}

void do_eco(ifstream &eco_file)
{
    ColorType side = White;
    Board board;
    int movecount = 0;
    char c;
    // Collect the ECO code
    c = skip_space(eco_file);
    static char code[20];
    int i = 0;
    if (isalpha(c) && isupper(c))
    {
        while (!eco_file.eof() && !isspace(c) && i < 19)
	{
           code[i++] = c;
	   c = eco_file.get();
	}
    }
    code[i] = '\0';
    if (i == 0)
        return;
    cout << '{' << '"' << code << '"' << ", ";
    static char name[255];
    char *name_ptr = name;
    *name_ptr = '\0';
    // Follow the opening line
    unsigned int x;
    while (eco_file.good() && !eco_file.eof())
    {
       // skip to next move
       while (!eco_file.eof())
       {
	  if (c == '\n' || c == '"')
	      break;
	  else if (isalpha(c))
	  {
	     break;
	  }
          c = eco_file.get();
       }
       if (c == '"')
       {
          while (!eco_file.eof())
          {
	     c = eco_file.get();
	     if (c == '"')
                 break;
             else
                 *name_ptr++ = c;
          }
	  *name_ptr = '\0';
          while (!eco_file.eof() && c != '\n')
             c = eco_file.get();
       }
       if (c == '\n')
          break;
       // collect the move text
       char movebuf[20];
       int i = 0;
       while (i < 19 && !eco_file.eof() && 
       	      !isspace(c) && (c != '\n'))
       {
          movebuf[i] = c; ++i;
	  c = eco_file.get();
       }
       if (i == 0)
       	  break;
       movebuf[i] = '\0';
       // parse the move
       Move m = Notation::Value(board,side,movebuf);
       if (m.IsNull() ||
       	   !legal_move(board,m.StartSquare(),
	       m.DestSquare()))
       {
           cerr << "Illegal or invalid move: " << movebuf << endl;
           cout << "Illegal or invalid move: " << movebuf << endl;
	   break;
       }
       else
       {
           ++movecount;
       	   x = m.StartSquare();
//	   charout((char)x);
	   x = m.DestSquare();
//	   charout((char)x);
	   ExtendedMove emove(board,m);
	   ReversibleMove rmove(board,emove);
	   board.MakeMove(rmove);
       }
       side = OppositeColor(side);
    }
    char buf[32];
    write_64(buf,board.HashCode());
    cout << (hex) << "0x" << buf << " ,";
    if (*name)
       cout << '"' << name << '"';
    else
       cout << '"' << '"';
    cout << "},";
    cout << endl;
}

int main(int argc, char **argv)
{
   if (argc ==1)
   {
	 cerr << "Usage: makeeco eco_file" << endl;
	 return -1;
   }
   programPath = strdup(argv[0]);
   ifstream eco_file( argv[argc-1], ios::in);
   if (!eco_file.good())
   {
         cerr << "Cannot open file: " << argv[argc-1] << endl;
	 return -1;
   }
   Board b;
   cout << "// This is a machine-generated file.  Do not edit." << endl;
   cout << endl;   
   cout << "#include \"types.h\"" << endl << endl;
   cout << "struct eco_data" << endl;
   cout << "{" << endl;
   cout << "\tchar *eco;" << endl;
   cout << "\thash_t hash_code;" << endl;
   cout << "\tchar *opening_name;" << endl;
   cout << "};" << endl;
   cout << endl;
   cout << "const struct eco_data eco_codes[] =" << endl;
   char buf[32];
   write_64(buf,b.HashCode());
   cout << "{{" << '"' << "A00" << '"' << ", 0x" << (hex) << 
       buf << ", " << 
     '"' << '"' << "}," << endl;
   while (eco_file.good() && !eco_file.eof())
   {
       do_eco(eco_file);
   }
   cout << "{0,0," << '"' << '"' << "}};" << endl;
   return 0;
}
