#include <stdlib.h>
#include <tk.h>
/* The following variable is a special hack that allows applications
 * to be linked using the procedure "main" from the Tk library.  The
 * variable generates a reference to "main", which causes main to
 * be brought in from the library (and all of Tk and Tcl with it).
 */
extern int main();
int *tclDummyMainPtr = (int *) main;

#define KARTEN_WERT(rang, wert) \
  switch (rang) {               \
    case 'a': wert = 1;  break; \
    case '2': wert = 2;  break; \
    case '3': wert = 3;  break; \
    case '4': wert = 4;  break; \
    case '5': wert = 5;  break; \
    case '6': wert = 6;  break; \
    case '7': wert = 7;  break; \
    case '8': wert = 8;  break; \
    case '9': wert = 9;  break; \
    case '0': wert = 10; break; \
    case 'b': wert = 11; break; \
    case 'd': wert = 12; break; \
    case 'k': wert = 13; break; \
    default:  return TCL_ERROR; \
  }
int KartenWertCmd (ClientData clientData, Tcl_Interp *interp,
              int argc, char *argv[]) {
  int wert;
  if (argc != 2) {
    interp->result = "wrong # args";
    return TCL_ERROR;
  }
  KARTEN_WERT (*(argv[1]), wert);
  sprintf (interp->result, "%d", wert);
  return TCL_OK;
}
int AufsteigendCmd (ClientData clientData, Tcl_Interp *interp,
              int argc, char *argv[]) {
  int   wertU, wertO, erstWert, zyklisch;
  char *aktuellErste;
  if (argc != 4) {
    interp->result = "wrong # args";
    return TCL_ERROR;
  }
  KARTEN_WERT (*(argv[2]), wertO);
  KARTEN_WERT (*(argv[1]), wertU);
  if (Tcl_GetBoolean (interp, argv[3], &zyklisch) != TCL_OK) {
    return TCL_ERROR;
  }
  if (!(aktuellErste = Tcl_GetVar2 (interp, "aktuellErste", 0,
                                   TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG))) {
    return TCL_ERROR;
  }
  KARTEN_WERT (*aktuellErste, erstWert);
  if (!zyklisch && erstWert == wertO) {
    interp->result = "0";
  } else {
    interp->result = (wertU + 1 - wertO) % 13 == 0 ? "1" : "0";
  }
  return TCL_OK;
}
int UnechtCmd (ClientData clientData, Tcl_Interp *interp,
              int argc, char *argv[]) {
  char farbeA,  farbeB;
  int  aIstRot, bIstRot;

  if (argc != 3) {
    interp->result = "wrong # args";
    return TCL_ERROR;
  }
  farbeA = argv[1][1];
  farbeB = argv[2][1];
  aIstRot = farbeA == 'c' || farbeA == 'h';
  bIstRot = farbeB == 'c' || farbeB == 'h';
  interp->result = aIstRot != bIstRot ? "1" : "0";
  return TCL_OK;
}
int EchtCmd (ClientData clientData, Tcl_Interp *interp,
             int argc, char *argv[]) {
  char farbeA,  farbeB;
  int  aIstRot, bIstRot;

  if (argc != 3) {
    interp->result = "wrong # args";
    return TCL_ERROR;
  }
  interp->result = argv[1][1] == argv[2][1] ? "1" : "0";
  return TCL_OK;
}
/* The largest number rand will return (same as INT_MAX).  */
#ifndef RAND_MAX
#define RAND_MAX        2147483647
#endif
int UnifRandCmd (ClientData clientData, Tcl_Interp *interp,
              int argc, char *argv[]) {
  int my_range, i, j;

  if (argc != 2) {
    interp->result = "wrong # args";
    return TCL_ERROR;
  }
  if (Tcl_GetInt (interp, argv[1], &my_range) != TCL_OK) {
    return TCL_ERROR;
  }

  /* The following four lines are in the spirit of the rand-man page. */
  i  = RAND_MAX/my_range;
  i *= my_range;
  while ((j = rand ()) >= i);
  sprintf (interp->result, "%d", j%my_range);

  return TCL_OK;
}
int InitrCmd (ClientData clientData, Tcl_Interp *interp,
              int argc, char *argv[]) {
  int seed;

  if (argc != 2) {
    interp->result = "wrong # args";
    return TCL_ERROR;
  }
  if (Tcl_GetInt (interp, argv[1], &seed) != TCL_OK) {
    return TCL_ERROR;
  }

  /* Initialization of the rand function. */
  srand (seed);
  return TCL_OK;
}

int Tcl_AppInit (interp)
Tcl_Interp *interp; /* Interpreter for application. */
{
  Tk_Window main = Tk_MainWindow(interp);
  if (Tcl_Init(interp) == TCL_ERROR) {return TCL_ERROR;}
  if (Tk_Init(interp)  == TCL_ERROR) {return TCL_ERROR;}
  Tcl_CreateCommand(interp, "kartenWert", KartenWertCmd, (ClientData) main,
                    (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateCommand(interp, "aufsteigend", AufsteigendCmd, (ClientData) main,
                    (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateCommand(interp, "unecht", UnechtCmd, (ClientData) main,
                    (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateCommand(interp, "echt", EchtCmd, (ClientData) main,
                    (Tcl_CmdDeleteProc *)NULL);
  Tcl_CreateCommand (interp, "unifRand", UnifRandCmd,
                     (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
  Tcl_CreateCommand (interp, "initr", InitrCmd,
                     (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
  return TCL_OK;
}
