/* nuxui.c - (new) Unix user interface for CHESS

	This file was extracted from the original GNU Chess file nuxui.c
	and converted to C++ by Warwick Allison.  It represents the ASCII
	interface requirements to implement ui.h.

  Revision: 1990-05-09

  Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc.
  Copyright (c) 1988, 1989, 1990  John Stanback

  Modified extensively Nov 1989 Christopher North-Keys
    40x24 two-colour display
	option for shading black squares
	expanded game save, list, and restore features using $HOME
	option to disable display of coordinates
	optional auto-updating of positional information
	optional starring of black side
	mass toggle for reverse-video functions

  This file is part of CHESS.

  CHESS is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY.  No author or distributor accepts responsibility to anyone for
  the consequences of using it or for whether it serves any particular
  purpose or works at all, unless he says so in writing.  Refer to the CHESS
  General Public License for full details.

  Everyone is granted permission to copy, modify and redistribute CHESS, but
  only under the conditions described in the CHESS General Public License.
  A copy of this license is supposed to have been given to you along with
  CHESS so you can know your rights and responsibilities.  It should be in a
  file named COPYING.  Among other things, the copyright notice and this
  notice must be preserved on all copies.
*/


#include <ctype.h>
#include <signal.h>
#ifdef MSDOS
#include <dos.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define ESC 0x1B
#define refresh() fflush(stdout)

int mycntl1, mycntl2;
static void param (short n);
#else
//#define refresh() 
#include <sys/param.h>
#include <sys/types.h>
#include <sys/file.h>

#include <curses.h>
#undef bool // Curses defines it as char !!!
#undef TRUE
#undef FALSE

#include <bool.h>

#endif /* MSDOS */
static char* ColorStr[2] = {"White", "Black"};

#include "ui.h"
#include "gnuchess.h"

#define pxx " PNBRQK"
#define qxx " pnbrqk"
#define rxx "12345678"
#define cxx "abcdefgh"
#define TAB (43)
/* coordinates within a square for the following are ([1,5],[1,3]) */
#define SQW (5)
#define SQH (3)
#define VIR_C(s)  ((flag.reverse) ? 7-column(s) : column(s))
#define VIR_R(s)  ((flag.reverse) ? 7-row(s) : row(s))
#define VSQ_X(x)  ((flag.reverse) ? SQW + 1 - (x) : (x))
#define VSQ_Y(y)  ((flag.reverse) ? SQH + 1 - (y) : (y))
#define Vblack(s) (!((VIR_C(s) + VIR_R(s)) % 2))
/* Squares swapped */
#define Vcoord(s,x,y) \
	((SQW)*(VIR_C(s)))+(x),((SQH)*(7-VIR_R(s))+(y))
#define XYcoord(X,Y,x,y) \
	(((SQW)*(X))+(x)),((SQH)*(7-(Y))+(y))
/* Squares and internal locations swapped */
#define VcoordI(s,x,y) \
	((SQW)*(VIR_C(s)))+(VSQ_X(x)),((SQH)*(7-VIR_R(s))+(VSQ_Y(y)))
/* Squares and internal rows swapped */
#define VcoordR(s,x,y) \
	((SQW)*(VIR_C(s)))+(x),((SQH)*(7-VIR_R(s))+(VSQ_Y(y)))

#if defined(MSDOS) && !defined(SEVENBIT)
short rv = 0;
static void ONormal (void);
static void OReverse (void);
#else
short stars = 0;
short rv = 1;
short shade = 0;
static void ONormal (void);
static void OReverse (void);
#endif /* MSDOS && !SEVENBIT */

//#define standout() wstandout(stdscr)
//#define standend() wstandend(stdscr)
//#define clear() wclear(stdscr)
//#define move(x,y) wmove(stdscr,x,y)
//#define clrtoeol() wclrtoeol(stdscr)

void TerminateSearch (int);


void ui_Initialize()
{
#ifndef MSDOS
  initscr ();
  crmode ();
#else
  mycntl1 = mycntl2 = 0;
#endif /* MSDOS */
}

void ui_Finalize()
{
  gotoXY (1, 24);
#ifndef MSDOS
  nocrmode ();
  endwin ();
#endif /* MSDOS */
}

void ui_GiveHelp (int compiswhite,int level,int easy,int maxdep,int dither,int hash)
{
  ClrScreen ();
  wprintw(stdscr,"CHESS command summary\n");
  wprintw(stdscr,"g1f3     move from g1 to f3      quit      Exit Chess\n");
  wprintw(stdscr,"Nf3      move knight to f3       beep      on/off\n");
  wprintw(stdscr,"o-o      castle king side        easy      on/off\n");
  wprintw(stdscr,"o-o-o    castle queen side       hash      on/off\n");
  wprintw(stdscr,"bd       redraw board            reverse   board display\n");
  wprintw(stdscr,"list     game to chess.lst       book      on/off\n");
  wprintw(stdscr,"undo     undo last ply           remove    take back a move\n");
  wprintw(stdscr,"edit     edit board              force     enter game moves\n");
  wprintw(stdscr,"switch   sides with computer     both      computer match\n");
  wprintw(stdscr,"white    computer plays white    black     computer plays black\n");
  wprintw(stdscr,"depth    set search depth        level     select level\n");
  wprintw(stdscr,"post     principle variation     hint      suggest a move\n");
  wprintw(stdscr,"save     game to file            get       game from file\n");
  wprintw(stdscr,"random   randomize play          new       start new game\n");
  wprintw(stdscr,"rv       toggle reverse video    coords    toggle coords\n");
#if !defined(MSDOS) || defined(SEVENBIT)
  wprintw(stdscr,"shade    toggle shade black      stars     toggle stars\n");
#endif /* !MSDOS || SEVENBIT */
  wprintw(stdscr,"p        show coordinate values\n");
  gotoXY (10, 21);
  wprintw(stdscr,"Computer: %s", ColorStr[compiswhite]);
  gotoXY (10, 22);
  wprintw(stdscr,"Opponent: %s", ColorStr[!compiswhite]);
  gotoXY (10, 23);
  wprintw(stdscr,"Level: %ld", level);
  gotoXY (10, 24);
  wprintw(stdscr,"Easy mode: %s", easy ? "ON" : "OFF");
  gotoXY (40, 21);
  wprintw(stdscr,"Depth: %d", maxdep);
  gotoXY (40, 22);
  wprintw(stdscr,"Random: %s", (dither) ? "ON" : "OFF");
  gotoXY (40, 23);
  wprintw(stdscr,"Transposition table: %s", hash ? "ON" : "OFF");
  gotoXY (40, 24);
  wprintw(stdscr,"Hit <RET> to return: ");
  refresh ();
  fflush(stdin);
  getchar();
  ClrScreen ();
  UpdateDisplay (0, 0, 1, 0);
}

void ui_ShowEditHelp()
{
  ClrScreen ();
  UpdateDisplay (0, 0, 1, 0);
  gotoXY (TAB, 3);
  wprintw(stdscr,".   Exit to main");
  gotoXY (TAB, 4);
  wprintw(stdscr,"#   Clear board");
  gotoXY (TAB, 5);
  wprintw(stdscr,"c   Change sides");
  gotoXY (TAB, 7);
  wprintw(stdscr,"Enter piece & location: ");
}

void ui_ShowEditColor(int col)
{
  gotoXY (TAB, 6);
  wprintw(stdscr,"Editing: %s", ColorStr[col]);
  gotoXY (TAB + 24, 7);
  ClrEoln ();
}

void ui_GetPieceAndLocation(char *s)
{
  wrefresh(stdscr);
  wscanw(stdscr,"%s", s);
}

void ui_ShowPlayers(bool reverse,int CompIsBlack)
{
  gotoXY (TAB, ((reverse) ? 23 : 2));
  wprintw(stdscr,"%s", (CompIsBlack) ? "Computer" : "Human   ");
  gotoXY (TAB, ((reverse) ? 2 : 23));
  wprintw(stdscr,"%s", (!CompIsBlack) ? "Computer" : "Human   ");
}

void ui_ShowDepth(int depth, char ch)
{
  gotoXY (TAB, 4);
  wprintw(stdscr,"Depth= %d%c ", depth, ch);
  ClrEoln ();
}

void ui_ShowScore(int score)
{
  gotoXY (TAB, 5);
  wprintw(stdscr,"Score= %d", score);
  ClrEoln ();
}

void ui_ShowMessage(char *msg)
{
  gotoXY (TAB, 6);
  wprintw(stdscr,"%s", msg);
  ClrEoln ();
}

void ui_ClearMessage()
{
  gotoXY (TAB, 6);
  ClrEoln ();
}

void ui_ShowCurrentMove(int pnt, char *move)
{
  gotoXY (TAB, 7);
  wprintw(stdscr,"(%2d) %4s", pnt, move);
}

void ui_ShowTitle()
{
  gotoXY (TAB, 10);
#ifdef MSDOS
  wprintw(stdscr,"GNU Chess display (MS-DOS, Mar 90)");
#else
  wprintw(stdscr,"GNU Chess display (Nov 89)");
#endif /* MSDOS */
}

void ui_ShowSideToMove(int movenum, int who)
{
  gotoXY (TAB, 14);
  wprintw(stdscr,"%2d:   %s", movenum,ColorStr[who]);
  ClrEoln ();
}

void ui_PromptForMove()
{
  gotoXY (TAB, 19);
  wprintw(stdscr,"Your move is? ");
  ClrEoln ();
}

void ui_ShowNodeCnt(long int NodeCnt, long int evrate)
{
  gotoXY (TAB, 21);
  wprintw(stdscr,"Nodes= %8ld, Nodes/Sec= %5ld", NodeCnt, evrate);
  ClrEoln ();
}  

void ui_ShowPlyMove(int ply,char *move)
{
  if (ply % 4 == 1)
    {
      gotoXY (TAB, 8+ply/4);
      ClrEoln ();
    }
  wprintw(stdscr,"%5s ", move);
}

void ui_NoMorePly(int ply)
{
  ClrEoln ();
  while (ply < 52)
  {
    if (ply % 4 == 1)
    {
      gotoXY (TAB, 8+ply/4);
      ClrEoln ();
    }
    ply++;
  }
}

void ui_SearchStartStuff(int side)
{
  int i;
  
  signal (SIGINT, TerminateSearch);
#ifdef MSDOS
  side++;				/* shut up the compiler */
#else
  signal (SIGQUIT, TerminateSearch);
#endif /* MSDOS */
  for (i = 4; i < 14; i++)
    {
      gotoXY (TAB, i);
      ClrEoln ();
    }
}

void ui_ShowComputerMove(char *move, int feature)
{
  gotoXY (TAB, 17);
  wprintw(stdscr,"My move is: %s", move);
  if (flag.beep)
    putchar (7);
  ClrEoln ();

  gotoXY (TAB, 24);
  switch (feature)
  {
    case 1: wprintw(stdscr,"Drawn game!");
  break; case 2: wprintw(stdscr,"Opponent mates!");
  break; case 3: wprintw(stdscr,"Computer mates!");
  break; case 4: wprintw(stdscr,"Opponent will soon mate!");
  break; case 5: wprintw(stdscr,"Computer will soon mate!");
  }

  ClrEoln ();
}

void ui_ShowMaxTree(int maxtree)
{
  gotoXY (TAB, 22);
  wprintw(stdscr,"Max Tree= %5d", maxtree);
  ClrEoln ();
}

void ui_ShowClock(bool OnWhiteSide, int minutes, int seconds)
{
  if (OnWhiteSide)
    gotoXY (60, 23);
  else
    gotoXY (60, 2);
  wprintw(stdscr,"%d:%2d   ", minutes, seconds);
}

void ui_ClrScreen()
{
#ifdef MSDOS
  putchar(ESC);
  putchar('[');
  putchar('2');
  putchar('J');
#else
  clear ();
#endif /* MSDOS */
  refresh ();
}

void ui_DrawPiece(bool used, bool isblack, int x, int y, int piece)
{
  gotoXY (2+SQW*x, 2+SQH*(7-y));

  if (used)
    {
      if (isblack) {
        if (rv)
	  OReverse ();
#if defined(MSDOS) && !defined(SEVENBIT)
        wprintw(stdscr," %c ", qxx[piece]);
#else
        wprintw(stdscr,(stars ? "*%c*" : " %c "), qxx[piece]);
#endif /* MSDOS && !SEVENBIT */
        ONormal ();
      } else {
#if defined(MSDOS) && !defined(SEVENBIT)
        if (!rv)
	  OReverse ();
        wprintw(stdscr," %c ", qxx[piece]);
        ONormal ();
#else
        wprintw(stdscr," %c ", qxx[piece]);
#endif /* MSDOS && !SEVENBIT */
      }
    } else {
#if defined(MSDOS) && !defined(SEVENBIT)
      if (rv)
    	wprintw(stdscr,Vblack (sq) ? "\262\262\262" : "\260\260\260");
      else
    	wprintw(stdscr,Vblack (sq) ? "\260\260\260" : "\262\262\262");
#else
      if (shade)
	/*wprintw(stdscr,Vblack (sq) ? "///" : "   ");*/
        wprintw(stdscr,(!((x + y) % 2)) ? "///" : "   ");
      else
	{
	  /*if (Vblack (sq))*/
          if (!((x + y) % 2))
	    OReverse ();
	  wprintw(stdscr,"   ");
	  ONormal ();
	}
#endif /* MSDOS && !SEVENBIT */
    }
}

void ui_DrawSquare(int x, int y, bool isblack)
{
#if defined(MSDOS) && !defined(SEVENBIT)
  if (rv)
    {
      gotoXY (XYcoord (x,y, 1, 1));
      wprintw(stdscr,isblack ? "\262\262\262\262\262" : "\260\260\260\260\260");
      gotoXY (XYcoord (x,y, 1, 2));
      wprintw(stdscr,isblack ? "\262\262\262\262\262" : "\260\260\260\260\260");
      gotoXY (XYcoord (x,y, 1, 3));
      wprintw(stdscr,isblack ? "\262\262\262\262\262" : "\260\260\260\260\260");
    }
  else
    {
      gotoXY (XYcoord (x,y, 1, 1));
      wprintw(stdscr,isblack ? "\260\260\260\260\260" : "\262\262\262\262\262");
      gotoXY (XYcoord (x,y, 1, 2));
      wprintw(stdscr,isblack ? "\260\260\260\260\260" : "\262\262\262\262\262");
      gotoXY (XYcoord (x,y, 1, 3));
      wprintw(stdscr,isblack ? "\260\260\260\260\260" : "\262\262\262\262\262");
    }
#else
  if (shade)
    {
      gotoXY (XYcoord (x,y, 1, 1));
      wprintw(stdscr,isblack ? "/////" : "     ");
      gotoXY (XYcoord (x,y, 1, 2));
      wprintw(stdscr,isblack ? "/////" : "     ");
      gotoXY (XYcoord (x,y, 1, 3));
      wprintw(stdscr,isblack ? "/////" : "     ");
    }
  else
    {
      if (isblack)
	OReverse ();
      gotoXY (XYcoord (x,y, 1, 1));
      wprintw(stdscr,"     ");
      gotoXY (XYcoord (x,y, 1, 2));
      wprintw(stdscr,"     ");
      gotoXY (XYcoord (x,y, 1, 3));
      wprintw(stdscr,"     ");
      ONormal ();
    }
#endif /* MSDOS && !SEVENBIT */
}

void ui_DrawCoords()
{
  short z;

  for (z = 0; z <= 7; z++)
    {
      short sq;

      sq = z << 3;
      gotoXY (VcoordI (sq, 1, 1));
#if !defined(MSDOS) || defined(SEVENBIT)
      if ((Vblack (sq) || shade) && rv)
#endif /* !MSDOS || SEVENBIT */
	OReverse ();
      wprintw(stdscr,"%d", 1 + z);
      ONormal ();
    }

  for (z = 0; z <= 7; z++)
    {
      short sq;

      sq = z;
      gotoXY (VcoordI (sq, SQW, SQH));
#if !defined(MSDOS) || defined(SEVENBIT)
      if ((Vblack (sq) || shade) && rv)
#endif /* !MSDOS || SEVENBIT */
	OReverse ();
      wprintw(stdscr,"%c", cxx[z]);
      ONormal ();
    }

#if !defined(MSDOS) || defined(SEVENBIT)
  for (z = 1; z <= (8 * SQH); z++)
    {
      gotoXY ((8 * SQW) + 1, z);
      wprintw(stdscr,"|");
    }
#endif /* MSDOS && !SEVENBIT */
}

void ui_ShowPosnValue(short sq, int score)
{
  gotoXY (VcoordR (sq, 2, 1));
#if !defined(MSDOS) || defined(SEVENBIT)
  if (Vblack (sq) && !shade)
    OReverse ();
#endif /* !MSDOS || SEVENBIT */

  if (color[sq] != neutral)
    wprintw(stdscr,"%3d", svalue[sq]);
  else
#if defined(MSDOS) && !defined(SEVENBIT)
    {
      if (rv)
     	wprintw(stdscr,Vblack (sq) ? "\262\262\262" : "\260\260\260");
      else
    	wprintw(stdscr,Vblack (sq) ? "\260\260\260" : "\262\262\262");
    }
#else
    wprintw(stdscr,shade && Vblack (sq) ? "///" : "   ");
#endif /* MSDOS && !SEVENBIT */
  ONormal ();
}

void ui_GetFilename(char *prompt,char *name)
{
  ShowMessage ("File name: ");
  wrefresh(stdscr);
  wscanw(stdscr,"%s", name);
}

void ui_ShowFileLoading(char *name)
{
  ShowMessage("Loading ");
  wprintw(stdscr,"%s", name);
}

void ui_LoadDone()
{
  ShowMessage ("Load done.  Press <Ret>");
  fflush (stdin);
  getchar ();
}

void ui_LoadFailed()
{
  ShowMessage ("Load failed");
  return;
}

void ui_ShowFileSaving(char *name)
{
  ShowMessage("Saving ");
  wprintw(stdscr,"%s", name);
}

void ui_SaveFailed()
{
  ShowMessage ("Not saved");
  return;
}

void ui_SaveDone()
{
  ShowMessage ("Save done.  Press <Ret>");
  fflush (stdin);
  getchar ();
}

void ui_ChangeSearchDepth(int *newdepth)
{
  ShowMessage ("depth= ");
  wrefresh(stdscr);
  wscanw(stdscr,"%hd", newdepth);
}

void ui_ChangeContempt(int *newcontempt)
{
  ShowMessage ("contempt= ");
  wrefresh(stdscr);
  wscanw(stdscr,"%hd", newcontempt);
}

void ui_ChangeLevel(int *newlevel)
{
  ClrScreen ();
  gotoXY (32, 2);
  wprintw(stdscr,"CHESS");
  gotoXY (20, 4);
  wprintw(stdscr," 1.   60 moves in   5 minutes");
  gotoXY (20, 5);
  wprintw(stdscr," 2.   60 moves in  15 minutes");
  gotoXY (20, 6);
  wprintw(stdscr," 3.   60 moves in  30 minutes");
  gotoXY (20, 7);
  wprintw(stdscr," 4.   40 moves in  30 minutes");
  gotoXY (20, 8);
  wprintw(stdscr," 5.   40 moves in  60 minutes");
  gotoXY (20, 9);
  wprintw(stdscr," 6.   40 moves in 120 minutes");
  gotoXY (20, 10);
  wprintw(stdscr," 7.   40 moves in 240 minutes");
  gotoXY (20, 11);
  wprintw(stdscr," 8.    1 move  in  15 minutes");
  gotoXY (20, 12);
  wprintw(stdscr," 9.    1 move  in  60 minutes");
  gotoXY (20, 13);
  wprintw(stdscr,"10.    1 move  in 600 minutes");

  gotoXY (20, 17);
  wprintw(stdscr,"Enter Level: ");
  refresh ();
  wrefresh(stdscr);
  wscanw(stdscr,"%ld", &Level);
  ClrScreen ();
}

void ui_ChoosePiece(char *s)
{
  ShowMessage ("Enter piece: ");
  wrefresh(stdscr);
  wscanw(stdscr,"%s", s);
}

void ui_GetMove(char *s)
{
  ui_PromptForMove();
  wrefresh(stdscr);
  wscanw(stdscr,"%s", s);
}

void ui_ToggleRV()
{
  rv = !rv;
#if !defined(MSDOS) || defined(SEVENBIT)
  shade = !rv;
  stars = !rv;
#endif /* MSDOS && !SEVENBIT */
  UpdateDisplay (0, 0, 1, 0);
}

void OReverse()
{
#ifdef MSDOS
  putchar (ESC);
  putchar ('[');
  param (7);
  putchar ('m');
#else
  standout ();
/* attron (A_REVERSE); */
#endif /* MSDOS */
}

void ONormal()
{
#ifdef MSDOS
  putchar (ESC);
  putchar ('[');
  param (0);
  putchar ('m');
#else
  standend ();
/* attroff (A_REVERSE);*/
#endif /* MSDOS */
}


void ui_ToggleStars()
{
  stars = !stars;
  UpdateDisplay (0, 0, 1, 0);
}

void ui_ToggleShade()
{
  shade = !shade;
  ClrScreen ();
  UpdateDisplay (0, 0, 1, 0);
}

void
gotoXY (short int x, short int y)
{
#ifdef MSDOS
  putchar(ESC);
  putchar('[');
  param(y);
  putchar(';');
  param(x);
  putchar('H');
#else
  move (y - 1, x - 1);
#endif /* MSDOS */
}

void
ClrScreen (void)
{
  ui_ClrScreen();
}

void
ClrEoln (void)
{
#ifdef MSDOS
  putchar(ESC);
  putchar('[');
  putchar('K');
#else
  clrtoeol ();
#endif /* MSDOS */
  refresh ();
}

#ifdef MSDOS
void
param(short n)
{
  if (n >= 10)
    {
    register short d, q;
    q = n/10; d = n%10;
    putchar(q + '0');
    putchar(d + '0');
  }
  else
    putchar(n + '0');
}
#endif /* MSDOS */

int ui_AskAbort()
{
  char s[80];

  ShowMessage ("Abort? ");
  wrefresh(stdscr);
  wscanw(stdscr,"%s", s);
  return (strcmp (s, "yes") == 0);
}

void ui_ClearEditHelp()
{
  ClrScreen();
}

void ui_RefreshEarly()
{
  wrefresh(stdscr);
}

void ui_ShowHint(char *move)
{
  gotoXY (TAB, 6);
  wprintw(stdscr,"Try: %s", move);
  ClrEoln ();
}

void ui_RejectMove(char *move)
{
	ui_ShowMessage("Illegal move");
}
