#include "xbugchess.h"

#include "bitmaps/knight_out"
#include "bitmaps/knight_piece"

#include "digits/one"
#include "digits/two"
#include "digits/three"
#include "digits/four"
#include "digits/five"
#include "digits/six"
#include "digits/seven"
#include "digits/eight"
#include "digits/nine"
#include "digits/zero"
#include "bitmaps/board"

#define WIDTH 400 
#define HEIGHT 150
#define CURPLAYER clk->clock[clk->whoseturn]

static char messages[][50] = {"", "", "Just Kidding", "Ken's a Schmuck",
			   "YOU WEENIE!!!",
			   "Right button",
			   "gimme a PAWN", 
			   "gimme a KNIGHT",
			   "gimme a KNIGHT",
			   "gimme a BISHOP",
			   "gimme a ROOK", 
			   "gimme a QUEEN",
			   "In MATE, TAKE KING", 
			   "PAWN coming",
			   "KNIGHT coming",
			   "KNIGHT coming",
			   "BISHOP coming",
			   "ROOK coming", 
			   "QUEEN coming", 
			   "GOT HIM in MATE!!!",
			   "SHUT UP",
			   "I need PIECES!",
			   "I need PIECES!",
			   "I NEED ^%(*% PIECES",
			   "Mate for a PAWN",
			   "Mate for a KNIGHT",
			   "Mate for a KNIGHT",
			   "Mate for a BISHOP",
			   "Mate for a QUEEN",
			   "Oh SHIT!",
			   "Your Move", 
			   "NO!",
			   "Yes",
			   "Yes",
			   "OK",
			   "STOP THINKING",
			   "GO!!!!",
			   "Oops!",
			   "WHAT???",
			   "WHAT???",
			   "Queen Trade?",
			   "Opus is a SQUID",
			   "Thanks!",
			   "Erg!",
			   "argh",
			   "ARGH!",
			   "AAAAARRRRRGGGGHH!",
			   "@#$%^&*()+"
			   };

Pixmap digit[10], kpix, koutpix, brd;

Window Cwindow,Crootwindow;;
Display *Cdisplay;
GC Cgc, gcpiece[2], gcoutline,gcdigit;
XGCValues Cgcvalues;
XEvent Cxevent;
XButtonPressedEvent *Cbuttonpressed;
int Cscreen;
XSizeHints Csize_hints;
XPoint points[4], points2[3];
XFontStruct *Cfont;
XClassHint classhint;

struct clock_data *make_clock(d,mycolor,stupid_quirk_in_the_compiler)
Display *d;
char mycolor;
int  stupid_quirk_in_the_compiler;
{
  static struct clock_data cclock;
  static char name[] = "xchessclock", class[] = "XChessclock";
  int timelim; 
  XrmValue v;
  int retval=0;
  Bool resret;
  char *strtype[20];
  char strname[80];

  timelim = stupid_quirk_in_the_compiler;
  Cdisplay = d;
  Cscreen=DefaultScreen(Cdisplay);
  Crootwindow = RootWindow(Cdisplay,Cscreen); /*get parent window id */

  Csize_hints.x = Csize_hints.y = 0;
  if(resret = XrmGetResource(XrmGetStringDatabase(XResourceManagerString(Cdisplay)), 
			     "xbugchess.clock.geometry", "XBugchess.Window.Geometry", strtype, &v)) {
    retval = XParseGeometry(v.addr, &Csize_hints.x, &Csize_hints.y, NULL, NULL);
    if (retval & XNegative) {
      Csize_hints.x = DisplayWidth(Cdisplay, 0) - Csize_hints.x - WIDTH+20;
      Csize_hints.x -= 10; /*for border */
      Csize_hints.x -= 40; 
    }
    if (retval & YNegative) {
      Csize_hints.y = DisplayHeight(Cdisplay, 0) - Csize_hints.y - HEIGHT;
      Csize_hints.y -= 10 ; /* for border */ 
      Csize_hints.y -= 25 ;
      if (getgametype() == BUGCHESS) Csize_hints.y -= 180;
    }
	
    if ((retval & XValue ) || (retval & YValue)) {
      Csize_hints.flags = USPosition;
    }

  }

  Cwindow=XCreateSimpleWindow(Cdisplay,Crootwindow,Csize_hints.x,Csize_hints.y,
			      WIDTH + 20 ,HEIGHT,5,
			      BlackPixel(Cdisplay,Cscreen), 
			      WhitePixel(Cdisplay,Cscreen));

  if ((Cfont = XLoadQueryFont(Cdisplay, "8x13bold")) == NULL) {
    fprintf(stderr,"can't load font\n");
  }                                                                     
  Cgcvalues.font = Cfont->fid;
  Cgc = XCreateGC(Cdisplay, Cwindow, GCFont, &Cgcvalues);
  Cgcvalues.function = GXcopyInverted; 
  gcdigit = XCreateGC(Cdisplay, Cwindow, (GCFunction), &Cgcvalues);
  Cgcvalues.function = GXandInverted;
  gcpiece[BLACK] = XCreateGC(Cdisplay, Cwindow, (GCFunction), &Cgcvalues);

  Cgcvalues.function = GXor;
  gcpiece[WHITE] = XCreateGC(Cdisplay, Cwindow, (GCFunction), &Cgcvalues); 

  Cgcvalues.function = GXxor;
  gcoutline = XCreateGC(Cdisplay, Cwindow, (GCFunction), &Cgcvalues);

  classhint.res_name = name;
  classhint.res_class = class;

  XSetClassHint(Cdisplay, Cwindow, &classhint);
  XStoreName(Cdisplay, Cwindow, "XChessClock");
  XSetIconName(Cdisplay, Cwindow, "XC-Clock");
  if (getgametype() == BUGCHESS) {
    strcpy(strname, "xbugchess.clock.geometry");
  } else {
    strcpy(strname, "xspeedchess.clock.geometry");
  }

  if(resret)
    XSetStandardProperties(Cdisplay, Cwindow, "XClock", "XClock", None, strtype,0, &Csize_hints);


  XSelectInput(Cdisplay, Cwindow, ExposureMask | KeyPressMask);
  XMapWindow(Cdisplay,Cwindow);

  timelim = 60 * timelim;

  cclock.board.used=0;
  cclock.mycolor = mycolor;
  cclock.opcolor = (mycolor == WHITE) ? BLACK : WHITE;
  cclock.totaltime = timelim;
  cclock.clock[mycolor]=&cclock.myclock;
  cclock.clock[cclock.opcolor]=&cclock.opclock;

  cclock.myclock.time_left.time = timelim;
  cclock.opclock.time_left.time = timelim;

  cclock.myclock.time_left.millitm = 0;
  cclock.opclock.time_left.millitm = 0;

  inits();

  cclock.whoseturn=WHITE;
  cclock.pause=1;
  return(&cclock);
  
}


Window ClockWindow()
{
  return Cwindow;
}

update_clock(clk)
struct clock_data *clk;
{
  struct timeb tp;
  time_t dif;
  unsigned short mdif;
  static int rang = 0;

  if ( clk->pause || rang ) return 0;
  ftime(&tp);

  
  if (( (dif  = (tp.time - (CURPLAYER->marker.time))) > 0.0) &&
      ( (mdif = (tp.millitm - (CURPLAYER->marker.millitm))) > 0.0)) {
    if ( CURPLAYER->time_left.time == 0) { 
      XBell(Cdisplay, 100); 
      XBell(Cdisplay, 50); 
      XBell(Cdisplay, 100); 
      XBell(Cdisplay, 50); 
      rang = 1;
      XBell(Cdisplay, 100); 
      XBell(Cdisplay, 50); 
      XBell(Cdisplay, 100); 
      XBell(Cdisplay, 50); 
      return -1 ; 
    }

    CURPLAYER->time_left.time -= dif;
    CURPLAYER->time_left.millitm -= mdif;
    Credraw_clk(clk);
    CURPLAYER->marker = tp;
  }
  return 0;
}

Credraw_clk(clk)
struct clock_data *clk;
{
  char buf[20];
  int counter,x;
  long temp;

  temp =( clk->clock[clk->mycolor]->time_left.time / 60 ) * 100 + 
    (clk->clock[clk->mycolor]->time_left.time % 60);
  
  sprintf(buf, "%03.0ld", temp);

  for(counter = 0,x = WIDTH/10 + 40; counter < 3; counter++, x += 40)  {
    put_num(buf[counter],x);
  }

  temp =( clk->clock[clk->opcolor]->time_left.time / 60 ) * 100 + 
    (clk->clock[clk->opcolor]->time_left.time % 60);

  sprintf(buf, "%03.0ld", temp);

  for(counter = 0,x = WIDTH/10 + 175; counter < 3; counter++, x += 40)  {
    put_num(buf[counter],x);
  }
}

put_num(c,x)
char c;
int x;
{
  int which;
  which = c - '0' ;
  
  if ( which > 9 || which < 0 )  {
    return;
  }
  if(getplanes() == 1) 
  XCopyArea(Cdisplay, digit[which], Cwindow, gcdigit, 0, 0, 32, 64, x, 50);
  else 
  XCopyPlane(Cdisplay, digit[which], Cwindow, gcdigit, 0, 0, 32, 64, x, 50,1);
}


Credraw(clk)
struct clock_data *clk;
{
  int offx;
  XDrawRectangle(Cdisplay, Cwindow, Cgc, 25 + WIDTH/10, 25, WIDTH * 8/10 - 30, 120);

  XDrawRectangle(Cdisplay, Cwindow, Cgc, 25 + WIDTH/10 + 10 , 35, WIDTH /3 , 100);
  XDrawRectangle(Cdisplay, Cwindow, Cgc,  WIDTH/2 , 35, WIDTH /3 , 100);

  XDrawLines(Cdisplay, Cwindow, Cgc,  points,4,CoordModePrevious);
  XDrawLines(Cdisplay, Cwindow, Cgc, points2, 3, CoordModePrevious);

  offx = (clk->mycolor == clk->whoseturn) ? WIDTH/10 + 95 :WIDTH* 8/10 - 45;
  XFillRectangle(Cdisplay, Cwindow, Cgc, WIDTH*8/10 - 45, 15, 20, 5);
  XFillRectangle(Cdisplay, Cwindow, Cgc, WIDTH / 10 + 95, 15, 20, 5);
  if ( clk->pause == 0 )
    XFillRectangle(Cdisplay, Cwindow, Cgc, offx , 5 , 20, 10);

#ifdef DEBUG 
  puts("C2");
#endif 
  if(getplanes() == 1) 
  XCopyArea(Cdisplay, kpix , Cwindow, gcpiece[clk->mycolor], 0,0, 50, 50, 5, 50);
  else 
  XCopyPlane(Cdisplay, kpix , Cwindow, gcpiece[clk->mycolor], 0,0, 50, 50, 5, 50,1);
#ifdef DEBUG 
  puts("C2");
#endif 
  if(getplanes() == 1) 
  XCopyArea(Cdisplay, koutpix , Cwindow, gcoutline, 0,0, 50, 50, 5, 50);
  else 
  XCopyPlane(Cdisplay, koutpix , Cwindow, gcoutline, 0,0, 50, 50, 5, 50,1);
#ifdef DEBUG 
  puts("C2");
#endif 
  Credraw_clk(clk);
}

toggle_clock(clk)
struct clock_data *clk;
{
  stop_clock(clk);
  clk->whoseturn =  (clk->whoseturn == WHITE ) ? BLACK : WHITE;
  start_clock(clk);
}

time_t *optime(clk)
struct clock_data *clk;
{
  return &(clk->opclock.time_left.time);
}

time_t *mytime(clk)
struct clock_data *clk;
{
  return &(clk->myclock.time_left.time);
}

stop_clock(clk)
struct clock_data *clk;
{
  static first = 1; 
  time_t dif;
  unsigned short mdif;
  struct timeb tp;
  int offx;

  if (!first) {
    first = 0;
    ftime(&tp);

    dif = tp.time - CURPLAYER->marker.time;
    mdif = tp.millitm - CURPLAYER->marker.millitm;
    
    CURPLAYER->time_left.time -= dif;
    CURPLAYER->time_left.millitm -= mdif;
  }

  offx = (clk->mycolor == clk->whoseturn) ? WIDTH/10 + 95 : WIDTH * 8/10 - 45;
  XClearArea(Cdisplay, Cwindow, offx , 5+1 , 21, 10, False);
  clk->pause=1;
}

start_clock(clk)
struct clock_data *clk;
{

  int offx; 

  ftime(&(CURPLAYER->marker));
  clk->pause=0;
  offx = (clk->mycolor == clk->whoseturn) ?  WIDTH /10 + 95 : WIDTH* 8/10 - 45;  
  XFillRectangle(Cdisplay, Cwindow, Cgc, offx , 5 , 20, 12);

}



pause_clock(clk)
struct clock_data *clk;
{
  if (clk->pause = !(clk->pause)) stop_clock(clk); else start_clock(clk);
}

ResizeClock(clk)
struct clock_data *clk;
{
  XResizeWindow(Cdisplay, Cwindow, WIDTH + 20, HEIGHT + 180);
  clk->board.used = 1;
}

FillNames(a,b,c,d, clk)
char *a, *b, *c, *d;
struct clock_data *clk;
{
  strcpy(clk->board.names[0],a);
  strcpy(clk->board.names[1],b);
  strcpy(clk->board.names[2],c);
  strcpy(clk->board.names[3],d);
  clk->board.msg[0] = messages[0];
  clk->board.msg[1] = messages[0];
  clk->board.msg[2] = messages[0];
  clk->board.msg[3] = messages[0];
}

CDrawBoard(clk)
struct clock_data *clk;
{
  if(!clk->board.used) return;
  if(getplanes() == 1) 
  XCopyArea(Cdisplay, brd, Cwindow, Cgc, 0, 0, board_width, board_height, 100, 
	    HEIGHT + 50);
  else 
  XCopyPlane(Cdisplay, brd, Cwindow, Cgc, 0, 0, board_width, board_height, 100, 
	    HEIGHT + 50,1);
  
  XDrawString(Cdisplay, Cwindow, Cgc, 50, HEIGHT + 35, clk->board.names[0], 
	      strlen(clk->board.names[0]));
  XDrawString(Cdisplay, Cwindow, Cgc, 250, HEIGHT + 35, clk->board.names[3], 
	      strlen(clk->board.names[3]));
  XDrawString(Cdisplay, Cwindow, Cgc, 50, HEIGHT + 145, clk->board.names[1], 
	      strlen(clk->board.names[1]));
  XDrawString(Cdisplay, Cwindow, Cgc, 250, HEIGHT + 145, clk->board.names[2], 
	      strlen(clk->board.names[2]));


  XDrawString(Cdisplay, Cwindow, Cgc, 50, HEIGHT + 15, clk->board.msg[0], 
	      strlen(clk->board.msg[0]));
  XDrawString(Cdisplay, Cwindow, Cgc, 250, HEIGHT + 15, clk->board.msg[3], 
	      strlen(clk->board.msg[3]));
  XDrawString(Cdisplay, Cwindow, Cgc, 50, HEIGHT + 165, clk->board.msg[1], 
	      strlen(clk->board.msg[1]));
  XDrawString(Cdisplay, Cwindow, Cgc, 250, HEIGHT + 165, clk->board.msg[2], 
	      strlen(clk->board.msg[2]));
}

NewMessage(clk, player, msg)
struct clock_data *clk;
char player; 
char msg;
{
  clk->board.msg[player] = messages[msg];
  switch(player) {
  case 0:
    XClearArea(Cdisplay, Cwindow, 50, HEIGHT , 180, 20, False);
    XDrawString(Cdisplay, Cwindow, Cgc, 50, HEIGHT +15, clk->board.msg[0], 
	      strlen(clk->board.msg[0]));

    break;
  case 1:
    XClearArea(Cdisplay, Cwindow, 50, HEIGHT + 150, 180, 20, False);
    XDrawString(Cdisplay, Cwindow, Cgc, 50, HEIGHT + 165, clk->board.msg[1], 
	      strlen(clk->board.msg[1]));
    break;
  case 2:
    XClearArea(Cdisplay, Cwindow, 250, HEIGHT + 150, 180, 20, False);
    XDrawString(Cdisplay, Cwindow, Cgc, 250, HEIGHT + 165, clk->board.msg[2], 
	      strlen(clk->board.msg[2]));
    break;
  case 3:
    XClearArea(Cdisplay, Cwindow, 250, HEIGHT , 180, 20, False);
    XDrawString(Cdisplay, Cwindow, Cgc, 250, HEIGHT +15, clk->board.msg[3], 
	      strlen(clk->board.msg[3]));
    break;
  }    
  XFlush(Cdisplay);
}


Crefresh(cxevent,clk)
struct clock_data *clk;
XEvent *cxevent;
{
  XRectangle crectangle;
  Region cregion;
  unsigned int w,h; 
  
  cregion = XCreateRegion();
  
  do {

    crectangle.x = (short)cxevent->xexpose.x;
    crectangle.y = (short)cxevent->xexpose.y;
    crectangle.width=(unsigned short) cxevent->xexpose.width;
    crectangle.height=(unsigned short) cxevent->xexpose.height;
    XUnionRectWithRegion(&crectangle, cregion, cregion);
    
  } while (XCheckTypedWindowEvent(Cdisplay, Cwindow,Expose, cxevent));

  XSetRegion(Cdisplay, Cgc, cregion);
  XSetRegion(Cdisplay, gcoutline, cregion);
  XSetRegion(Cdisplay, gcpiece[0], cregion);
  XSetRegion(Cdisplay, gcpiece[1], cregion);

  /* add refresh here */
  Credraw(clk);
  CDrawBoard(clk);

  crectangle.x = (short)0;
  crectangle.y = (short)0;
  
  crectangle.width = 1000;
  crectangle.height = 1000;
  XUnionRectWithRegion(&crectangle, cregion, cregion);
  XSetRegion(Cdisplay, Cgc, cregion);
  XSetRegion(Cdisplay, gcoutline, cregion);
  XSetRegion(Cdisplay, gcpiece[0], cregion);
  XSetRegion(Cdisplay, gcpiece[1], cregion);


  XDestroyRegion(cregion);

}


inits()
{
  digit[0]=XCreateBitmapFromData(Cdisplay,Cwindow, zero_bits, zero_width,zero_height);
  digit[1]=XCreateBitmapFromData(Cdisplay,Cwindow, one_bits, one_width,one_height);
  digit[2]=XCreateBitmapFromData(Cdisplay,Cwindow, two_bits, two_width,two_height);
  digit[3]=XCreateBitmapFromData(Cdisplay,Cwindow, three_bits, three_width,three_height);
  digit[4]=XCreateBitmapFromData(Cdisplay,Cwindow, four_bits, four_width,four_height);
  digit[5]=XCreateBitmapFromData(Cdisplay,Cwindow, five_bits, five_width,five_height);
  digit[6]=XCreateBitmapFromData(Cdisplay,Cwindow, six_bits, six_width,six_height);
  digit[7]=XCreateBitmapFromData(Cdisplay,Cwindow, seven_bits, seven_width,seven_height);
  digit[8]=XCreateBitmapFromData(Cdisplay,Cwindow, eight_bits, eight_width,eight_height);
  digit[9]=XCreateBitmapFromData(Cdisplay,Cwindow, nine_bits, eight_width,eight_height);

  kpix = XCreateBitmapFromData(Cdisplay, Cwindow, knight_piece_bits,
					     knight_piece_width, knight_piece_height);

  koutpix = XCreateBitmapFromData(Cdisplay, Cwindow, knight_out_bits,
					     knight_out_width, knight_out_height);
  brd = XCreateBitmapFromData(Cdisplay, Cwindow, board_bits, board_width, board_height);

  points[0].x = 25 + WIDTH / 10;
  points[0].y = 25;
  points[1].x = 60 ;
  points[1].y = - 20 ;
  points[2].x = WIDTH * 8 / 10 - 30 ;
  points[2].y = 0;
  points[3].x = -60 ;
  points[3].y = 20;

  points2[0].x = WIDTH / 10 + 55 + WIDTH * 8 / 10;
  points2[0].y = 5;
  points2[1].x = 0;
  points2[1].y = 120; 
  points2[2].x = -60; 
  points2[2].y = 20;
}
