/****************************************************************************************************************
 *
 *  Copyright (c) 1992 by Antoine Dumesnil de Maricourt. All rights reserved.
 *
 *  This program is distributed in the hope that it will be useful.
 *  Use and copying of this software and preparation of derivative works
 *  based upon this software are permitted, so long as the following
 *  conditions are met:
 *       o credit to the authors is acknowledged following current
 *         academic behaviour
 *       o no fees or compensation are charged for use, copies, or
 *         access to this software
 *       o this copyright notice is included intact.
 *  This software is made available AS IS, and no warranty is made about 
 *  the software or its performance. 
 * 
 *  Bug descriptions, use reports, comments or suggestions are welcome.
 *  Send them to    dumesnil@etca.fr   or to:
 *       
 *       Antoine de Maricourt
 *       ETCA CREA-SP
 *       16 bis, avenue Prieur de la Cote d'Or
 *       94114 Arcueil Cedex
 *       France
 */

#include <stdio.h>
#include <malloc.h>
#include <ctype.h>

#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>

#include <X11/Xaw/Form.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>

#include "xgoban.h"
#include "icon.bm"

Widget      w_toplevel;
Widget      w_form;
Widget      w_goban;
Widget      w_menu            = NULL;
Widget      c_toplevel;
Widget      c_comment;
Widget      w_second_toplevel = NULL;
Widget      w_second_goban    = NULL;

SG_NodePtr  tree          = NULL;
SG_NodePtr  current_node  = NULL;
SG_NodePtr  mail_node     = NULL;

Mode        current_mode  = EditMode;

Player      black_player  = Human;
Player      white_player  = Human;
int         handicap      = 0;
int         board_size    = 19;
int         second_player = 0;

Boolean     edit          = False;
Boolean     modified      = False;
Boolean     autonum;
Boolean     strict;
Boolean     short_print   = False;
int         beep;

String      file = NULL;

char        file_name[512];
char        mail_file_name[512];
char       *path;

/*******************************************************************************************************
 */

typedef struct {
  int        handicap;
  int        size;
  int        stipple;
  String     path;
  String     mail;
  int        beep;
  Boolean    help;
  Boolean    autonum;
  Boolean    strict;
  Boolean    short_print;
  String     black;
  String     white;
  Dimension  point_size;
  String     white_dsp;
  String     black_dsp;
} AppData, *AppDataPtr;

static XtResource resources[] = {
  { "blackDisplay", XtCString   , XtRString   , sizeof (String)   , XtOffset (AppDataPtr, black_dsp)  , XtRString    , (caddr_t) NULL , },
  { "whiteDisplay", XtCString   , XtRString   , sizeof (String)   , XtOffset (AppDataPtr, white_dsp)  , XtRString    , (caddr_t) NULL , },
  { "path"        , XtCString   , XtRString   , sizeof (String)   , XtOffset (AppDataPtr, path)       , XtRString    , (caddr_t) "."  , },
  { "handicap"    , "Handicap"  , XtRInt      , sizeof (int)      , XtOffset (AppDataPtr, handicap)   , XtRImmediate , (caddr_t) 0    , },
  { "size"        , "Size"      , XtRInt      , sizeof (int)      , XtOffset (AppDataPtr, size)       , XtRImmediate , (caddr_t) 19   , },
  { "stipple"     , "Stipple"   , XtRInt      , sizeof (int)      , XtOffset (AppDataPtr, stipple)    , XtRImmediate , (caddr_t) 0    , },
  { "beep"        , "Beep"      , XtRInt      , sizeof (int)      , XtOffset (AppDataPtr, beep)       , XtRImmediate , (caddr_t) 0    , },
  { "short"       , XtCBoolean  , XtRBoolean  , sizeof (Boolean)  , XtOffset (AppDataPtr, short_print), XtRImmediate , (caddr_t) False, },
  { "mail"        , XtCString   , XtRString   , sizeof (String)   , XtOffset (AppDataPtr, mail)       , XtRString    , (caddr_t) NULL , },
  { "autonum"     , XtCBoolean  , XtRBoolean  , sizeof (Boolean)  , XtOffset (AppDataPtr, autonum)    , XtRImmediate , (caddr_t) True , },
  { "versatile"   , XtCBoolean  , XtRBoolean  , sizeof (Boolean)  , XtOffset (AppDataPtr, strict)     , XtRImmediate , (caddr_t) True , },
  { "black"       , XtCString   , XtRString   , sizeof (String)   , XtOffset (AppDataPtr, black)      , XtRImmediate , (caddr_t) NULL , },
  { "white"       , XtCString   , XtRString   , sizeof (String)   , XtOffset (AppDataPtr, white)      , XtRImmediate , (caddr_t) NULL , },
  { "help"        , XtCBoolean  , XtRBoolean  , sizeof (Boolean)  , XtOffset (AppDataPtr, help)       , XtRImmediate , (caddr_t) False, },
  { "pointSize"   , "Size"      , XtRDimension, sizeof (Dimension), XtOffset (AppDataPtr, point_size) , XtRImmediate , (caddr_t) 26   , },
};

static XrmOptionDescRec options[] = {
  { "-help"           , ".help"           , XrmoptionNoArg  , "True"  , },
  { "-size"           , ".size"           , XrmoptionSepArg , NULL    , },
  { "-handicap"       , ".handicap"       , XrmoptionSepArg , NULL    , },
  { "-path"           , ".path"           , XrmoptionSepArg , NULL    , },
  { "-pointSize"      , ".pointSize"      , XrmoptionSepArg , NULL    , },
  { "-silent"         , ".beep"           , XrmoptionNoArg  , "-101"  , },
  { "-beep"           , ".beep"           , XrmoptionSepArg , NULL    , },
  { "-nonum"          , ".autonum"        , XrmoptionNoArg  , "False" , },
  { "-versatile"      , ".versatile"      , XrmoptionNoArg  , "False" , },
  { "-black"          , ".black"          , XrmoptionSepArg , NULL    , },
  { "-white"          , ".white"          , XrmoptionSepArg , NULL    , },
  { "-stipple1"       , ".stipple"        , XrmoptionNoArg  , "1"     , },
  { "-stipple2"       , ".stipple"        , XrmoptionNoArg  , "2"     , },
  { "-stipple3"       , ".stipple"        , XrmoptionNoArg  , "3"     , },


  { "-m"              , ".mail"           , XrmoptionSepArg , NULL    , },
  { "-s"              , ".short"          , XrmoptionNoArg  , "True"  , },
  { "-mail"           , ".mail"           , XrmoptionSepArg , NULL    , },
  { "-short"          , ".short"          , XrmoptionNoArg  , "True"  , },
  { "-blackDisplay"   , ".blackDisplay"   , XrmoptionSepArg , NULL    , },
  { "-whiteDisplay"   , ".whiteDisplay"   , XrmoptionSepArg , NULL    , },
};

static AppData  app_data;

static char *stars[18] = {
  "",				/*  2  */  
  "",				/*  3  */  
  "",				/*  4  */  
  "",				/*  5  */  
  "",				/*  6  */  
  "",				/*  7  */  
  "cffcffcc",			/*  8  */    
  "cggcggccee",			/*  9  */  
  "hchhchcc",			/* 10  */  
  "ciiciiccffcfiffcfi",		/* 11  */  
  "cjjcjjcc",			/* 12  */  
  "ckkckkccggcgkggcgk",		/* 13  */  
  "dkkdkkdd",			/* 14  */  
  "dlldllddhhdhlhhdhl",		/* 15  */  
  "dmmdmmdd",			/* 16  */  
  "dnndnnddiidiniidin",		/* 17  */  
  "doodoodd",			/* 18  */  
  "dppdppddjjdjpjjdjp",		/* 19  */  
};

char translations_table[] =
  "#override                                                                            \
   Ctrl Shift <Key> P        : makeVariationPass()                                    \n\
   Shift <Key> A             : selectVariation(A)                                     \n\
   Shift <Key> B             : selectVariation(B)                                     \n\
   Shift <Key> C             : selectVariation(C)                                     \n\
   Shift <Key> D             : selectVariation(D)                                     \n\
   Shift <Key> E             : selectVariation(E)                                     \n\
   Shift <Key> F             : selectVariation(F)                                     \n\
   Shift <Key> G             : selectVariation(G)                                     \n\
   Shift <Key> H             : selectVariation(H)                                     \n\
   Shift <Key> I             : selectVariation(I)                                     \n\
   Shift <Key> J             : selectVariation(J)                                     \n\
   Shift <Key> K             : selectVariation(K)                                     \n\
   Shift <Key> L             : selectVariation(L)                                     \n\
   Shift <Key> M             : selectVariation(M)                                     \n\
   Shift <Key> N             : selectVariation(N)                                     \n\
   Shift <Key> O             : selectVariation(O)                                     \n\
   Shift <Key> P             : selectVariation(P)                                     \n\
   Shift <Key> Q             : selectVariation(Q)                                     \n\
   Shift <Key> R             : selectVariation(R)                                     \n\
   Shift <Key> S             : selectVariation(S)                                     \n\
   Shift <Key> T             : selectVariation(T)                                     \n\
   Shift <Key> U             : selectVariation(U)                                     \n\
   Shift <Key> V             : selectVariation(V)                                     \n\
   Shift <Key> W             : selectVariation(W)                                     \n\
   Shift <Key> X             : selectVariation(X)                                     \n\
   Shift <Key> Y             : selectVariation(Y)                                     \n\
   Shift <Key> Z             : selectVariation(Z)                                     \n\
   Shift <Key> }             : nextComment()                                          \n\
   Shift <Key> {             : previousComment()                                      \n\
   <Key> a                   : setMode(Diagram)                                       \n\
   <Key> b                   : setPlayer(Black)                                       \n\
   <Key> e                   : dialog(Edit)                                           \n\
   <Key> p                   : pass()                                                 \n\
   <Key> i                   : eventInfo()                                            \n\
   <Key> v                   : setMode(View)                                          \n\
   <Key> w                   : setPlayer(White)                                       \n\
   <Key> z                   : setMode(Size)                                          \n\
   <Key> Escape              : setMode(Edit)                                          \n\
   <Key> l                   : dialog(Load)                                           \n\
   <Key> n                   : dialog(NodeName)                                       \n\
   <Key> q                   : exit()                                                 \n\
   <Key> s                   : dialog(Save)                                           \n\
   <Key> ]                   : nextVariationBranch()                                  \n\
   <Key> [                   : previousVariationBranch()                              \n\
   <Key> <                   : previousMove()                                         \n\
   <Key> >                   : nextMove()                                             \n\
   <Key> ?                   : dialog(Help)                                           \n\
   <Key> h                   : dialog(Help)                                           \n\
   Ctrl Shift <Btn1Down>     : makeVariation()                                        \n\
   Ctrl Shift <Btn2Down>     : makeVariationDiagram()                                 \n\
   Shift <Btn1Down>          : makeMove()                                             \n\
   Shift <Btn3Down>          : deleteMove()                                           \n\
   Ctrl <Btn1Down>           : letter()                                               \n\
   Ctrl <Btn2Down>           : mark()                                                 \n\
   Ctrl <Btn3Down>           : deleteMark()                                           \n\
   <Btn1Down>                : nextMove() add(Black) drag(Start)                      \n\
   <Btn2Down>                : add(White) selectDiagram()                             \n\
   <Btn3Down>                : previousMove() add(Empty)                              \n\
   <Btn1Motion>              : drag()                                                 \n\
   <Btn1Up>                  : drag(Stop)                                             \n\
"; 

/*******************************************************************************************************
 */

extern void SelectDiagram           ();
extern void Dialog                  ();
extern void NextMove                ();
extern void PreviousMove            ();
extern void SelectVariation         ();
extern void NextVariationBranch     ();
extern void PreviousVariationBranch ();
extern void NextComment             ();
extern void PreviousComment         ();
extern void Exit                    ();
extern void Help                    ();
extern void PopdownHelp             ();
extern void MakeVariationDiagram    ();
extern void SetPlayer               ();
extern void Add                     ();
extern void SetMode                 ();
extern void MakeMove                ();
extern void Pass                    ();
extern void DeleteMove              ();
extern void DeleteMark              ();
extern void MakeVariation           ();
extern void MakeVariationPass       ();
extern void Drag                    ();
extern void Letter                  ();
extern void Mark                    ();
extern void EventInfo               ();

XtActionsRec actions[] = {
  { "selectDiagram"           , SelectDiagram           , },
  { "dialog"                  , Dialog                  , },
  { "nextMove"                , NextMove                , },
  { "previousMove"            , PreviousMove            , },
  { "selectVariation"         , SelectVariation         , },
  { "nextVariationBranch"     , NextVariationBranch     , },
  { "previousVariationBranch" , PreviousVariationBranch , },
  { "nextComment"             , NextComment             , },
  { "previousComment"         , PreviousComment         , },
  { "exit"                    , Exit                    , },
  { "makeVariationDiagram"    , MakeVariationDiagram    , },
  { "setPlayer"               , SetPlayer               , },
  { "add"                     , Add                     , },
  { "selectDiagram"           , SelectDiagram           , },
  { "setMode"                 , SetMode                 , },
  { "makeMove"                , MakeMove                , },
  { "deleteMove"              , DeleteMove              , },
  { "deleteMark"              , DeleteMark              , },
  { "pass"                    , Pass                    , },
  { "makeVariation"           , MakeVariation           , },
  { "makeVariationPass"       , MakeVariationPass       , },
  { "drag"                    , Drag                    , },
  { "letter"                  , Letter                  , },
  { "mark"                    , Mark                    , },
  { "eventInfo"               , EventInfo               , },
}; 

extern void exit ();

#define stipple1_width  2
#define stipple1_height 2

static char stipple1_bits[] = {
   0x01, 0x02};

#define stipple2_width  4
#define stipple2_height 4

static char stipple2_bits[] = {
   0x05, 0x00, 0x0a, 0x00};

#define stipple3_width  4
#define stipple3_height 4

static char stipple3_bits[] = {
   0x01, 0x00, 0x00, 0x00};


void main (argc, argv)
int    argc;
char **argv;
{
  XtAppContext   app_context;
  Display       *display;
  Display       *second_display;
  Drawable       window;
  String         title;
  String         icon_title;
  Pixmap         icon_pixmap;
  Arg            args[16];
  int            xtargc;
 
  w_toplevel = XtAppInitialize (&app_context, ApplicationName,  options, XtNumber (options), 
				&argc, argv, NULL, NULL, 0);

  XtGetApplicationResources (w_toplevel, &app_data, resources, XtNumber (resources), NULL, 0);

  if (argc == 2 && argv[1][0] != '-')
    file = argv[1];

  else if (argc > 1)
    app_data.help = True;

  /*
   *    help option 
   */
   
  if (app_data.help == True) {
    (void) fprintf (stderr, "%s", UsageString);
    (void) exit (1);
  }

  /*
   *    Various options 
   */

  if (app_data.beep > 100)
    app_data.beep = 0;

  path        = app_data.path;
  beep        = app_data.beep;
  autonum     = app_data.autonum;
  strict      = app_data.strict;
  short_print = app_data.short_print;

  if (strict == False) autonum = False;

  /*
   *    Mail option
   */

  if (app_data.mail != NULL) {

    if (file == NULL) {
      (void) fprintf (stderr, "XGoban : Mail mode : no input file specified\n");
      (void) exit (1);
    }

    strcpy (mail_file_name, app_data.mail);

    current_mode = MailMode;
    edit         = True;
  }

  /*
   *    Widget creation
   */

  display   = XtDisplay (w_toplevel);
  window    = RootWindowOfScreen (XtScreen (w_toplevel));

  icon_pixmap = XCreateBitmapFromData (display, window, icon_bits, icon_width, icon_height);

  xtargc    = 0;
  XtSetArg (args[xtargc], XtNiconPixmap       , (XtArgVal) icon_pixmap         ); xtargc++;
  XtSetArg (args[xtargc], XtNtitle            , (XtArgVal) ApplicationName     ); xtargc++;
  XtSetArg (args[xtargc], XtNiconName         , (XtArgVal) "Goban"             ); xtargc++;
   
  XtSetValues (w_toplevel, args, xtargc);

  xtargc    = 0;
  XtSetArg (args[xtargc], XtNtranslations     , (XtArgVal) XtParseTranslationTable (translations_table)); xtargc++;
  XtSetArg (args[xtargc], XtNpointSize        , (XtArgVal) app_data.point_size ); xtargc++;
  XtSetArg (args[xtargc], XtNautoRedisplay    , (XtArgVal) False               ); xtargc++;

  switch (app_data.stipple) {
  case 1 :
    XtSetArg (args[xtargc], XtNbackgroundPixmap , 
	      XCreatePixmapFromBitmapData (display, window, (char *) stipple1_bits, 
					   stipple1_width, stipple1_height,
					   BlackPixel (display, DefaultScreen (display)),
					   WhitePixel (display, DefaultScreen (display)),
					   DefaultDepthOfScreen (XtScreen (w_toplevel))));
    xtargc++;
    break;
  case 2 :
    XtSetArg (args[xtargc], XtNbackgroundPixmap , 
	      XCreatePixmapFromBitmapData (display, window, (char *) stipple2_bits, 
					   stipple2_width, stipple2_height,
					   BlackPixel (display, DefaultScreen (display)),
					   WhitePixel (display, DefaultScreen (display)),
					   DefaultDepthOfScreen (XtScreen (w_toplevel))));
    xtargc++;
    break;
  case 3 :
    XtSetArg (args[xtargc], XtNbackgroundPixmap , 
	      XCreatePixmapFromBitmapData (display, window, (char *) stipple3_bits, 
					   stipple3_width, stipple3_height,
					   BlackPixel (display, DefaultScreen (display)),
					   WhitePixel (display, DefaultScreen (display)),
					   DefaultDepthOfScreen (XtScreen (w_toplevel))));
    xtargc++;
    break;
  }

  w_goban   = XtCreateManagedWidget ("goban"      , gobanWidgetClass     , w_toplevel  , args, xtargc);

  xtargc    = 0;
  XtSetArg (args[xtargc], XtNiconPixmap       , (XtArgVal) icon_pixmap         ); xtargc++;
  XtSetArg (args[xtargc], XtNtitle            , (XtArgVal) "XGoban : comment"  ); xtargc++;
  XtSetArg (args[xtargc], XtNiconName         , (XtArgVal) "Comment"           ); xtargc++;

  c_toplevel = XtCreatePopupShell ("comment", applicationShellWidgetClass, w_toplevel, args, xtargc);

  xtargc    = 0;
  XtSetArg (args[xtargc], XtNwidth            , (XtArgVal) 540                 ); xtargc++;
  XtSetArg (args[xtargc], XtNheight           , (XtArgVal) 200                 ); xtargc++;
  XtSetArg (args[xtargc], XtNscrollVertical   , (XtArgVal) XawtextScrollAlways ); xtargc++;
  XtSetArg (args[xtargc], XtNwrap             , (XtArgVal) XawtextWrapWord     ); xtargc++;
  XtSetArg (args[xtargc], XtNeditType         , (XtArgVal) XawtextRead         ); xtargc++;
  XtSetArg (args[xtargc], XtNdisplayCaret     , (XtArgVal) False               ); xtargc++;

  c_comment = XtCreateManagedWidget ("commentText", asciiTextWidgetClass , c_toplevel   , args, xtargc);

  makeDialogWindow  (w_toplevel, app_context);
  makeEventWindow   (w_toplevel, app_context);

  XtAppAddActions (app_context, actions, XtNumber(actions));
  XawSimpleMenuAddGlobalActions (app_context); 

  XtRegisterGrabAction (SelectDiagram, True, (ButtonPressMask | ButtonReleaseMask), GrabModeAsync, GrabModeAsync);
  XtRealizeWidget (w_toplevel);

  /*
   *   Second display
   */

  if (current_mode == EditMode) {
    if (app_data.white_dsp != NULL) {
      second_display = XtOpenDisplay (app_context, app_data.white_dsp, NULL, ApplicationName, 
				      options, XtNumber (options), &argc, argv);
      
      w_second_toplevel  = XtAppCreateShell (argv[0], ApplicationName, applicationShellWidgetClass, second_display, NULL, 0);
      second_player      = SG_WhiteStone;
    }
    
    else if (app_data.black_dsp != NULL) {
      second_display = XtOpenDisplay (app_context, app_data.black_dsp, NULL, ApplicationName,
				      options, XtNumber (options), &argc, argv);
      
      w_second_toplevel  = XtAppCreateShell (argv[0], ApplicationName, applicationShellWidgetClass, second_display, NULL, 0);
      second_player      = SG_BlackStone;
    }
    
    if (w_second_toplevel != NULL) {
      
      window     = RootWindowOfScreen (XtScreen (w_second_toplevel));
      
      title      = second_player == SG_BlackStone ? "XGoban : Black" : "XGoban : White"; 
      icon_title = second_player == SG_BlackStone ? "Black" : "White"; 
      
      xtargc    = 0;
      XtSetArg (args[xtargc], XtNiconPixmap, icon_pixmap ); xtargc++;
      XtSetArg (args[xtargc], XtNtitle     , title       ); xtargc++;
      XtSetArg (args[xtargc], XtNiconName  , icon_title  ); xtargc++;
      
      XtSetValues (w_second_toplevel, args, xtargc);
      
      title      = second_player == SG_BlackStone ? "XGoban : White" : "XGoban : Black"; 
      icon_title = second_player == SG_BlackStone ? "White" : "Black"; 
      
      xtargc    = 0;
      XtSetArg (args[xtargc], XtNtitle     , title       ); xtargc++;
      XtSetArg (args[xtargc], XtNiconName  , icon_title  ); xtargc++;
      
      XtSetValues (w_toplevel, args, xtargc);
      
      xtargc    = 0;
      XtSetArg (args[xtargc], XtNtranslations     , (XtArgVal) XtParseTranslationTable (translations_table)); xtargc++;
      XtSetArg (args[xtargc], XtNpointSize        , (XtArgVal) app_data.point_size ); xtargc++;
      XtSetArg (args[xtargc], XtNautoRedisplay    , (XtArgVal) False               ); xtargc++;
      
      w_second_goban   = XtCreateManagedWidget ("goban"      , gobanWidgetClass     , w_second_toplevel, args, xtargc);
      
      XtRealizeWidget (w_second_toplevel);
      
      current_mode = PlayMode;
    }
  }

  /*
   *   Black and White options : play a game
   */
    
  if (current_mode == EditMode) {
    if (app_data.black != NULL) {
      current_mode = PlayMode;
      edit         = True;
      
      if (strcmp (app_data.black, "wally") == 0)
	black_player = Wally;
      else if (strcmp (app_data.black, "gnugo") == 0)
	black_player = Gnugo;
    }
    
    if (app_data.white != NULL) {
      current_mode = PlayMode;
      edit         = True;
      
      if (strcmp (app_data.white, "wally") == 0)
	PopupDialog (w_toplevel, NULL, WallyWhitePlayWarning);
      else if (strcmp (app_data.white, "gnugo") == 0)
	white_player = Gnugo;
    }
  }

  /*
   *    File option 
   */

  file_name[0] = '\0';

  if (file != NULL) {
    (void) strcpy (file_name, file);

    if (current_mode != PlayMode)
      if (LoadFile (NULL, NULL, file) == True) {
	app_data.handicap = 0;
	app_data.size     = 19;
      }
    
      else {
	(void) fprintf (stderr, "XGoban : can't open file : %s\n", file);
	(void) exit (1);
      }
  }

  /*
   *   Create first node
   */

  if (tree == NULL) {
    tree         = SG_MakeNode (NULL, SG_Event);
    current_node = tree;

    if (current_mode != PlayMode) Edit (True);
  }

  if (current_mode == PlayMode) {
    switch (black_player) {
    case Gnugo : SG_MakeProperty (tree, SG_PlayerBlack, (long) "gnugo"); break;
    case Wally : SG_MakeProperty (tree, SG_PlayerBlack, (long) "wally"); break;
    case Human : 
      if (app_data.black != NULL) 
	SG_MakeProperty (tree, SG_PlayerBlack, (long) app_data.black); 
      break;
    }

    switch (white_player) {
    case Gnugo : SG_MakeProperty (tree, SG_PlayerWhite, (long) "gnugo"); break;
    case Wally : SG_MakeProperty (tree, SG_PlayerWhite, (long) "wally"); break;
    case Human : 
      if (app_data.white != NULL) 
	SG_MakeProperty (tree, SG_PlayerWhite, (long) app_data.white); 
      break;
    }
  }

  /*
   *    Size option 
   */

  if (app_data.size > 1 && app_data.size < 19) {
    if (black_player == Wally && app_data.size != 9 && app_data.size != 13 && app_data.size != 19) {
      PopupDialog (w_toplevel, NULL, WallyBadSizeWarning);
      app_data.size = 9;
    }

    SG_MakeProperty (current_node, SG_SiZe, (long) app_data.size);

    modified = True;
    if (current_mode != PlayMode) Edit (True);
  }

  else 
    app_data.size = 19;

  board_size = app_data.size;

  /*
   *    Handicap option 
   */

  current_node->player = SG_BlackStone;

  if (app_data.handicap > 1) {
    int            x;
    int            y;
    int            h;
    char          *ptr = stars[app_data.size - 2];
    unsigned char *setup;

    if (black_player == Wally && app_data.handicap != 9) {
      PopupDialog (w_toplevel, NULL, WallyBadHandicapWarning);
      app_data.handicap = 9;
    }

    if (*ptr == '\0') {
      PopupDialog (w_toplevel, NULL, BadHandicapWarning);
      app_data.handicap = 0;
    }

    else {
      setup = current_node->setup = (unsigned char *) malloc ((unsigned) 2 * app_data.handicap + 1);

      for (h = 0; h < app_data.handicap && *ptr != '\0'; h++) {
	x = *ptr++;
	y = *ptr++;
	
	if (h == 4 && (app_data.handicap == 6 || app_data.handicap == 8)) {
	  x = *ptr++;
	  y = *ptr++;
	}

	*setup++ = SG_SETB | (x - 'a' + 1);
	*setup++ = SG_SETB | (y - 'a' + 1);
      }
      
      if (h != app_data.handicap) {
	PopupDialog (w_toplevel, NULL, RemainingStonesWarning);
	app_data.handicap -= h;
      }
	
      *setup++ = SG_EOS;
      current_node->player = SG_WhiteStone;
      
      modified = True;
      if (current_mode != PlayMode) Edit (True);
    }
  }

  else 
    app_data.handicap = 0;

  handicap = app_data.handicap;

  /*
   *    Play first node and go... 
   */

  GbClearBoard (w_goban);

  switch (current_mode) {
  case PlayMode :
    startGame (app_context);
    break;

  case EditMode :
    XtPopup (c_toplevel, XtGrabNone);
    break;

  case MailMode :
    XtPopup (c_toplevel, XtGrabNone);

    while (current_node->down != NULL) {
      Play            (current_node);
      ShowProperty    (current_node);
      HideTmpProperty (current_node);

      current_node = current_node->down;
    }

    mail_node = current_node;
    break;

  default :
    break;
  }

  Play           (current_node);
  ShowProperty   (current_node);
  RedisplayBoard ();

  XtAppMainLoop    (app_context);

  /* NOTREACHED */
}

/*******************************************************************************************************
 */
