//
// Specific Athena part of X11 interface
//

#include <stdlib.h>
#include <sys/time.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>

#include "global.h"

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

#include "XawScreen.h"
#include "XawDisplays.h"

static void PopupNotify(Widget, XtPointer, XtPointer);

typedef struct
{
  Widget hostItem, nameItem, numPlayersItem;
  Widget restore, newGame;
  XawScreen* screen;
} InitCallbackStruct;
  

void XawScreen::MainLoop()
{
  XtRealizeWidget(top);
  XtAppMainLoop(app);
}

MapDisplay *XawScreen::CreateMapDisplay() {
  return new XawMapDisplay();
}

MapDisplay *XawScreen::CreateMapDisplay(World *w, Player *p) {
  return new XawMapDisplay(w, p);
}

CityDisplay *XawScreen::CreateCityDisplay(City *city, Player *owner) {
  return new XawCityDisplay(city, owner);
}

TextDisplay *XawScreen::CreateTextDisplay(int x, int y) {
  return new XawtextDisplay(x ,y);
}

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

  dpy = XtDisplay(top);

  // font
  XFontStruct *font = XLoadQueryFont(dpy, fontName);
  FontHeight = font->ascent + font->descent;
  FontWidth = font->max_bounds.width;

  // 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 XawScreen::StartUp()
{
  // Initialization popup
  //
  InitCallbackStruct* cbStruct = new InitCallbackStruct;
  cbStruct->screen = this;

  Widget popup = XtCreatePopupShell("init_popup", transientShellWidgetClass,
				    top, NULL, 0);
  Widget initFrame = XtCreateManagedWidget("init", formWidgetClass, popup,
					   NULL, 0);
  
  Widget label = XtVaCreateManagedWidget("hostL", labelWidgetClass, initFrame,
					 XtNlabel, "Server Host Name:",
					 "borderWidth", 0,
					 NULL);
  
  cbStruct->hostItem =
    XtVaCreateManagedWidget("host", asciiTextWidgetClass, initFrame,
			    XtNeditType, XawtextEdit,
			    XtNfromHoriz, label,
			    XtNleft, XawChainLeft,
			    XtNstring, "localhost",
			    NULL);

  label =
    XtVaCreateManagedWidget("nameL", labelWidgetClass, initFrame,
			    XtNfromVert, cbStruct->hostItem,
			    XtNtop, XawChainTop,
			    XtNlabel, "Name:",
			    "borderWidth", 0,
			    NULL);
				  
  cbStruct->nameItem =
    XtVaCreateManagedWidget("name", asciiTextWidgetClass, initFrame,
			    XtNeditType, XawtextEdit,
			    XtNfromHoriz, label,
			    XtNleft, XawChainLeft,
			    XtNfromVert, cbStruct->hostItem,
			    XtNtop, XawChainTop,
			    XtNwidth, 200,
			    NULL);
  
  label =
    XtVaCreateManagedWidget("nplayL", labelWidgetClass, initFrame,
			    XtNfromHoriz, cbStruct->nameItem,
			    XtNleft, XawChainLeft,
			    XtNfromVert, cbStruct->hostItem,
			    XtNtop, XawChainTop,
			    XtNlabel, "Number of Players:",
			    "borderWidth", 0,
			    NULL);
  
  // FIXME: should allow only numbers; see PopupNotify
  cbStruct->numPlayersItem =
    XtVaCreateManagedWidget("nPlayers", asciiTextWidgetClass, initFrame,
			    XtNeditType, XawtextEdit,
			    XtNfromHoriz, label,
			    XtNleft, XawChainLeft,
			    XtNfromVert, cbStruct->hostItem,
			    XtNtop, XawChainTop,
			    XtNstring, "0",
			    NULL);

  cbStruct->restore =
    XtVaCreateManagedWidget("restore", commandWidgetClass, initFrame,
			    XtNfromVert, cbStruct->nameItem,
			    XtNtop, XawChainTop,
			    XtNlabel, "Restore",
			    NULL);
  XtAddCallback(cbStruct->restore, XtNcallback, PopupNotify, (XtPointer)cbStruct);
  
  cbStruct->newGame =
    XtVaCreateManagedWidget("newGame", commandWidgetClass, initFrame,
			    XtNfromHoriz, cbStruct->restore,
			    XtNleft, XawChainLeft,
			    XtNfromVert, cbStruct->nameItem,
			    XtNtop, XawChainTop,
			    XtNlabel, "New Game",
			    NULL);
  XtAddCallback(cbStruct->newGame, XtNcallback, PopupNotify, (XtPointer)cbStruct);
  XtPopup(popup, XtGrabExclusive);
}

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

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

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

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

// create a popup choice list
void XawScreen::CreateChoiceFrame(char *mesg, List<charp> choices, ChoiceHandlerFunc f,	void *client_data)
{
  state = IN_SELECT;
  // create popup window
  Widget popup = XtCreatePopupShell("listForm_popup", transientShellWidgetClass, top,
				    NULL, 0);
  // with form inside
  Widget listForm = XtVaCreateManagedWidget("listForm", formWidgetClass, popup,
					    XtNtitle, mesg,
					    NULL);

  // fill list
  String* items = new String[choices.Count()];
  Lister<charp> choicel(choices);
  int i = 0;
  while (choicel) {
      items[i++] = choicel.Elem();
      choicel.Next();
    }
  // create scrolled list in popup
  Widget list = XtVaCreateManagedWidget("list", listWidgetClass, listForm,
					XtNlist, items,
					XtNnumberStrings, i,
					NULL);

  ChoiceCallData *d = new ChoiceCallData;
  d->func = f;
  d->data = client_data;
  XtAddCallback(list, XtNcallback, ChoiceNotify, d);

  // popup list
  // FIXME: pop it up on the original window
  XtPopup(popup, XtGrabExclusive);
}

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(XtParent(w));			  // get popup widget

  XtPopdown(w);
  XtDestroyWidget(w);
}

// pop up a message box with OK button
void XawScreen::DispMessageBox(char *mesg, MessageHandlerFunc f, void *client_data)
{
  Widget popup = XtCreatePopupShell("message_popup", transientShellWidgetClass, top,
				    NULL, 0);
  Widget message = XtCreateManagedWidget("message", formWidgetClass, popup,
					 NULL, 0);
  Widget label = XtVaCreateManagedWidget("message_label", labelWidgetClass, message,
					 XtNlabel, mesg,
					 "borderWidth", 0,
					 NULL);
  Widget butt = XtVaCreateManagedWidget("ok_butt", commandWidgetClass, message,
					XtNfromVert, label,
					XtNtop, XawChainTop,
					XtNlabel, "Ok",
					NULL);
  
  MesgCallData *d = new MesgCallData;
  d->func =f;
  d->data = client_data;
  XtAddCallback(butt, XtNcallback, MessageNotify, d);

  XtPopup(popup, XtGrabExclusive);
}

// PushButtons' activateCallback proc in init form
static void PopupNotify(Widget w, XtPointer clt, XtPointer /*call*/)
{
  InitCallbackStruct* cbs = (InitCallbackStruct*)clt;

  char* server;
  char* name;
  char* nPlayers;
  
  XtVaGetValues(cbs->hostItem,
		XtNstring, &server,
		NULL);
  XtVaGetValues(cbs->nameItem,
		XtNstring, &name,
		NULL);
  XtVaGetValues(cbs->numPlayersItem,
		XtNstring, &nPlayers,
		NULL);
		
  numPlayers = atoi(nPlayers);

  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);

  Widget shell = XtParent(XtParent(w));			  // get Shell id
  XtPopdown(shell);
  XtDestroyWidget(shell);				  // destroy shell
  
  Debug('i', "Startup as %d players, name \"%s\", server \"%s\"\n",
	numPlayers, name, server);
  CivInit(w == cbs->restore ? RestoreSaveFile : StartNewGame,
	  strdup(server));
}


