//
// fltk Front end for gnuchess  
//
// Based on the fltk game checkers
//
// Copyright 2001 by Andreas Holzer
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
//

// Modified a teeny bit by george (jirka at 5z dot com)

const char *copyright =
    "fltkGnuChess 0.2\n\n"
    "Based on the gnuchess 5 engine by Stuart Cracraft <cracraft@gnu.org>.\n"
    "Fltk interface is based on the Fltk test program checkers (GPL)\n\n"
    "The interface was adopted for use with the gnuchess engine by\n"
    "Woody in December/2001";

// Define FLTK to get the fltk interface
// Define VT100 to get the VT100 interface
// Define both to get a program that takes a -t switch

#define FLTK

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include <unistd.h>
#include <sys/poll.h>
#include <ctype.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

////////////////////////////////////////////////////////////////
// fltk interface:


#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Pixmap.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Menu_Item.H>
#include <FL/fl_ask.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Slider.H>
#include <FL/Fl_Value_Output.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Menu_Button.H>
#include <FL/Fl_Bitmap.H>

//#ifdef AGENDA
//#include <flpda/Widget_Factory.h>
//#endif

//----------------------------------------------------------------
// old 4-level NeXT images have been seperated into bitmaps so they
// can be drawn with arbitrary colors and real transparency.  This is
// rather tedious and perhaps fltk should provide a direct support
// to do this:

/* 1st version uses pixmaps, maybo for interest later when porting
to coloured screen

#include "pixmaps/bdd21.xpm"
#include "pixmaps/bdl21.xpm"
#include "pixmaps/bld21.xpm"
#include "pixmaps/bll21.xpm"
#include "pixmaps/kdd21.xpm"
#include "pixmaps/kdl21.xpm"
#include "pixmaps/kld21.xpm"
#include "pixmaps/kll21.xpm"
#include "pixmaps/ndd21.xpm"
#include "pixmaps/ndl21.xpm"
#include "pixmaps/nld21.xpm"
#include "pixmaps/nll21.xpm"
#include "pixmaps/pdd21.xpm"
#include "pixmaps/pdl21.xpm"
#include "pixmaps/pld21.xpm"
#include "pixmaps/pll21.xpm"
#include "pixmaps/qdd21.xpm"
#include "pixmaps/qdl21.xpm"
#include "pixmaps/qld21.xpm"
#include "pixmaps/qll21.xpm"
#include "pixmaps/rdd21.xpm"
#include "pixmaps/rdl21.xpm"
#include "pixmaps/rld21.xpm"
#include "pixmaps/rll21.xpm"               

*/

#include "bitmaps/b21o.bm"
#include "bitmaps/b21s.bm"
#include "bitmaps/k21o.bm"
#include "bitmaps/k21s.bm"
#include "bitmaps/n21o.bm"
#include "bitmaps/n21s.bm"
#include "bitmaps/p21o.bm"
#include "bitmaps/p21s.bm"
#include "bitmaps/q21o.bm"
#include "bitmaps/q21s.bm"
#include "bitmaps/r21o.bm"
#include "bitmaps/r21s.bm"

// --------------------------------------------------------
// Constants

#define CB_BT  6
#define CB_WT 16
#define CB_BH  3
#define CB_WH 13
#define CB_BR  1
#define CB_WR 11
#define CB_BD  2
#define CB_WD 12
#define CB_BK  5
#define CB_WK 15
#define CB_BB  4
#define CB_WB 14


#define CB_NO  0
#define CB_WHITE 1
#define CB_BLACK 0


#define BOXSIZE 23
#define BOXSIZE_X 20
#define BOXSIZE_Y 23
#define BORDER 3
#define BOARDSIZE (8*BOXSIZE+BORDER)
#define BMOFFSET 5

#define WINSIZE_X 160


#define ENG_STR 0
#define ENG_NEW 1
#define ENG_UNDO 2
#define ENG_SHOWBOARD 3
#define ENG_X 4
#define ENG_MOVE 5
#define ENG_SECONDS 6
#define ENG_SWITCH 7
#define ENG_LEVEL 8
#define ENG_CLOCK 9
#define ENG_EVAL  10

// --------------------------------------------------------
// prototypes

void interpretLine(char *s);
void printcBoard();

void autoplay_cb(Fl_Widget *, void *);
void legal_cb(Fl_Widget *, void *);
void move_cb(Fl_Widget *, void *);
void newgame_cb(Fl_Widget *, void *);
void predict_cb(Fl_Widget *, void *);
void switch_cb(Fl_Widget *, void *);
void undo_cb(Fl_Widget *, void *);
void forced_cb(Fl_Widget *, void *);
void debug_cb(Fl_Widget *, void *);
void intel_cb(Fl_Widget *, void *);
void copyright_cb(Fl_Widget *, void *);
void quit_cb(Fl_Widget *, void *);
void stop_cb(Fl_Widget *, void *);
void continue_cb(Fl_Widget *, void *);
void menu_cb(Fl_Widget *, void *);
void cb_P(Fl_Widget *, void *);
void interpretLine(char *s);
void interpretLine_gnuChess(char *s);

void (*cbPtr) (Fl_Widget *, void *);

// -----------------------------------------------------------------
// class

class Board:public Fl_Double_Window {
    void draw();
    int handle(int);
  public:
    void drag_piece(int, int, int);
    void drop_piece(int);
    void animate(char *move, int backwards);
    void computer_move(int);
     Board(int x, int y, int w, int h):Fl_Double_Window(x, y, w, h) {
	color(15);
}};

// --------------------------------------------------------
// predefined globals

int cBoard[8][8] = {

    {CB_WT, CB_WH, CB_WR, CB_WD, CB_WK, CB_WR, CB_WH, CB_WT},
    {CB_WB, CB_WB, CB_WB, CB_WB, CB_WB, CB_WB, CB_WB, CB_WB},
    {CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO},
    {CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO},
    {CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO},
    {CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO, CB_NO},
    {CB_BB, CB_BB, CB_BB, CB_BB, CB_BB, CB_BB, CB_BB, CB_BB},
    {CB_BT, CB_BH, CB_BR, CB_BD, CB_BK, CB_BR, CB_BH, CB_BT}

};


Fl_Menu_Item menu[] = {
//  {"Autoplay", 'a', autoplay_cb,0,0,0,0,11},
//  {"Legal moves", 'l', legal_cb,0,0,0,0,11},
    {"Change P to", 0, 0, 0, FL_SUBMENU, 0, 0, 11},
    {"Q", 0, cb_P, (void *) 'q', FL_MENU_RADIO | FL_MENU_VALUE, 0, 0, 11},
    {"R", 0, cb_P, (void *) 'r', FL_MENU_RADIO, 0, 0, 11},
    {"N", 0, cb_P, (void *) 'n', FL_MENU_RADIO, 0, 0, 11},
    {"B", 0, cb_P, (void *) 'b', FL_MENU_RADIO, 0, 0, 11},
    {NULL},
    {"Move for me", 'm', move_cb, 0, 0, 0, 0, 11},
    {"New game", 'n', newgame_cb, 0, 0, 0, 0, 11},
//  {"Predict", 'p', predict_cb,0,0,0,0,11},
    {"Switch sides", 's', switch_cb, 0, 0, 0, 0, 11},
    {"Undo", 'u', undo_cb, 0, 0, 0, 0, 11},
//  {"Forced jumps rule", 'f', forced_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE,0,0,0,11},
//  {"Debug", 'd', debug_cb, (void *)"d", FL_MENU_TOGGLE,0,0,0,11},
    {"Level...", 'i', intel_cb, 0, 0, 0, 0, 11},
    {"Copyright", 'c', copyright_cb, 0, 0, 0, 0, 11},
    {"Quit", 'q', quit_cb, 0, 0, 0, 0, 11},
    {0}
};

// --------------------------------------------------------
// globals

//Fl_Pixmap* bm[6][2][2];
Fl_Bitmap *bm[6][2][2];

void addToLine(char *s);
char faileL[1024];

static long wT = 0;
static long bT = 0;

int playing;

int blackWhite = CB_WHITE;

int busy;			// causes pop-up abort menu

Board *bP;

int gnuB = 0;

int fdTo[2], fdFrom[2];

char rS[80];
int first = 0;
int cbTm = 0;

Fl_Output *o1P, *o2P, *o3P;
Fl_Input *i1P;

Fl_Window *intel_window;
Fl_Value_Output *intel_output;
Fl_Window *copyright_window;


int terminal;

int autoplay = 0;
int debug = 0;

int forcejumps = 0;

int sel_1x = -1, sel_1y = -1;
char nextMove[10] = "\0";
char storeMove[10] = "\0";

char changeP = 'q';


int pidChild = -1;

// --------------------------------------------------------
// implementation 

/*
void make_pixmaps() {
    
  
  bm[0][0][0] = new Fl_Pixmap(bdd21);
  bm[0][0][1] = new Fl_Pixmap(bdl21);
  bm[0][1][0] = new Fl_Pixmap(bld21);
  bm[0][1][1] = new Fl_Pixmap(bll21);
  bm[1][0][0] = new Fl_Pixmap(qdd21);
  bm[1][0][1] = new Fl_Pixmap(qdl21);
  bm[1][1][0] = new Fl_Pixmap(qld21);
  bm[1][1][1] = new Fl_Pixmap(qll21);
  bm[2][0][0] = new Fl_Pixmap(ndd21);
  bm[2][0][1] = new Fl_Pixmap(ndl21);
  bm[2][1][0] = new Fl_Pixmap(nld21);
  bm[2][1][1] = new Fl_Pixmap(nll21);
  bm[3][0][0] = new Fl_Pixmap(pdd21);
  bm[3][0][1] = new Fl_Pixmap(pdl21);
  bm[3][1][0] = new Fl_Pixmap(pld21);
  bm[3][1][1] = new Fl_Pixmap(pll21);
  bm[4][0][0] = new Fl_Pixmap(kdd21);
  bm[4][0][1] = new Fl_Pixmap(kdl21);
  bm[4][1][0] = new Fl_Pixmap(kld21);
  bm[4][1][1] = new Fl_Pixmap(kll21);
  bm[5][0][0] = new Fl_Pixmap(rdd21);
  bm[5][0][1] = new Fl_Pixmap(rdl21);
  bm[5][1][0] = new Fl_Pixmap(rld21);
  bm[5][1][1] = new Fl_Pixmap(rll21);      
            
}*/

void make_bitmaps()
{


    bm[0][0][0] = new Fl_Bitmap(b21s_bits, 21, 21);
    bm[0][0][1] = bm[0][0][0];

    bm[0][1][0] = new Fl_Bitmap(b21o_bits, 21, 21);
    bm[0][1][1] = bm[0][1][0];

    bm[1][0][0] = new Fl_Bitmap(q21s_bits, 21, 21);
    bm[1][0][1] = bm[1][0][0];

    bm[1][1][0] = new Fl_Bitmap(q21o_bits, 21, 21);
    bm[1][1][1] = bm[1][1][0];

    bm[2][0][0] = new Fl_Bitmap(n21s_bits, 21, 21);
    bm[2][0][1] = bm[2][0][0];

    bm[2][1][0] = new Fl_Bitmap(n21o_bits, 21, 21);
    bm[2][1][1] = bm[2][1][0];

    bm[3][0][0] = new Fl_Bitmap(p21s_bits, 21, 21);
    bm[3][0][1] = bm[3][0][0];

    bm[3][1][0] = new Fl_Bitmap(p21o_bits, 21, 21);
    bm[3][1][1] = bm[3][1][0];

    bm[4][0][0] = new Fl_Bitmap(k21s_bits, 21, 21);
    bm[4][0][1] = bm[4][0][0];

    bm[4][1][0] = new Fl_Bitmap(k21o_bits, 21, 21);
    bm[4][1][1] = bm[4][1][0];

    bm[5][0][0] = new Fl_Bitmap(r21s_bits, 21, 21);
    bm[5][0][1] = bm[5][0][0];

    bm[5][1][0] = new Fl_Bitmap(r21o_bits, 21, 21);
    bm[5][1][1] = bm[5][1][0];
}

// --------------------------------------------------------------

void draw_piece(int piece, int x, int y)
{

    if ((piece != CB_NO) && (piece < 20))

	bm[(piece - 1) % 10]
	    [piece / 10]
	    [1 - ((x + y) % 2)]->draw((x) * BOXSIZE_X + BORDER / 2,
				      (7 - y) * BOXSIZE_Y + BORDER);
}


// ----------------------------------------------------------------

void Board::draw()
{

    int x, y;

    //fl_color((Fl_Color) FL_BLACK); 

    //fl_draw_box(box(),0,0,w(),h(),color());
    fl_draw_box(box(), 0, 0, w(), h(), FL_DARK2);	//FL_DARK3);

    fl_color((Fl_Color) FL_WHITE);

// BOXES
    for (x = 0; x < 8; x++)
	for (y = 0; y < 8; y++) {
	    if (!((x ^ y) & 1))
		fl_rectf(BORDER + x * BOXSIZE_X, BORDER + y * BOXSIZE_Y,
			 BOXSIZE_X - BORDER, BOXSIZE_Y - BORDER);
	}

// BORDER
    fl_color(FL_DARK1 /*FL_GRAY_RAMP+4 */ );

    for (x = 0; x < 9; x++) {
	fl_rectf(x * BOXSIZE_X, 0, BORDER, h());
	fl_rectf(0, x * BOXSIZE_Y, w(), BORDER);
    }

    fl_color(FL_BLACK);

    for (y = 0; y < 8; y++) {
	for (x = 0; x < 8; x++) {
	    draw_piece(cBoard[y][x], x, y);
	}
    }

    if (sel_1x != -1) {
	fl_color(FL_BLACK);
	for (x = 0; x < BORDER; x++) {

	    fl_rect(sel_1x * BOXSIZE_X + x, (7 - sel_1y) * BOXSIZE_Y + x,
		    BOXSIZE_X + BORDER - 2 * x,
		    BOXSIZE_Y + BORDER - 2 * x);
	}
    }


}


void doMove(char *s);

// ------------------------------------------------------------------------

void message(const char *m, ...)
{
    char buffer[2048];
    va_list a;
    va_start(a, m);
    vsprintf(buffer, m, a);
    va_end(a);
    fl_message(buffer);
}

// -------------------------------------------------------------------------

void writeToEngine(int c, char *s)
{

    switch (c) {
    case ENG_MOVE:
	write(fdTo[1], s, strlen(s));
	break;
    case ENG_STR:
	write(fdTo[1], s, strlen(s));
	break;
    case ENG_NEW:
	writeToEngine(ENG_STR, "new\n");

	break;
    case ENG_UNDO:
	writeToEngine(ENG_STR, "undo\n");
	break;
    case ENG_SWITCH:
	writeToEngine(ENG_STR, "go\n");
	break;
    case ENG_SHOWBOARD:
	writeToEngine(ENG_STR, "show board\n");
	break;
    case ENG_LEVEL:
	writeToEngine(ENG_STR, "level ");
	writeToEngine(ENG_STR, s);
	break;
    case ENG_CLOCK:
	writeToEngine(ENG_STR, "clock\n");
	writeToEngine(ENG_STR, s);
	break;
	//case ENG_SWITCH : writeToEngine(ENG_STR,"switch\n"); break; 
    case ENG_EVAL:
	writeToEngine(ENG_STR, "show eval\n");
	break;
    default:
	break;
    }
}

// -------------------------------------------------------------------------

void Board::computer_move(int help)
{
}

void genMove(int x, int y)
{

    int p;

    if ((x == sel_1x) && (y == sel_1y)) {
	strcpy(nextMove, "");
	sel_1x = sel_1y = -1;
	bP->redraw();
    } else {
	if (strlen(nextMove) > 0) {

	    nextMove[2] = 'a' + x;
	    nextMove[3] = '1' + y;
	    nextMove[4] = '\n';
	    nextMove[5] = '\0';

	    p = cBoard[sel_1y][sel_1x];

	    // printf("%d %d %p\n",sel_1y,y,p);

	    if (((p % 10) == CB_BB) &&
		(((sel_1y == 6) && (y == 7))
		 || ((sel_1y == 1) && (y == 0)))) {
		nextMove[4] = changeP;
		nextMove[5] = '\n';
		nextMove[6] = '\0';
	    }

	    printf("%s\n", nextMove);
	    writeToEngine(ENG_MOVE, nextMove);

	    strcpy(storeMove, nextMove);

	    strcpy(nextMove, "");
	    sel_1x = sel_1y = -1;
	} else {
	    sel_1x = x;
	    sel_1y = y;
	    nextMove[0] = 'a' + x;
	    nextMove[1] = '1' + y;
	    nextMove[2] = '\0';
	    bP->redraw();
	}
    }

    i1P->cut(0, 50);
    i1P->insert(nextMove);
    i1P->position(0, 0);
    i1P->redraw();

    printf("%s\n", nextMove);
}

// ------------------------------------------------------------------

int Board::handle(int e)
{

    const Fl_Menu_Item *m;

    switch (e) {

    case FL_PUSH:
	//  if (Fl::event_button() > 1) {
	//    if(cbTm <= 1) {
	//    m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
	//    if (m) m->do_callback(this, (void*)m);
	//    return 1;
	//    }
	//  }
	if (cbTm > 0) {
	    int x, y;

	    x = Fl::event_x() / BOXSIZE_X;
	    y = (7 - Fl::event_y() / BOXSIZE_Y);

	    printf("%02d %02d %02d %02d\n", x, y, cBoard[y][x],
		   blackWhite);

	    if ((sel_1x == -1) && ((cBoard[y][x] == CB_NO) ||
				   ((cBoard[y][x] / 10 - blackWhite) !=
				    0)))
		return 0;

	    genMove(x, y);

	    return 1;

	}
	return 0;
    case FL_SHORTCUT:
	m = menu->test_shortcut();
	if (m) {
	    m->do_callback(this, (void *) m);
	    return 1;
	}
	return 0;
    case FL_DRAG:
	// drag_piece(erase_this, Fl::event_x()-deltax, Fl::event_y()-deltay);
	return 1;
    case FL_RELEASE:
	// find the closest legal move he dropped it on:   
	return 1;
    default:
	return 0;
    }

}

// -----------------------------------------------------------------------------

void quit_cb(Fl_Widget *, void *)
{

    int sigR;

    if (pidChild > 0) {
	kill(pidChild, SIGTERM);
	wait(&sigR);
    }
    exit(0);
}

// -----------------------------------------------------------------------------

void cb(Fl_Widget * ob)
{

    char cmdstring[100];

    printf("Callback for %s '%s'\n", ob->label(),
	   ((Fl_Input *) ob)->value());
    strcpy(cmdstring, ((Fl_Input *) ob)->value());
    ((Fl_Input *) ob)->replace(0, strlen(cmdstring), NULL, 0);

    printf("%s %d\n", cmdstring,
	   write(fdTo[1], cmdstring, strlen(cmdstring)));
    writeToEngine(ENG_STR, "\n");
}

// -----------------------------------------------------------------------------

void cb_P(Fl_Widget * ob, void *p)
{

    changeP = (char) p;
}



// -----------------------------------------------------------------------------

void cbT(void *p)
{

    char wTs[10], bTs[10];
    char m1, m2;

    Fl::add_timeout(1.0, cbT);

    switch (cbTm) {
    case 0:
	return;
    case 1:
	if (blackWhite == CB_WHITE) {
	    wT++;
	    m1 = 'U';
	    m2 = 'C';
	} else {
	    bT++;
	    m1 = 'C';
	    m2 = 'U';
	}
	break;
    case 2:
	if (blackWhite == CB_WHITE) {
	    bT++;
	    m1 = 'U';
	    m2 = 'C';
	} else {
	    wT++;
	    m1 = 'C';
	    m2 = 'U';
	}
	break;
    }

    sprintf(wTs, "%c %02d:%02d", m1, (int) (wT / 60), (int) (wT % 60));
    sprintf(bTs, "%c %02d:%02d", m2, (int) (bT / 60), (int) (bT % 60));

    o1P->value(wTs);
    o3P->value(bTs);
}

// --------------------------------------------------------------------------

void cbPipe(int fd, void *rS)
{

    int rN;

    rN = read(fd, (char *) rS, 79);
    ((char *) rS)[rN] = '\0';
    // printf("%s",rS);       
    addToLine((char *) rS);
}

// -----------------------------------------------------------------------------

int FLTKmain(int argc, char **argv)
{

#define BSIZE 18

    int sigR;

    Fl_Window w(160, 240, "Fltk Chess");

    Fl_Output b1(0, 0, WINSIZE_X / 3, BSIZE, "");
    Fl_Output b2(WINSIZE_X / 3, 0, WINSIZE_X / 3, BSIZE, "");
    Fl_Output b3(2 * WINSIZE_X / 3, 0, WINSIZE_X / 3, BSIZE, "");
    Fl_Input bi(0, BSIZE, WINSIZE_X, BSIZE, "");

    Fl_Button bd(0, BOARDSIZE + BSIZE * 2, 40, BSIZE, "Done");

    Fl_Menu_Button bm(40, BOARDSIZE + BSIZE * 2, 55, BSIZE, "Menu");

    bd.labelsize(11);

    bm.labelsize(11);
    bm.textsize(11);
    bm.menu(menu);

    b1.textsize(11);
    b2.textsize(11);
    b3.textsize(11);
    bi.textsize(11);

    b3.color(FL_BLACK);
    b3.textcolor(FL_WHITE);

    Board b(0, BSIZE * 2, BOARDSIZE, BOARDSIZE);

    Fl::add_timeout(1.0, cbT);

    make_bitmaps();

    o1P = &b1;
    o2P = &b2;
    o3P = &b3;
    i1P = &bi;

    w.box(FL_FLAT_BOX);
    Fl::visual(FL_DOUBLE | FL_INDEX);
    bP = &b;
    b.callback(quit_cb);


    bi.when(FL_WHEN_ENTER_KEY | FL_WHEN_NOT_CHANGED);
    bi.callback(cb);

    bd.callback(quit_cb, 0);

//  bm.callback(menu_cb,0);

    b.end();
    w.end();
    w.show();
    b.show();
    bi.show();
    b1.show();
    b2.show();

    bP->redraw();
    Fl::wait(100U);

    pipe(fdTo);
    pipe(fdFrom);

    if ((pidChild = fork()) == 0) {

	dup2(fdTo[0], 0);
	dup2(fdFrom[1], 1);

	// close(fdTo[0]); 
	// close(fdTo[1]);
	// close(fdFrom[0]); 
	// close(fdFrom[1]);

	execl("./gnuchess", NULL);
	execl("/usr/bin/gnuchess", NULL);

    } else {

	// close(fdTo[0]);
	// close(fdFrom[1]);


	writeToEngine(ENG_LEVEL, "30 1 0\n");
	cbTm = 1;

	Fl::add_fd(fdFrom[0], cbPipe, rS);

	Fl::run();
    }

    if (pidChild > 0) {
	kill(pidChild, SIGTERM);
	wait(&sigR);
    }
    return 0;
}


// ------------------------------------------------------------------------

void autoplay_cb(Fl_Widget * bp, void *)
{
    if (autoplay) {
	autoplay = 0;
	return;
    }
    if (!playing)
	return;
    Board *b = (Board *) bp;
    autoplay = 1;
    while (autoplay) {
	b->computer_move(0);
	b->computer_move(0);
    }
}


// -------------------------------------------------------------------------
void cb_copyright(Fl_Widget *, void *)
{
    copyright_window->hide();
}

// -----------------------------------------------------------------------------
void copyright_cb(Fl_Widget *, void *)
{
    if (!copyright_window) {
	copyright_window = new Fl_Window(160, 240, "Copyright");
	copyright_window->color(FL_WHITE);
	Fl_Box *b = new Fl_Box(0, 0, 160, 220, copyright);
	Fl_Button *b1 = new Fl_Button(0, 220, 30, 20, "Done");
	b->labelsize(11);
	b1->labelsize(11);
	b1->callback(cb_copyright);
	b->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP);
	copyright_window->end();
    }
    copyright_window->hotspot(copyright_window);
    copyright_window->set_non_modal();
    copyright_window->show();
}

// -----------------------------------------------------------------------------
void debug_cb(Fl_Widget *, void *v)
{
    debug = !debug;
    ((Fl_Menu_Item *) v)->flags =
	debug ? FL_MENU_TOGGLE | FL_MENU_VALUE : FL_MENU_TOGGLE;
}

// -----------------------------------------------------------------------------
void forced_cb(Fl_Widget * b, void *v)
{
    forcejumps = !forcejumps;
    ((Fl_Menu_Item *) v)->flags =
	forcejumps ? FL_MENU_TOGGLE | FL_MENU_VALUE : FL_MENU_TOGGLE;
}


// -----------------------------------------------------------------------------
void move_cb(Fl_Widget * pb, void *uD)
{

    if ((((int) uD) == 0) && (cbTm == 2)) {
	printf("Discarded \n");
	return;
    }

    writeToEngine(ENG_SWITCH, "");
    blackWhite = 1 - blackWhite;
    if (cbPtr == 0) {
	cbTm = 2;
	cbPtr = move_cb;
    } else {
	cbTm = 1;
	cbPtr = 0;
    }
}

// -----------------------------------------------------------------------------
void newgame_cb(Fl_Widget * b, void *)
{
    writeToEngine(ENG_NEW, "");
    cbTm = 0;
    bT = wT = 0;
    blackWhite = CB_WHITE;
    o1P->value("00:00");
    o2P->value("0.0");
    o3P->value("00:00");
    writeToEngine(ENG_CLOCK, "1\n");
    writeToEngine(ENG_SHOWBOARD, "");
}

// -----------------------------------------------------------------------------
void legal_cb(Fl_Widget * pb, void *)
{
}

// -----------------------------------------------------------------------------
void predict_cb(Fl_Widget * pb, void *)
{
}

// -----------------------------------------------------------------------------
void switch_cb(Fl_Widget * pb, void *uD)
{

    if ((((int) uD) == 0) && (cbTm == 2)) {
	printf("Discarded \n");
	return;
    }

    writeToEngine(ENG_SWITCH, "");
    blackWhite = 1 - blackWhite;
}

void undo_cb(Fl_Widget * pb, void *uD)
{

    if ((((int) uD) == 0) && (cbTm == 2)) {
	printf("Discarded \n");
	return;
    }
    o2P->value ("");

    writeToEngine(ENG_UNDO, "");
    blackWhite = 1 - blackWhite;
    if (cbPtr == 0) {
	cbTm = 2;
	cbPtr = undo_cb;
    } else {
	cbTm = 1;
	cbPtr = 0;
    }
}


void menu_cb(Fl_Widget * pb, void *)
{
    const Fl_Menu_Item *m;

    if (cbTm < 2) {
	m = menu->popup(-40, -50, 0, 0, 0);
	if (m)
	    m->do_callback(pb, (void *) m);
    }
}

// ---------------------------------------------------

void cb_intelDone(Fl_Widget * pb, void *w)
{

    char s[20];
    int n = (int)((Fl_Slider *) w)->value();
    int m;
    switch (n) {
    case 0:
	    m = 60;
	    break;
    case 1:
	    m = 30;
	    break;
    case 2:
	    m = 15;
	    break;
    case 3:
	    m = 10;
	    break;
    case 4:
	    m = 6;
	    break;
    case 5:
	    m = 3;
	    break;
    default:
	    m = 60;
	    break;
    }

    sprintf (s, "%d 1 0\n", m);

    writeToEngine(ENG_LEVEL, s);
    printf(s);

    intel_window->hide();
}

void intel_slider_cb(Fl_Widget * w, void *)
{

    double v = ((Fl_Slider *) w)->value();
    intel_output->value((int)v);
}



// -------------------------------------------------------------------

void intel_cb(Fl_Widget *, void *)
{

    if (!intel_window) {
	intel_window = new Fl_Window(150, 50, "Chess Level");
	Fl_Slider *s = new Fl_Slider(30, 0, 120, 25);
	Fl_Button *b = new Fl_Button(0, 25, 40, 25, "Done");
	b->labelsize(11);
	s->type(FL_HOR_NICE_SLIDER);
	s->minimum(0);
	s->maximum(5);
	s->value(1);
	s->callback(intel_slider_cb);
	intel_output = new Fl_Value_Output(0, 0, 30, 25);
	intel_output->value(1);
	intel_output->textsize(11);
	//intel_window->resizable(s);
	b->callback(cb_intelDone, s);
    }
    //intel_window->hotspot(intel_window);
    //intel_window->set_non_modal();
    intel_window->show();
}

// ---------------------------------------------------------------

int abortflag = 1;
void stop_cb(Fl_Widget *, void *)
{
    abortflag = 1;
}

void continue_cb(Fl_Widget *, void *)
{
}


// ----------------------------------------------------------------

int arg(int, char **argv, int &i)
{
    return 0;
}

// ----------------------------------------------------------------

int didabort(void)
{
    Fl::check();
    if (abortflag) {
	autoplay = 0;
	abortflag = 0;
	return 1;
    }
    return (0);
}

// ---------------------------------------------------------------

int main(int argc, char **argv)
{
    int i = 1;
    if (Fl::args(argc, argv, i, arg) < argc) {
	fprintf(stderr, "... %s \n", Fl::help);
	exit(1);
    }

    if (!getenv("DISPLAY")) {
	exit(1);
    }

    return FLTKmain(argc, argv);
}

// ---------------------------------------------------------------

void addToLine(char *s)
{

    char *newL;

    strcat(faileL, s);

    while ((newL = strchr(faileL, '\n')) != NULL) {

	*newL = '\0';
	printf("%s\n", faileL);

	// interpretLine(faileL);

	interpretLine_gnuChess(faileL);

	strcpy(faileL, newL + 1);
    }
}

// ---------------------------------------------------------------

void doMove(char *s)
{

    int L1, R1, L2, R2;

    L1 = s[0] - 'a';
    R1 = s[1] - '1';
    L2 = s[2] - 'a';
    R2 = s[3] - '1';


    printf("%d %d %d %d\n", L1, R1, L2, R2);

    cBoard[R2][L2] = cBoard[R1][L1];
    cBoard[R1][L1] = CB_NO;

}

// -----------------------------------------------------------------------------

void printX(char *s)
{

    i1P->cut(0, 50);
    i1P->insert(s);
    i1P->position(0, 0);
}

// -----------------------------------------------------------------------------

char *strnchr(char *s, char c)
{

    while (*s == c) {
	s++;
    }

    return s;
}

// -----------------------------------------------------------------------------
void interpretLine_gnuChess(char *s)
{

    int i, L, R1;
    char *tP;

    if (strstr(s, "GNU Chess v5") != NULL) {
	cbTm = 1;
    }

    if ((gnuB > 0) && (strchr("RNBQKPrnbqkp.", s[0]) != NULL)
	&& (strlen(s) > 8) && (s[1] == ' ')) {

	for (i = 0; i < 0 + 2 * 8; i += 2) {
	    L = gnuB - 1;
	    R1 = i / 2;

	    switch (s[i]) {

	    case 'R':
		cBoard[L][R1] = CB_WT;
		break;
	    case 'r':
		cBoard[L][R1] = CB_BT;
		break;
	    case 'N':
		cBoard[L][R1] = CB_WH;
		break;
	    case 'n':
		cBoard[L][R1] = CB_BH;
		break;
	    case 'B':
		cBoard[L][R1] = CB_WR;
		break;
	    case 'b':
		cBoard[L][R1] = CB_BR;
		break;
	    case 'Q':
		cBoard[L][R1] = CB_WD;
		break;
	    case 'q':
		cBoard[L][R1] = CB_BD;
		break;
	    case 'K':
		cBoard[L][R1] = CB_WK;
		break;
	    case 'k':
		cBoard[L][R1] = CB_BK;
		break;
	    case 'P':
		cBoard[L][R1] = CB_WB;
		break;
	    case 'p':
		cBoard[L][R1] = CB_BB;
		break;
	    case '.':
		cBoard[L][R1] = CB_NO;
		break;
	    default:
		break;
	    }
	}

	gnuB--;

	if (gnuB == 0) {
	    bP->redraw();
	    if (cbPtr != 0)
		(*cbPtr) (0, (void *) 1);
	}
    }

    if (strstr(s, "My move is : ") != NULL) {
	//doMove(s+12);
	bP->redraw();
	printX(s);
	// writeToEngine(ENG_SHOWBOARD,"");    
	// gnuB=8;    
	cbTm = 1;

	if (cbPtr != 0)
	    (*cbPtr) (0, (void *) 1);

	writeToEngine(ENG_EVAL, "");
    }

    if ((storeMove[0] != '\0') && (strstr(s, "Illegal move") == NULL)) {
	doMove(storeMove);
	strcpy(storeMove, "");
	bP->redraw();
	// writeToEngine(ENG_SHOWBOARD,"");
	// gnuB=8;    
	cbTm = 2;
    }


    if ((strstr(s, "white ") == s) || (strstr(s, "black ") == s)) {
	if (cbTm == 0)
	    cbTm = 1;
	gnuB = 8;
    }

    if (strstr(s, "wins") != NULL || strstr(s, "loses") != NULL) {
	printX(s);
	o2P->value("Mates");
	cbTm = 0;
    } else if (strstr(s, "{stalemate}") != NULL) {
	printX(s);
	o2P->value("Stalemate");
	cbTm = 0;
    } else if (strstr(s, "{draw}") != NULL) {
	printX(s);
	o2P->value("Draw");
	cbTm = 0;
    }

    if ((tP = strstr(s, "score = ")) != NULL) {

	char tmp[20];
	int ev;

	ev = atoi(tP + 8);

	tmp[0] = ' ';
	if (ev < 0) {
	    ev = -ev;
	    tmp[0] = '-';
	}

	sprintf(tmp + 1, "%d.%02d", ev / 100, ev % 100);
	if (cbTm > 0)
	    o2P->value(tmp);
    }
}

// -------------------------------------------------------------

void printcBoard()
{
    int x, y;
    for (x = 0; x < 8; x++) {
	for (y = 0; y < 8; y++) {
	    printf("%2d ", cBoard[x][y]);
	}
	printf("\n");
    }
}
