//
// Specific Xview part of X11/Xview interface
//

#include <stdlib.h>
#include "global.h"

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

#include "XvScreen.h"
#include "displays.h"
#include "XvDisplays.h"

Frame XvScreen::DefaultFrame;

Notify_value ReadNotify(Notify_client, int);
Notify_value TimerNotify(...);

// XV_KEY_DATA values (arbitrary)
#define HANDLER_FUNC 1
#define CLIENT_DATA  2

char *ReadEnv(char *name, char *def)
{
  char *str = getenv(name);
  return str == NULL ? def : str;
}

// Initialization popup data and routines
static Frame initFrame;
static Panel_item hostItem, numPlayersItem, nameItem;
static Panel_item RestoreButton, NewGameButton;

static void PopupNotify(Panel_item item, int /*value*/)
{
  char *server = (char *)xv_get(hostItem, PANEL_VALUE);
  char *name = (char *)xv_get(nameItem, PANEL_VALUE);
  numPlayers = (int)xv_get(numPlayersItem, PANEL_VALUE);
  myName = strdup(name);
  xv_set(initFrame, XV_SHOW, FALSE, NULL);
  Debug('i', "Startup as %d players, name %s, server %s\n", numPlayers,
	name, server);
  CivInit(item == RestoreButton ? RestoreSaveFile : StartNewGame,
	  strdup(server));
}

void XvScreen::MainLoop()
{
  xv_main_loop(DefaultFrame);
}

MapDisplay *XvScreen::CreateMapDisplay() {
  return new XvMapDisplay();
}

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

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

TextDisplay *XvScreen::CreateTextDisplay(int x, int y) {
  return new XvTextDisplay(x, y);
}

void
XvScreen::StartUp()
{
  state = NORMAL;
  Panel panel = (Panel)xv_get(initFrame, FRAME_CMD_PANEL);
  hostItem = xv_create(panel, PANEL_TEXT,
		       PANEL_LABEL_STRING, "Server Host Name:",
		       PANEL_VALUE, "localhost",
		       PANEL_VALUE_DISPLAY_LENGTH, 50,
		       NULL);
  nameItem = xv_create(panel, PANEL_TEXT,
		       PANEL_LABEL_STRING, "Name:",
		       PANEL_VALUE, ReadEnv("CIV_NAME", ""),
		       PANEL_VALUE_DISPLAY_LENGTH, 20,
		       NULL);
  numPlayersItem = xv_create(panel, PANEL_NUMERIC_TEXT,
			     PANEL_LABEL_STRING, "Number of Players:",
			     PANEL_VALUE, atoi(ReadEnv("CIV_NUMPL", "0")),
			     PANEL_VALUE_DISPLAY_LENGTH, 10,
			     NULL);
  xv_set(panel, PANEL_LAYOUT, PANEL_VERTICAL, NULL);
  RestoreButton = xv_create(panel, PANEL_BUTTON,
			    PANEL_LABEL_STRING, "Restore",
			    PANEL_NOTIFY_PROC, PopupNotify,
			    NULL);
  xv_set(panel, PANEL_LAYOUT, PANEL_HORIZONTAL, NULL);
  NewGameButton = xv_create(panel, PANEL_BUTTON,
			    PANEL_LABEL_STRING, "New Game",
			    PANEL_NOTIFY_PROC, PopupNotify,
			    NULL);
  window_fit(panel);
  window_fit(initFrame);
  xv_set(initFrame, XV_SHOW, TRUE, NULL);
}
// end of initialisation popup stuff

// XvScreen constructor: create Xview interface
XvScreen::XvScreen(int argc, char **argv) : X11Screen(argc, argv)
{
  xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);

  Xv_Font _font = (Xv_Font)xv_find(XV_NULL, FONT,
				   FONT_NAME, fontName,
				   NULL);
  XFontStruct *font = (XFontStruct *)xv_get(_font, FONT_INFO);

  FontHeight = xv_get(_font, FONT_CHAR_HEIGHT);
  FontWidth = xv_get(_font, FONT_CHAR_WIDTH);

  initFrame = xv_create(XV_NULL, FRAME_CMD,
			FRAME_LABEL, "Initialize Network",
			NULL);

  dpy = (Display *)xv_get(initFrame, XV_DISPLAY);

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

  readHandlers = new ReadHandlerP[FD_SETSIZE];
  for (int i = 0; i < (int)FD_SETSIZE; ++i)
    readHandlers[i] = NULL;
}

void *TimerClientData;

void XvScreen::StartTimer(int which, unsigned long milli, HandlerFunc func, void *client_data)
{
  if (which != 0) return;
  struct itimerval timer;
  timer.it_value.tv_sec = timer.it_interval.tv_sec = 0;
  timer.it_value.tv_usec = timer.it_interval.tv_usec = milli*1000L;
  Timers[0] = func;
  TimerClientData = client_data;
  notify_set_itimer_func(DefaultFrame, TimerNotify, ITIMER_REAL, &timer, NULL);
}

void XvScreen::StopTimer(int which)
{
  if (which != 0) return;
  notify_set_itimer_func(DefaultFrame, NOTIFY_FUNC_NULL, ITIMER_REAL, NULL, NULL);
}

void XvScreen::AddReadNotify(int fd, readNotifyFunc func, int info, int q)
{
  ReadHandler *ptr = new ReadHandler;
  readHandlers[fd] = ptr;
  ptr->fd = fd;
  ptr->func = func;
  ptr->q = q;
  ptr->info = info;
  notify_set_input_func(DefaultFrame, (Notify_func)ReadNotify, fd);
}

// got data, read the queue and hand it to the guy who wants it
Notify_value ReadNotify(Notify_client client, int fd)
{
  extern MsgQ *RecvQ(int);
  ReadHandler *ptr = screen->readHandlers[fd];
  if (ptr == NULL) return NOTIFY_DONE;
  MsgQ *q = NULL;
  if (ptr->q)
    q = RecvQ(fd);
  (*ptr->func)(q, fd, ptr->info);
  return NOTIFY_DONE;
}

Notify_value TimerNotify(...)
{
  (*screen->Timers[0])(0, TimerClientData);
  return NOTIFY_DONE;
}

void
ChoiceNotify(Panel_item item, char *string, caddr_t /*client_data*/,
		 Panel_list_op op)
{
  if (op != 1) return;
  Panel panel = (Panel)xv_get(item, XV_OWNER, NULL);
  ChoiceHandlerFunc f = (ChoiceHandlerFunc)xv_get(panel, XV_KEY_DATA, HANDLER_FUNC);
  f(string, (void *)xv_get(panel, XV_KEY_DATA, CLIENT_DATA));
  state = NORMAL;

  xv_destroy_safe(xv_get(panel,XV_OWNER));
}

void
XvScreen::CreateChoiceFrame(char *mesg, List<charp> choices, ChoiceHandlerFunc f, void *client_data)
{
  Frame cFrame;
  Panel panel;
  Panel_item list;

  state = IN_SELECT;
  cFrame = (Frame)xv_create(XV_NULL, FRAME_CMD,
			    FRAME_LABEL, "Select ...",
			    //XV_X, (int)xv_get(DefaultFrame, XV_X, NULL)+40,
			    //XV_Y, (int)xv_get(DefaultFrame, XV_Y, NULL)+20,
			    NULL);
  panel = (Panel)xv_get(cFrame, FRAME_CMD_PANEL, NULL);
  xv_set(panel, XV_KEY_DATA, HANDLER_FUNC, f,
	 XV_KEY_DATA, CLIENT_DATA, client_data,
	 NULL);
  list = (Panel_item)xv_create(panel, PANEL_LIST,
			       PANEL_LIST_ROW_HEIGHT, 16,
			       PANEL_LIST_DISPLAY_ROWS, 8,
			       PANEL_LIST_TITLE, mesg,
			       PANEL_NOTIFY_PROC, ChoiceNotify,
			       NULL);
  Lister<charp> choicel(choices);
  int row = 0;
  while (choicel) {
    xv_set(list, PANEL_LIST_INSERT, row, NULL);
    xv_set(list, PANEL_LIST_STRING, row, choicel.Elem(), NULL);
    ++row;
    choicel.Next();
  }

  window_fit(panel);
  window_fit(cFrame);
  xv_set(cFrame, XV_SHOW, TRUE, NULL);
}

void MessageNotify(Panel_item item, int /*value*/)
{
  MessageHandlerFunc f = (MessageHandlerFunc)xv_get(item, XV_KEY_DATA, HANDLER_FUNC);
  if (f != NULL)
    f((void *)xv_get(item, XV_KEY_DATA, CLIENT_DATA));

  xv_destroy_safe(xv_get(xv_get(item,XV_OWNER),XV_OWNER));
}

void XvScreen::DispMessageBox(char *mesg, MessageHandlerFunc f, void *client_data)
{
  Frame cFrame;
  Panel panel;
  Panel_item button;

  cFrame = (Frame)xv_create(XV_NULL, FRAME_CMD,
			    //XV_X, (int)xv_get(DefaultFrame, XV_X, NULL)+58,
			    //XV_Y, (int)xv_get(DefaultFrame, XV_Y, NULL)+20,
			    NULL);
  panel = (Panel)xv_get(cFrame, FRAME_CMD_PANEL, NULL);
  xv_create(panel, PANEL_MESSAGE,
	    // PANEL_LABEL_WIDTH, 204,
	    PANEL_LABEL_STRING, mesg,
	    NULL);
  button = (Panel_item)xv_create(panel, PANEL_BUTTON,
	    PANEL_LABEL_STRING, "Ok",
	    PANEL_NOTIFY_PROC, MessageNotify,
	    XV_KEY_DATA, HANDLER_FUNC, f,
            XV_KEY_DATA, CLIENT_DATA, client_data,
	    NULL);
  window_fit(panel);
  window_fit(cFrame);
  xv_set(cFrame, XV_SHOW, TRUE, NULL);
}
