/****************************************************************************************************************
 *
 *  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 <ctype.h>

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

#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/AsciiText.h>

#include "xgoban.h"

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

static Widget   d_top;
static Widget   d_form;
static Widget   d_msg;
static Widget   d_text;
static Widget   d_confirm;
static Widget   d_cancel;

static Widget   a_top;
static Widget   a_form;
static Widget   a_msg;
static Widget   a_confirm;
static Widget   a_cancel;

static Widget   w_top;
static Widget   w_form;
static Widget   w_msg;
static Widget   w_confirm;

static Widget   h_top;
static Widget   h_text;

static int      dialog_mode  = -1;
static Widget   dialog_widget;

static XEvent   delay_event;

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

/* ARGSUSED */

void PopupDialog (w, event, mode)
Widget   w;
XEvent  *event;
int      mode;
{
  SG_PropertyPtr property;
  Widget         top;
  Widget         focus;
  Arg            arg;

  switch (mode) {

  case HelpDialog : 
    top   = h_top; 
    focus = NULL; 
    break;

  case ReallyQuitDialog :
    XtSetArg (arg, XtNlabel, (XtArgVal) ReallyQuitMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) QuitLabel    ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel  ); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;
  
  case ReallyDeleteDialog :

    delay_event = *event;
    
    XtSetArg (arg, XtNlabel, (XtArgVal) ReallyDeleteMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) DeleteLabel    ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel    ); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;
   
  case SaveBeforeQuitDialog :
  case SaveBeforeLoadDialog :
    XtSetArg (arg, XtNlabel, (XtArgVal) SaveFileBeforeMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) YesLabel         ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) NoLabel          ); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;
   
  case SaveAsAndLoadDialog :
  case SaveAsAndQuitDialog :
  case SaveAsDialog        :
    XtSetArg (arg, XtNstring , (XtArgVal) file_name   ); XtSetValues (d_text    , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) SaveFileMsg ); XtSetValues (d_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) SaveLabel   ); XtSetValues (d_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) CancelLabel ); XtSetValues (d_cancel  , &arg, 1);

    top   = d_top;
    focus = d_text;
    break;

  case NodeNameDialog      :
    property = SG_GetProperty (current_node, SG_nodeName);
    
    if (property != NULL && property->data.pvalue != NULL)
      { XtSetArg (arg, XtNstring , (XtArgVal) property->data.pvalue); XtSetValues (d_text    , &arg, 1); }
    else
      { XtSetArg (arg, XtNstring , (XtArgVal) ""                   ); XtSetValues (d_text    , &arg, 1); }

    XtSetArg (arg, XtNlabel  , (XtArgVal) NodeNameMsg ); XtSetValues (d_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) OkLabel     ); XtSetValues (d_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) CancelLabel ); XtSetValues (d_cancel  , &arg, 1);

    top   = d_top;
    focus = d_text;
    break;

  case LoadDialog :
    XtSetArg (arg, XtNstring , (XtArgVal) ""          ); XtSetValues (d_text    , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) LoadFileMsg ); XtSetValues (d_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) LoadLabel   ); XtSetValues (d_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel  , (XtArgVal) CancelLabel ); XtSetValues (d_cancel  , &arg, 1);

    top   = d_top;
    focus = d_text;
    break;

  case EditDialog :
    if (edit == True) return;

    delay_event = *event;
    
    XtSetArg (arg, XtNlabel, (XtArgVal) EditFileMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) EditLabel  ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;

  case StopGameDialog :
    delay_event = *event;

  case StopGameBeforeQuitDialog :
    
    XtSetArg (arg, XtNlabel, (XtArgVal) StopGameMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) StopLabel  ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;

  case ReplaceNodeDialog :
    delay_event = *event;

    XtSetArg (arg, XtNlabel, (XtArgVal) ReplaceNodeMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) ReplaceLabel  ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel   ); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;

  case MailConfirmMoveDialog :
    delay_event = *event;

    XtSetArg (arg, XtNlabel, (XtArgVal) MailConfirmMoveMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) ConfirmLabel      ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel       ); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;

  case MailNoMoveDialog :
    delay_event = *event;

    XtSetArg (arg, XtNlabel, (XtArgVal) MailNoMoveMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) QuitLabel    ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel  ); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;

  case RemoveStonesDialog :
    delay_event = *event;

    XtSetArg (arg, XtNlabel, (XtArgVal) RemoveStonesMsg); XtSetValues (a_msg     , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) RemoveLabel    ); XtSetValues (a_confirm , &arg, 1);
    XtSetArg (arg, XtNlabel, (XtArgVal) CancelLabel    ); XtSetValues (a_cancel  , &arg, 1);

    top   = a_top;
    focus = a_confirm;
    break;

  default :
    switch (mode) {
    case PlayerNodeErrorWarning  : XtSetArg (arg, XtNlabel, PlayerNodeErrorMsg ); XtSetValues (w_msg, &arg, 1); break;
    case PlayerMoveErrorWarning  : XtSetArg (arg, XtNlabel, PlayerMoveErrorMsg ); XtSetValues (w_msg, &arg, 1); break;
    case MemoryErrorDialog       : XtSetArg (arg, XtNlabel, MemoryErrorMsg     ); XtSetValues (w_msg, &arg, 1); break;
    case CantOpenFileDialog      : XtSetArg (arg, XtNlabel, CantOpenFileMsg    ); XtSetValues (w_msg, &arg, 1); break;
    case IllegalMoveDialog       : XtSetArg (arg, XtNlabel, IllegalMoveMsg     ); XtSetValues (w_msg, &arg, 1); break;
    case SuicideMoveDialog       : XtSetArg (arg, XtNlabel, SuicideMoveMsg     ); XtSetValues (w_msg, &arg, 1); break;
    case KoMoveDialog            : XtSetArg (arg, XtNlabel, KoMoveMsg          ); XtSetValues (w_msg, &arg, 1); break;
    case BadHandicapWarning      : XtSetArg (arg, XtNlabel, BadHandicapMsg     ); XtSetValues (w_msg, &arg, 1); break;
    case RemainingStonesWarning  : XtSetArg (arg, XtNlabel, RemainingStonesMsg ); XtSetValues (w_msg, &arg, 1); break;
    case DiagramBadNodeWarning   : XtSetArg (arg, XtNlabel, DiagramBadNodeMsg  ); XtSetValues (w_msg, &arg, 1); break;
    case SizeBadNodeWarning      : XtSetArg (arg, XtNlabel, SizeBadNodeMsg     ); XtSetValues (w_msg, &arg, 1); break;
    case WallyWhitePlayWarning   : XtSetArg (arg, XtNlabel, WallyWhitePlayMsg  ); XtSetValues (w_msg, &arg, 1); break;
    case WallyBadSizeWarning     : XtSetArg (arg, XtNlabel, WallyBadSizeMsg    ); XtSetValues (w_msg, &arg, 1); break;
    case WallyBadHandicapWarning : XtSetArg (arg, XtNlabel, WallyBadHandicapMsg); XtSetValues (w_msg, &arg, 1); break;
    case BlackPassDialog         : XtSetArg (arg, XtNlabel, BlackPassMsg       ); XtSetValues (w_msg, &arg, 1); break;
    case WhitePassDialog         : XtSetArg (arg, XtNlabel, WhitePassMsg       ); XtSetValues (w_msg, &arg, 1); break;
    }

    top   = w_top;
    focus = w_confirm;
    break;
  }

  dialog_mode   = mode;
  dialog_widget = top;

  CenterWindow  (top, focus);
  XtPopup       (top, XtGrabNonexclusive);
}

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

static void dialogConfirm  (w, event)
Widget    w;
XEvent   *event;
{
  SG_NodePtr     node;
  String         name;
  Arg            arg;

  XtPopdown (dialog_widget);

  switch (dialog_mode) {
 
  case ReallyDeleteDialog :
    delete_confirm = True;
    XPutBackEvent (XtDisplay (w), &delay_event);
    break;

  case ReallyQuitDialog :
    exit (1);
    break;

  case SaveBeforeQuitDialog :
    if (file_name[0] != '\0') {
      if (SaveFile (w, event, file_name) == True)
	(void) exit (1);
    }

    else 
      PopupDialog (w, event, SaveAsAndQuitDialog);
    break;

  case SaveBeforeLoadDialog :
    if (file_name[0] != '\0') {
      if (SaveFile (w, event, file_name) == True)
	PopupDialog (w, event, LoadDialog);
    }

    else 
      PopupDialog (w, event, SaveAsAndLoadDialog);
    break;

  case NodeNameDialog      :
    XtSetArg (arg, XtNstring, (XtArgVal) &name); 
    XtGetValues (d_text, &arg, 1);

    SG_MakeProperty (current_node, SG_nodeName, name);
    ShowTmpProperty (current_node);

    modified = True;
    break;

  case SaveAsAndQuitDialog :
  case SaveAsAndLoadDialog :
  case SaveAsDialog        :
    
    XtSetArg (arg, XtNstring, (XtArgVal) &name); XtGetValues (d_text, &arg, 1);
    
    if (SaveFile (w, event, name) == True)
      switch (dialog_mode) {
      case SaveAsAndQuitDialog : exit (1);
      case SaveAsAndLoadDialog : PopupDialog (w, event, LoadDialog);
      }
    break;
    
  case LoadDialog :
    XtSetArg (arg, XtNstring , (XtArgVal) &name); XtGetValues (d_text, &arg, 1);

    if (LoadFile (w, event, name) == True) {
      XtSetArg (arg, XtNtitle , (XtArgVal) ApplicationName); XtSetValues (w_toplevel, &arg, 1);
      XtSetArg (arg, XtNstring, (XtArgVal) ""             ); XtSetValues (c_comment , &arg, 1);
      XtSetArg (arg, XtNstring, (XtArgVal) ""             ); XtSetValues (d_text    , &arg, 1); 

      GbClearBoard  (w_goban);

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

      Edit (False);
    }
    break;
    
  case EditDialog :
    Edit (True);

    XPutBackEvent (XtDisplay (w), &delay_event);
    break;
    
  case StopGameDialog :
    stopGame ();

    XPutBackEvent (XtDisplay (w), &delay_event);
    break;

  case StopGameBeforeQuitDialog :
    stopGame ();
    (void) exit (1);

    /* NOTREACHED */

  case RemoveStonesDialog :
  case ReplaceNodeDialog :
    node = current_node->down;
    
    SG_RemoveNode (node);
    SG_FreeNode   (node);
    
    modified = True;
    
    XPutBackEvent (XtDisplay (w), &delay_event);
    break;
    
  case MailNoMoveDialog :
    (void) exit (1); 

    /* NOTREACHED */

  case MailConfirmMoveDialog :
    if (SaveFile (w, event, mail_file_name) == True)
      (void) exit (0);
    else
      (void) exit (1);
    
    /* NOTREACHED */
  }
}

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

static void dialogCancel  (w, event) 
Widget    w;
XEvent   *event;
{ 
  XtPopdown (dialog_widget);
 
  switch (dialog_mode) {
  case SaveBeforeQuitDialog : PopupDialog (w, event, ReallyQuitDialog); break;
  case SaveBeforeLoadDialog : PopupDialog (w, event, LoadDialog      ); break;
  }
}

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

void makeDialogWindow (toplevel, app_context)
Widget        toplevel;
XtAppContext  app_context;
{
  static XtActionsRec   actions[] = {
    { "dialogConfirm"   , dialogConfirm  , },
    { "dialogCancel"    , dialogCancel   , },
  }; 
  
  Arg            args[10];
  int            xtargc;
  XtTranslations translations;
  
  XtAppAddActions (app_context, actions, XtNumber(actions));
  
  /*
   *    Dialog Window.
   */
  
  translations = XtParseTranslationTable 
    ("#override                        \
      <Key> Escape   : dialogCancel()  \n\
      <Key> Linefeed : dialogConfirm() \n\
      <Key> Return   : dialogConfirm() \n\
      Ctrl <Key> J   : dialogConfirm() \n\
      Ctrl <Key> M   : dialogConfirm()");
  
  d_top      = XtCreatePopupShell ("dialog"     , transientShellWidgetClass, toplevel , NULL, 0);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNdefaultDistance  , (XtArgVal) 12          ); xtargc++;
  XtSetArg (args[xtargc], XtNtranslations     , (XtArgVal) translations); xtargc++;

  d_form     = XtCreateManagedWidget ("form"     , formWidgetClass     , d_top   , args, xtargc);

  xtargc = 0;
  XtSetArg (args[xtargc], XtNwidth            , (XtArgVal) 294         ); xtargc++;  
  XtSetArg (args[xtargc], XtNborderWidth      , (XtArgVal) 0           ); xtargc++;  

  d_msg      = XtCreateManagedWidget ("msg"      , labelWidgetClass    , d_form   , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNfromVert         , (XtArgVal) d_msg       ); xtargc++;  
  XtSetArg (args[xtargc], XtNwidth            , (XtArgVal) 294         ); xtargc++;  
  XtSetArg (args[xtargc], XtNvertDistance     , (XtArgVal) 8           ); xtargc++;  
  XtSetArg (args[xtargc], XtNeditType         , (XtArgVal) XawtextEdit ); xtargc++;  
  XtSetArg (args[xtargc], XtNtranslations     , (XtArgVal) translations); xtargc++;  

  d_text     = XtCreateManagedWidget ("text"     , asciiTextWidgetClass, d_form   , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNfromVert         , (XtArgVal) d_text      ); xtargc++;  
  XtSetArg (args[xtargc], XtNwidth            , (XtArgVal) 140         ); xtargc++;  

#ifndef NO_EXTENSION
  XtSetArg (args[xtargc], XtNshapeStyle       , (XtArgVal) XmuShapeOval); xtargc++;  
#endif

  d_cancel   = XtCreateManagedWidget ("cancel"   , commandWidgetClass  , d_form   , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNfromVert         , (XtArgVal) d_text      ); xtargc++;  
  XtSetArg (args[xtargc], XtNfromHoriz        , (XtArgVal) d_cancel    ); xtargc++;  
  XtSetArg (args[xtargc], XtNwidth            , (XtArgVal) 140         ); xtargc++;  

#ifndef NO_EXTENSION
  XtSetArg (args[xtargc], XtNshapeStyle       , (XtArgVal) XmuShapeOval); xtargc++;  
#endif
  
  d_confirm  = XtCreateManagedWidget ("confirm"  , commandWidgetClass  , d_form   , args, xtargc);
  
  XtAddCallback (d_cancel , XtNcallback, dialogCancel , NULL);
  XtAddCallback (d_confirm, XtNcallback, dialogConfirm, NULL);

  XtRealizeWidget (d_top);

  /*
   *    Ask Window.
   */
   
  a_top      = XtCreatePopupShell ("ask", transientShellWidgetClass, toplevel, NULL, 0);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNdefaultDistance, (XtArgVal) 12          ); xtargc++;  
  XtSetArg (args[xtargc], XtNtranslations   , (XtArgVal) translations); xtargc++;  
  
  a_form     = XtCreateManagedWidget ("form"     , formWidgetClass     , a_top    , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNwidth          , (XtArgVal) 214         ); xtargc++;  
  XtSetArg (args[xtargc], XtNheight         , (XtArgVal) 30          ); xtargc++;  
  XtSetArg (args[xtargc], XtNborderWidth    , (XtArgVal) 0           ); xtargc++;  
  
  a_msg      = XtCreateManagedWidget ("msg"      , labelWidgetClass    , a_form   , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNfromVert       , (XtArgVal) a_msg       ); xtargc++;  
  XtSetArg (args[xtargc], XtNwidth          , (XtArgVal) 100         ); xtargc++;  

#ifndef NO_EXTENSION
  XtSetArg (args[xtargc], XtNshapeStyle     , (XtArgVal) XmuShapeOval); xtargc++;  
#endif

  a_cancel   = XtCreateManagedWidget ("cancel"   , commandWidgetClass  , a_form   , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNfromVert       , (XtArgVal) a_msg       ); xtargc++;  
  XtSetArg (args[xtargc], XtNfromHoriz      , (XtArgVal) a_cancel    ); xtargc++;  
  XtSetArg (args[xtargc], XtNwidth          , (XtArgVal) 100         ); xtargc++;  

#ifndef NO_EXTENSION
  XtSetArg (args[xtargc], XtNshapeStyle     , (XtArgVal) XmuShapeOval); xtargc++;  
#endif
  
  a_confirm  = XtCreateManagedWidget ("confirm"  , commandWidgetClass  , a_form   , args, xtargc);
  
  XtAddCallback (a_cancel , XtNcallback, dialogCancel , NULL);
  XtAddCallback (a_confirm, XtNcallback, dialogConfirm, NULL);
  
  XtRealizeWidget (a_top);

  /*
   *    Warning Window.
   */
  
  translations = XtParseTranslationTable 
    ("#override                    \
      <BtnDown>  : dialogCancel()  \n\
      <Key>      : dialogCancel()");
  
  w_top     = XtCreatePopupShell ("warning", transientShellWidgetClass, toplevel, NULL, 0);
   
  xtargc = 0;
  XtSetArg (args[xtargc], XtNdefaultDistance, (XtArgVal) 12          ); xtargc++;  
  XtSetArg (args[xtargc], XtNtranslations   , (XtArgVal) translations); xtargc++;  

  w_form     = XtCreateManagedWidget ("form"     , formWidgetClass     , w_top    , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNwidth          , (XtArgVal) 206         ); xtargc++;  
  XtSetArg (args[xtargc], XtNheight         , (XtArgVal) 48          ); xtargc++;  
  XtSetArg (args[xtargc], XtNborderWidth    , (XtArgVal) 0           ); xtargc++;  
  
  w_msg      = XtCreateManagedWidget ("msg"      , labelWidgetClass    , w_form   , args, xtargc);
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNfromVert       , (XtArgVal) w_msg       ); xtargc++;  
  XtSetArg (args[xtargc], XtNwidth          , (XtArgVal) 100         ); xtargc++;  
  XtSetArg (args[xtargc], XtNhorizDistance  , (XtArgVal) 65          ); xtargc++;  
  XtSetArg (args[xtargc], XtNlabel          , (XtArgVal) OkLabel     ); xtargc++;  

#ifndef NO_EXTENSION
  XtSetArg (args[xtargc], XtNshapeStyle     , (XtArgVal) XmuShapeOval); xtargc++;  
#endif
 
  w_confirm  = XtCreateManagedWidget ("confirm"  , commandWidgetClass  , w_form   , args, xtargc);
  
  XtAddCallback (w_confirm, XtNcallback, dialogCancel, NULL);

  XtRealizeWidget (w_top);
  
  /*
   *  Help window
   */
 
  h_top  = XtCreatePopupShell ("help", transientShellWidgetClass, w_toplevel, NULL, 0); 
  
  xtargc = 0;
  XtSetArg (args[xtargc], XtNlabel        , (XtArgVal) HelpString  ); xtargc++;  
  XtSetArg (args[xtargc], XtNtranslations , (XtArgVal) translations); xtargc++;  
 
  h_text     = XtCreateManagedWidget ("text"     , labelWidgetClass    ,  h_top   , args, xtargc);

  XtRealizeWidget (h_top);
}
