/*>>> sandci.c: SAN project dispatch command input routines */

/* Revised: 1994.02.06 */

#include <stdio.h>
#include <time.h>
#include <string.h>

#include "sandef.h"
#include "sanvar.h"

#include "sanbap.h"
#include "sancmd.h"
#include "sandci.h"
#include "sandsp.h"
#include "sanenu.h"
#include "sanfen.h"
#include "sangtc.h"
#include "sanhsh.h"
#include "sanint.h"
#include "sanmnd.h"
#include "sanmne.h"
#include "sanmpu.h"
#include "sanpce.h"
#include "sanpgn.h"
#include "sanrdr.h"
#include "sanrst.h"
#include "sansel.h"
#include "sanslm.h"
#include "sansss.h"
#include "santag.h"
#include "sanutl.h"
#include "sanval.h"

/*--> SANDcAUTO: do command: performa automatic competition */
nonstatic
void
SANDcAUTO (void)
{
  char ch;

  if (strlen (tkv[1]) != 1)
    SANBadParmForm (1);
  else
    {
      ch = tkv[1][0];
      if (!SANCheckColor (ch))
        SANBadParmForm (1);
      else
        SANBAPAuto (SANEvalColor (ch));
    };

  return;
}

/*--> SANDcAFDO: do command: append file: dribble output */
nonstatic
void
SANDcAFDO (void)
{
  charptrT fn;

/* get file name */

  fn = tkv[1];

/* close dribble file if needed */

  if (do_fptr != NULL)
    SANTextFileClose (do_fptr);

/* attempt to open file in append mode */

  do_fptr = SANTextFileOpen (fn, "a");
  if (do_fptr == NULL)
    SANDspError ("Can't open file for appending");

  return;
}

/*--> SANDcBEEP: do command: emit ASCII BEL */
nonstatic
void
SANDcBEEP (void)
{
  (void) fputc (0x07, stderr);

  return;
}

/*--> SANDcCALL: do command: call command subfile */
nonstatic
void
SANDcCALL (void)
{
  if (!SANCMDOpen (tkv[1]))
    SANDspError ("Can't call command file");

  return;
}

/*--> SANDcCFDO: do command: close file: dribble output */
nonstatic
void
SANDcCFDO (void)
{
  if (do_fptr != NULL)
    {
      SANTextFileClose (do_fptr);
      do_fptr = NULL;
    };

  return;
}

/*--> SANDcCVCA: do command: clear value: castling availability */
nonstatic
void
SANDcCVCA (void)
{
  siT i, flag;
  castT cast;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (SANCheckCastling (tkv[i]))
      i++;
    else
      flag = 0;

  if (!flag)
    SANBadParmForm (i);
  else
    {
      cast = curr_e.e_cast;
      for (i = 1; i < tkn; i++)
        cast &= ~(bit << SANEvalCastling (tkv[i]));
      SANPutCAST (cast);
    };

  return;
}

/*--> SANDcCVCB: do command: clear value: chessboard */
nonstatic
void
SANDcCVCB (void)
{
  SANClrBoard ();

  return;
}

/*--> SANDcCVEP: do command: clear value: en passant target square */
nonstatic
void
SANDcCVEP (void)
{
  SANPutEPSQ (sq_nil);

  return;
}

/*--> SANDcCVGT: do command: clear value: game termination */
nonstatic
void
SANDcCVGT (void)
{
  SANGTCSet (gtc_norm);

  return;
}

/*--> SANDcCVOP: do command: clear value: option */
nonstatic
void
SANDcCVOP (void)
{
  siT flag, i;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (!SANCheckOption (tkv[i]))
      flag = 0;
    else
      i++;

  if (!flag)
    SANBadParmForm (i);
  else
    for (i = 1; i < tkn; i++)
      optnv[SANEvalOption (tkv[i])] = 0;

  return;
}

/*--> SANDcCVSQ: do command: clear value: square */
nonstatic
void
SANDcCVSQ (void)
{
  siT i, flag;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (SANCheckSquare (tkv[i]))
      i++;
    else
      flag = 0;

  if (!flag)
    SANBadParmForm (i);
  else
    for (i = 1; i < tkn; i++)
      SANPutSq (SANEvalSquare (tkv[i]), cp_v0);

  return;
}

/*--> SANDcCVTF: do command: clear value: tag field */
nonstatic
void
SANDcCVTF (void)
{
  siT i, flag;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (SANTagLocate (tkv[i]) != NULL)
      i++;
    else
      flag = 0;

  if (!flag)
    SANBadParmForm (i);
  else
    for (i = 1; i < tkn; i++)
      SANTagUpdate (SANTagLocate (tkv[i]), "");

  return;
}

/*--> SANDcDVAS: do command: display value: hash address and signature */
nonstatic
void
SANDcDVAS (void)
{
  sprintf (stv, "Hash address: %08lx   Hash signature: %08lx",
           curr_e.e_mhca, curr_e.e_mhcs);
  SANDspSTVNL ();

  return;
}

/*--> SANDcDVCB: do command: display value: chess board */
nonstatic
void
SANDcDVCB (void)
{
  SANDspBoard ();

  return;
}

/*--> SANDcDVCR: do command: display value: correspondence report */
nonstatic
void
SANDcDVCR (void)
{
  SANPGNCorrespondenceReport (stdout);

  return;
}

/*--> SANDcDVER: do command: display value: event report */
nonstatic
void
SANDcDVER (void)
{
  SANPGNEventReport (stdout);

  return;
}

/*--> SANDcDVFE: do command: display value: Forsyth-Edwards notation */
nonstatic
void
SANDcDVFE (void)
{
  charptrT s;

  s = SANFENGen ();
  SANDspLine (s);
  SANMemFree (s);

  return;
}

/*--> SANDcDVHG: do command: display value: hash generation tables */
nonstatic
void
SANDcDVHG (void)
{
  SANHashDisplayGenerationTables ();

  return;
}

/*--> SANDcDVSS: do command: display value: search strategies */
nonstatic
void
SANDcDVSS (void)
{
  rcT c;

  for (c = c_w; c <= c_b; c++)
    {
      SANDspChar (accv[c]);
      SANDspStr (": ");
      SANDspLine (ssstrv[ssv[c]]);
    };

  return;
}

/*--> SANDcDVTE: do command: display value: tag environment */
nonstatic
void
SANDcDVTE (void)
{
  SANDspError ("Not yet implemented");

  return;
}

/*--> SANDcDVTF: do command: display value: tag field */
nonstatic
void
SANDcDVTF (void)
{
  siT i, flag;
  charptrT s;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (SANTagLocate (tkv[i]) == NULL)
      flag = 0;
    else
      i++;

  if (!flag)
    SANBadParmForm (i);
  else
    for (i = 1; i < tkn; i++)
      {
        s = SANTagFormat (SANTagLocate (tkv[i]));
        SANDspLine (s);
        SANMemFree (s);
      };

  return;
}

/*--> SANDcDVTS: do command: display value: timestamp */
nonstatic
void
SANDcDVTS (void)
{
  SANDspTimestamp ();

  return;
}

/*--> SANDcECHO: do command: echo arguments */
nonstatic
void
SANDcECHO (void)
{
  siT i;
  for (i = 1; i < tkn; i++)
    {
      SANDspStr (tkv[i]);
      if (i < (tkn - 1))
        SANDspChar (' ');
    };
  SANDspNL ();

  return;
}

/*--> SANDcENUM: do command: enumerate descendents */
nonstatic
void
SANDcENUM (void)
{
  siT depth;
  liT total;

/* check input */

  if (!SANCheckShortInteger (tkv[1]))
    SANBadParmForm (1);
  else
    {
      depth = SANEvalShortInteger (tkv[1]);
      if ((depth < 1) || (depth >= aL))
        SANBadParmValue (1);
      else if (SANStatus () == gs_norm)
        {
          total = SANEnumerate (depth);
          SANDspStrLINL ("Total: ", total);
        };
    };

  return;
}

/*--> SANDcEXIT: do command: exit program */
nonstatic
void
SANDcEXIT (void)
{
  progdone = 1;

  return;
}

/*--> SANDcEXSM: do command: execute supplied move */
nonstatic
void
SANDcEXSM (void)
{
  mptrT mptr;

  mptr = SANDecodeAux (tkv[1]);
  if (mptr == NULL)
    SANDspError ("No such move");
  else
    SANPlayMove (mptr);

  return;
}

/*--> SANDcGAME: do command: autoplay to end of game */
nonstatic
void
SANDcGAME (void)
{
  while (SANStatus () == gs_norm)
    {
      SANSelect ();
      SANPlayMove (&select_m);
    };

  return;
}

/*--> SANDcHELP: do command: display help */
nonstatic
void
SANDcHELP (void)
{
  cmdT cmd;
  optnT optn;

  SANDspLine ("Commands:");
  for (cmd = 0; cmd < cmdL; cmd++)
    {
      SANDspStr ("  ");
      SANDspStr (civ[cmd].ci_name);
      SANDspStr (": ");
      SANDspLine (civ[cmd].ci_help);
    };
  SANDspNL ();

  SANDspLine ("Options:");
  for (optn = 0; optn < optnL; optn++)
    {
      SANDspStr ("  ");
      SANDspStr (optnnamev[optn]);
      SANDspStr (": ");
      SANDspLine (optnhelpv[optn]);
    };
  SANDspNL ();

  return;
}

/*--> SANDcLFER: do command: load file: event report */
nonstatic
void
SANDcLFER (void)
{
  charptrT fn;
  siT n;

  fn = tkv[1];

  n = 0;
  if (!SANRGSingle (fn, &n))
    SANDspError ("Can't load event report");

  return;
}

/*--> SANDcNEWG: do command: new game */
nonstatic
void
SANDcNEWG (void)
{
  SANInitGround ();

  return;
}

/*--> SANDcNOOP: do command: no operation */
nonstatic
void
SANDcNOOP (void)
{

  return;
}

/*--> SANDcOFDO: do command: open file: dribble output */
nonstatic
void
SANDcOFDO (void)
{
  charptrT fn;

/* get file name */

  fn = tkv[1];

/* close dribble file if needed */

  if (do_fptr != NULL)
    SANTextFileClose (do_fptr);

/* attempt to open file in write mode */

  do_fptr = SANTextFileOpen (fn, "w");
  if (do_fptr == NULL)
    SANDspError ("Can't open file for writing");

  return;
}

/*--> SANDcPLAY: do command: select and play N moves */
nonstatic
void
SANDcPLAY (void)
{
  siT flag, i, n = {0};

  flag = 1;
  if (tkn == 1)
    n = 1;
  else if (!SANCheckShortInteger (tkv[1]))
    {
      SANBadParmForm (1);
      flag = 0;
    }
  else
    {
      n = SANEvalShortInteger (tkv[1]);
      if (n < 0)
        {
          SANBadParmValue (1);
          flag = 0;
        };
    };

  if (flag)
    {
      i = 0;
      while ((i < n) && (SANStatus () == gs_norm))
        {
          SANSelect ();
          SANPlayMove (&select_m);
          i++;
        };
    };

  return;
}

/*--> SANDcRTMV: do command: retract N played moves */
nonstatic
void
SANDcRTMV (void)
{
  siT flag, i, n = {0};

  flag = 1;
  if (tkn == 1)
    n = 1;
  else if (!SANCheckShortInteger (tkv[1]))
    {
      SANBadParmForm (1);
      flag = 0;
    }
  else
    {
      n = SANEvalShortInteger (tkv[1]);
      if (n < 0)
        {
          SANBadParmValue (1);
          flag = 0;
        };
    };

  if (flag)
    {
      if (n > hn)
        {
          SANDspNote ("Can't retract past history start");
          n = hn;
        };
      for (i = 0; i < n; i++)
        SANUnplayMove ();
    };

  return;
}

/*--> SANDcRTRN: do command: return from command subfile */
nonstatic
void
SANDcRTRN (void)
{
  SANCMDClose ();

  return;
}

/*--> SANDcSFCR: do command: save file: correspondence report */
nonstatic
void
SANDcSFCR (void)
{
  FILEptrT fptr;
  charptrT fn;

  fn = tkv[1];

  fptr = SANTextFileOpen (fn, "w");
  if (fptr == NULL)
    SANDspError ("Can't open file for output");
  else
    {
      SANPGNCorrespondenceReport (fptr);
      SANTextFileClose (fptr);
    };

  return;
}

/*--> SANDcSFER: do command: save file: event report */
nonstatic
void
SANDcSFER (void)
{
  FILEptrT fptr;
  charptrT fn;

  fn = tkv[1];

  fptr = SANTextFileOpen (fn, "w");
  if (fptr == NULL)
    SANDspError ("Can't open file for output");
  else
    {
      SANPGNEventReport (fptr);
      SANTextFileClose (fptr);
    };

  return;
}

/*--> SANDcSRCH: do command: search for target move(s) */
nonstatic
void
SANDcSRCH (void)
{
  siT flag, i;
  mptrT mptr;
  slaT sla;
  sanT san;

  flag = 1;
  if (SANStatus () == gs_norm)
    {
      /* construct list */

      SANSLMInitAnchor (&sla);
      i = 1;
      while (flag && (i < tkn))
        {
          mptr = SANDecodeAux (tkv[i]);
          if (mptr == NULL)
            {
              SANBadParmForm (i);
              flag = 0;
            }
          else
            {
              SANEncode (mptr, san);
              SANSLMAppend (&sla, san);
            };
          i++;
        };

      /* perform search */

      if (flag)
        {
          /* move result */

          SANSelect ();
          SANDspStr ("Selected: ");
          SANDspSANNL (&select_m);

          /* search match result */

          SANEncode (&select_m, san);
          if (SANSLMMember (&sla, san) == NULL)
            SANDspLine ("*srch: 0: failure");
          else
            SANDspLine ("*srch: 1: success");
        };

      /* clean up */

      SANSLMReleaseAnchor (&sla);
    };

  return;
}

/*--> SANDcSTAT: do command: status report */
nonstatic
void
SANDcSTAT (void)
{
  SANDspStatus ();

  return;
}

/*--> SANDcSVAC: do command: set value: active color */
nonstatic
void
SANDcSVAC (void)
{
  char ch;

  if (strlen (tkv[1]) != 1)
    SANBadParmForm (1);
  else
    {
      ch = tkv[1][0];
      if (!SANCheckColor (ch))
        SANBadParmForm (1);
      else
        SANPutACTC (SANEvalColor (ch));
    };

  return;
}

/*--> SANDcSVCA: do command: set value: castling availability */
nonstatic
void
SANDcSVCA (void)
{
  siT i, flag;
  castT cast;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (SANCheckCastling (tkv[i]))
      i++;
    else
      flag = 0;

  if (!flag)
    SANBadParmForm (i);
  else
    {
      cast = curr_e.e_cast;
      for (i = 1; i < tkn; i++)
        cast |= (bit << SANEvalCastling (tkv[i]));
      SANPutCAST (cast);
    };

  return;
}

/*--> SANDcSVEP: do command: set value: en passant target square */
nonstatic
void
SANDcSVEP (void)
{
  if (!SANCheckSquare (tkv[1]))
    SANBadParmForm (1);
  else
    SANPutEPSQ (SANEvalSquare (tkv[1]));

  return;
}

/*--> SANDcSVFE: do command: set value: Forsyth-Edwards notation */
nonstatic
void
SANDcSVFE (void)
{
  charptrT s;
  siT i, length;

  length = 0;
  for (i = 1; i < 7; i++)
    length += (strlen (tkv[i]) + 1);
  s = SANMemGrab (length);
  (void) sprintf (s, "%s %s %s %s %s %s",
                  tkv[1], tkv[2], tkv[3], tkv[4], tkv[5], tkv[6]);
  if (!SANFENSet (s))
    SANDspError ("Can't set position; faulty FEN input");
  SANMemFree (s);

  return;
}

/*--> SANDcSVFN: do command: set value: fullmove number */
nonstatic
void
SANDcSVFN (void)
{
  siT n;

  if (!SANCheckShortInteger (tkv[1]))
    SANBadParmForm (1);
  else
    {
      n = SANEvalShortInteger (tkv[1]);
      if ((n < 1) || (n >= fmpL))
        SANBadParmValue (1);
      else
        SANPutFMVN (n);
    };

  return;
}

/*--> SANDcSVHC: do command: set value: halfmove clock */
nonstatic
void
SANDcSVHC (void)
{
  siT n;

  if (!SANCheckShortInteger (tkv[1]))
    SANBadParmForm (1);
  else
    {
      n = SANEvalShortInteger (tkv[1]);
      if ((n < 0) || (n >= hmpL))
        SANBadParmValue (1);
      else
        SANPutHMVC (n);
    };

  return;
}

/*--> SANDcSVOP: do command: set value: option */
nonstatic
void
SANDcSVOP (void)
{
  siT flag, i;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (!SANCheckOption (tkv[i]))
      flag = 0;
    else
      i++;

  if (!flag)
    SANBadParmForm (i);
  else
    for (i = 1; i < tkn; i++)
      optnv[SANEvalOption (tkv[i])] = 1;

  return;
}

/*--> SANDcSVPL: do command: set value: playing level */
nonstatic
void
SANDcSVPL (void)
{
  siT depth;

  if (!SANCheckShortInteger (tkv[1]))
    SANBadParmForm (1);
  else
    {
      depth = SANEvalShortInteger (tkv[1]);
      if ((depth < 0) || (depth >= aL))
        SANBadParmValue (1);
      else
        {
          level = depth;
          SANSSS (sep_config);
        };
    };

  return;
}

/*--> SANDcSVRT: do command: set value: average response time */
nonstatic
void
SANDcSVRT (void)
{
  liT value;

  if (!SANCheckLongInteger (tkv[1]))
    SANBadParmForm (1);
  else
    {
      value = SANEvalLongInteger (tkv[1]);
      if (value < 0)
        SANBadParmValue (1);
      else
        {
          artsec = value;
          SANSSS (sep_config);
        };
    };

  return;
}

/*--> SANDcSVSQ: do command: set value: square */
nonstatic
void
SANDcSVSQ (void)
{
  siT flag, i;
  rankT rank;
  fileT file;
  cT c;
  pT p;
  sqT sq;
  cpT cp;

  flag = 1;
  i = 1;
  while (flag && (i < tkn))
    if (strlen (tkv[i]) != 4)
      flag = 0;
    else if (!SANCheckColor (tkv[i][0]) || !SANCheckPiece (tkv[i][1]) ||
             !SANCheckFile (tkv[i][2]) || !SANCheckRank (tkv[i][3]))
      flag = 0;
    else
      i++;

  if (!flag)
    SANBadParmForm (i);
  else
    for (i = 1; i < tkn; i++)
      {
        c = SANEvalColor (tkv[i][0]);
        p = SANEvalPiece (tkv[i][1]);
        cp = cv_cp_cpv[c][p];
        file = SANEvalFile (tkv[i][2]);
        rank = SANEvalRank (tkv[i][3]);
        sq = map_sq_rank_file (rank, file);
        SANPutSq (sq, cp);
      };

  return;
}

/*--> SANDcSVSS: do command: set value: search strategies */
nonstatic
void
SANDcSVSS (void)
{
  if (!SANCheckStrategy (tkv[1]))
    SANBadParmForm (1);
  else if (!SANCheckStrategy (tkv[2]))
    SANBadParmForm (2);
  else
    {
      ssv[c_w] = SANEvalStrategy (tkv[1]);
      ssv[c_b] = SANEvalStrategy (tkv[2]);
    };

  return;
}

/*--> SANDcSVTF: do command: set value: tag field */
nonstatic
void
SANDcSVTF (void)
{
  tagptrT tagptr;

  if ((tagptr = SANTagLocate (tkv[1])) == NULL)
    SANBadParmForm (1);
  else if (tkn == 2)
    SANTagUpdate (tagptr, "");
  else
    SANTagUpdate (tagptr, tkv[2]);

  return;
}

/*--> SANDcTEST: do command: developer test */
nonstatic
void
SANDcTEST (void)
{
  SANDspNote ("no test code present");

  return;
}

/*--> SANDcTFGC: do command: translate file: games to code (PGC) */
nonstatic
void
SANDcTFGC (void)
{
  charptrT fn0, fn1;
  siT n;

  fn0 = tkv[1];
  fn1 = tkv[2];

  n = 0;
  SANRGSetGRTM (grtm_pgc);
  if (!SANRGMultiple (fn0, fn1, &n))
    SANDspError ("Can't translate games to PGC");
  else if (optnv[optn_verb])
    SANDspStrSINL ("Game translation count: ", n);

  return;
}

/*--> SANDcTFGE: do command: translate file: games to EPD */
nonstatic
void
SANDcTFGE (void)
{
  charptrT fn0, fn1;
  siT n;

  fn0 = tkv[1];
  fn1 = tkv[2];

  n = 0;
  SANRGSetGRTM (grtm_epd);
  if (!SANRGMultiple (fn0, fn1, &n))
    SANDspError ("Can't translate games to EPD");
  else if (optnv[optn_verb])
    SANDspStrSINL ("Game translation count: ", n);

  return;
}

/*--> SANDcTFGG: do command: translate file: games to games (PGN) */
nonstatic
void
SANDcTFGG (void)
{
  charptrT fn0, fn1;
  siT n;

  fn0 = tkv[1];
  fn1 = tkv[2];

  n = 0;
  SANRGSetGRTM (grtm_pgn);
  if (!SANRGMultiple (fn0, fn1, &n))
    SANDspError ("Can't translate games to PGN");
  else if (optnv[optn_verb])
    SANDspStrSINL ("Game translation count: ", n);

  return;
}

/*--> SANDcTFGV: do command: translate file: games to variations */
nonstatic
void
SANDcTFGV (void)
{
  charptrT fn0, fn1;
  siT n;

  fn0 = tkv[1];
  fn1 = tkv[2];

  n = 0;
  SANRGSetGRTM (grtm_var);
  if (!SANRGMultiple (fn0, fn1, &n))
    SANDspError ("Can't translate games to variations");
  else if (optnv[optn_verb])
    SANDspStrSINL ("Game translation count: ", n);

  return;
}

/*<<< sandci.c: EOF */
