//
// Specific Motif part of X11 interface
//

#ifdef HAVE_X11_XMU_EDITRES_H
# include <X11/Xmu/Editres.h>
#endif
#include <stdlib.h>
#include <sys/time.h>				  // FD_SETSIZE

#include <Xm/DrawingA.h>
#include <Xm/ScrolledW.h>
#include <Xm/List.h>
#include <Xm/MessageB.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/TextF.h>

#include "global.h"

#include "misc.h"
#include "net.h"
#include "server.h"
#include "displays.h"

#include "XmScreen.h"
//#include "XtActions.h"

static void PopupNotify(Widget, XtPointer, XtPointer);
void ExposeNotify(Widget, XtPointer, XtPointer);

typedef struct
{
  Widget hostItem, nameItem, numPlayersItem;
  int civInitOption;
  XmScreen* screen;
} InitCallbackStruct;
  
void XmScreen::MainLoop()
{
  XtRealizeWidget(top);
  XtAppMainLoop(app);
}

// X11Screen constructor: create Motif interface
XmScreen::XmScreen(int argc, char **argv) : XtkScreen(argc, argv)
{
  top = XtAppInitialize(&app, "Civ",
			NULL, 0,
			&argc, argv, NULL,
			NULL, 0);

  // use Editres protocol
#ifdef HAVE_X11_XMU_EDITRES_H
  XtAddEventHandler(top, (EventMask)0, TRUE, (XtEventHandler)_XEditResCheckMessages, NULL);
#endif
  
  dpy = XtDisplay(top);

  /* // add actions
  XtAppAddActions(app, actionTable, XtNumber(actionTable));*/
  
  // font
  XFontStruct *font = XLoadQueryFont(dpy, fontName);

  // gc
  XGCValues gcvalues;
  gcvalues.font = font->fid;
  gcvalues.foreground = WhitePixel(dpy, DefaultScreen(dpy));
  gcvalues.background = BlackPixel(dpy, DefaultScreen(dpy));
  gcvalues.graphics_exposures = False;
  gcvalues.clip_mask = None;
  gc = XCreateGC(dpy, RootWindow(dpy, DefaultScreen(dpy)),
		 GCForeground | GCBackground | GCFont | GCGraphicsExposures
		 | GCClipMask,
	      &gcvalues);
  colormap = DefaultColormap(dpy, DefaultScreen(dpy));

  // place to hold read handlers
  readHandlers = new ReadHandlerP[FD_SETSIZE];
  for (int i = 0; i < (int)FD_SETSIZE; ++i)
    readHandlers[i] = NULL;
}

void XmScreen::StartUp()
{
  //
  // Initialization popup
  //
  InitCallbackStruct* cbStruct = new InitCallbackStruct;
  cbStruct->screen = this;

  Widget initFrame = XmCreateFormDialog(top, "init", NULL, 0);
  
  Widget label = XtVaCreateManagedWidget("hostL", xmLabelWidgetClass, initFrame,
					 XmNleftAttachment, XmATTACH_FORM,
					 XmNtopAttachment, XmATTACH_FORM,
					 NULL);
  
  cbStruct->hostItem =
    XtVaCreateManagedWidget("host", xmTextFieldWidgetClass, initFrame,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, label,
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNtopAttachment, XmATTACH_FORM,
			    NULL);

  label =
    XtVaCreateManagedWidget("nameL", xmLabelWidgetClass, initFrame,
			    XmNleftAttachment, XmATTACH_FORM,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, cbStruct->hostItem,
			    NULL);
  
  cbStruct->nameItem =
    XtVaCreateManagedWidget("name", xmTextFieldWidgetClass, initFrame,
			    XmNcolumns, 20,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, label,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, cbStruct->hostItem,
			    NULL);
  
  label =
    XtVaCreateManagedWidget("nplayL", xmLabelWidgetClass, initFrame,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, cbStruct->nameItem,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, cbStruct->hostItem,
			    NULL);
  
  // FIXME: should allow only numbers; see PopupNotify
  cbStruct->numPlayersItem =
    XtVaCreateManagedWidget("nPlayers", xmTextFieldWidgetClass, initFrame,
			    XmNcolumns, 10,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, label,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, cbStruct->hostItem,
			    NULL);

  Widget RestoreButton =
    XtVaCreateManagedWidget("restore", xmPushButtonWidgetClass, initFrame,
			    XmNleftAttachment, XmATTACH_FORM,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, cbStruct->nameItem,
			    NULL);
  cbStruct->civInitOption = RestoreSaveFile;
  XtAddCallback(RestoreButton, XmNactivateCallback, PopupNotify, (XtPointer)cbStruct);
  
  Widget NewGameButton =
    XtVaCreateManagedWidget("newGame", xmPushButtonWidgetClass, initFrame,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, RestoreButton,
			    XmNtopAttachment, XmATTACH_WIDGET,
			    XmNtopWidget, cbStruct->nameItem,
			    NULL);
  cbStruct->civInitOption = StartNewGame;
  XtAddCallback(NewGameButton, XmNactivateCallback, PopupNotify, (XtPointer)cbStruct);

  XtVaSetValues(initFrame,
		XmNdefaultButton, NewGameButton,
		NULL);
  XtManageChild(initFrame);
}

struct ChoiceCallData {
  ChoiceHandlerFunc func;
  void *data;
};

// callback for popup list
void ChoiceNotify(Widget w, ChoiceCallData* clt, XtPointer call)
{
  XmListCallbackStruct* cbs = (XmListCallbackStruct*)call;
  char* string;

  // get item
  XmStringGetLtoR(cbs->item, XmFONTLIST_DEFAULT_TAG, &string);
  clt->func(string, clt->data);
  state = NORMAL;
  XtFree(string);
  delete clt;

  // popdown and destroy list
  w = XtParent(XtParent(XtParent(w)));
  XtUnmanageChild(w);
  XtDestroyWidget(w);
}

// create a popup choice list
void XmScreen::CreateChoiceFrame(char *mesg, List<charp> choices, ChoiceHandlerFunc f,	void *client_data)
{
  state = IN_SELECT;
  // create popup window
  Widget listForm = XmCreateFormDialog(top, "listForm", NULL, 0);
  XtVaSetValues(listForm,
		XmNtitle, mesg,
		NULL);

  // create scrolled list in popup
  Widget list = XmCreateScrolledList(listForm, "list", NULL, 0);
  XtManageChild(list);
  ChoiceCallData *d = new ChoiceCallData;
  d->func =f;
  d->data = client_data;
  XtAddCallback(list, XmNsingleSelectionCallback, ChoiceNotify, d);

  // fill list
  Lister<charp> choicel(choices);
  while (choicel)
    {
      XmString str = XmStringCreateLtoR(choicel.Elem(), XmFONTLIST_DEFAULT_TAG);
      XmListAddItem(list, str, 0);
      choicel.Next();
    }

  // popup list
  XtManageChild(listForm);
}

struct MesgCallData {
  MessageHandlerFunc func;
  void *data;
};

// Callback for MessageBox (below)
static void MessageNotify(Widget w, MesgCallData *clt, XtPointer /*call*/)
{
  if (clt->func != NULL)
    clt->func(clt->data);
  delete clt;

  w = XtParent(w);

  XtUnmanageChild(w);
  XtDestroyWidget(w);
}

// pop up a message box with OK button
void XmScreen::DispMessageBox(char *mesg, MessageHandlerFunc f, void *client_data)
{
  Arg args[5];
  int n=0;
  
  XmString msg = XmStringCreateLtoR(mesg, XmFONTLIST_DEFAULT_TAG);
  XtSetArg(args[n], XmNmessageString, msg); n++;
  XmString lab = XmStringCreateLtoR("Ok", XmFONTLIST_DEFAULT_TAG);
  XtSetArg(args[n], XmNokLabelString, lab); n++;

  Widget dialog = XmCreateMessageDialog(top, "message", args, n);
  XtVaSetValues(XtParent(dialog),
		XmNtitle, "civ Message",
		NULL);
  
  MesgCallData *d = new MesgCallData;
  d->func =f;
  d->data = client_data;
  XtAddCallback(dialog, XmNokCallback, MessageNotify, d);

  XtManageChild(dialog);
  
  XmStringFree(msg);
  XmStringFree(lab);
}

// PushButtons' activateCallback proc in init form
static void PopupNotify(Widget w, XtPointer clt, XtPointer /*call*/)
{
  InitCallbackStruct* cbs = (InitCallbackStruct*)clt;
  
  XmTextFieldGetString(cbs->hostItem);
  char *server = XmTextFieldGetString(cbs->hostItem);
  char *name = XmTextFieldGetString(cbs->nameItem);
  numPlayers = atoi(XmTextFieldGetString(cbs->numPlayersItem));

  if (strcmp(server, "")==0)
    { cbs->screen->DispMessageBox("No server specified !", NULL, NULL); return; }
  if (strcmp(name, "")==0)
    { cbs->screen->DispMessageBox("No name specified !", NULL, NULL); return; }
  if (numPlayers < 0)
    { cbs->screen->DispMessageBox("Should declare at least 0 players !", NULL, NULL); return; }
  
  myName = strdup(name);

  w = XtParent(w);				  // get Form id
  XtUnmanageChild(w);
  XtDestroyWidget(XtParent(w));			  // destroy shell
  
  Debug('i', "Startup as %d players, name \"%s\", server \"%s\"\n",
	numPlayers, name, server);
  CivInit(cbs->civInitOption, strdup(server));
}
