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

#include <math.h>

#include "player.h"
#include "graph.h"
#include "world.h"
#include "city.h"
#include "units.h"
#include "trans.h"
#include "keyboard.h"
#include <xview/xv_xrect.h>

#define Xvscreen ((XvScreen *)screen)
#define BUTTON_CALLBACK  100
#define BUTTON_CALL_DATA 101
#define MENU_LIST_KEY    102
#define MENU_CALLBACK    103
#define MENU_CALL_DATA   104

WDisplay *FindWindow(Xv_Window window)
{
  return (WDisplay *)xv_get(window, WIN_CLIENT_DATA);
}

void XvGetEvent(Xv_Window window, Event *event, Notify_arg /*arg*/)
{
  if (state == IN_SELECT)
    return;
  switch (event_action(event)) {
  case ACTION_SELECT:
    if (event_is_down(event)) return;
    FindWindow(window)->GetEvent(MOUSE_LEFT, event_x(event), event_y(event), NULL);
    return;
  case ACTION_MENU:
    if (event_is_down(event)) return;
    FindWindow(window)->GetEvent(MOUSE_RIGHT, event_x(event), event_y(event), NULL);
    return;
  }
  if (event_xevent(event)->type != KeyPress) return;

  XKeyEvent *key_event = (XKeyEvent *)event_xevent(event);
  int key = TranslateMoveKey(key_event->keycode);

  if (key == 0) {
    char buf[20];
    XLookupString(key_event, buf, 20, NULL, NULL);
    key = *buf;
    if (TranslateChar2MoveKey(key))
      key = TranslateChar2MoveKey(key);
  }
  FindWindow(window)->GetEvent(KEYBOARD, key, 0, NULL);
}

XvDisplayData::~XvDisplayData()
{
  xv_destroy_safe(XvFrame);
}

XvDisplayData::XvDisplayData(X11Screen *scr, Display *display, char *name) : X11DisplayData(scr, display)
{
  XvFrame = xv_create(XV_NULL, FRAME,
		      WIN_CLIENT_DATA, this,
		      FRAME_LABEL, name,
		      NULL);
  topPanel = (Panel)xv_create(XvFrame, PANEL,
			      PANEL_LAYOUT, PANEL_HORIZONTAL,
			      PANEL_CLIENT_DATA, this,
			      NULL);

  if (XvScreen::DefaultFrame == XV_NULL)
    XvScreen::DefaultFrame = XvFrame;
}

void buttonHandler(Panel_item item, int /*value*/)
{
  void (*callback)(void *) = (void(*)(void*))xv_get(item, XV_KEY_DATA, BUTTON_CALLBACK);
  callback((void *)xv_get(item ,XV_KEY_DATA, BUTTON_CALL_DATA));
}

void
XvDisplayData::AddButton(char *name, void (*callback)(void *), void *call_data)
{
  xv_create(topPanel, PANEL_BUTTON,
	    PANEL_LABEL_STRING, name,
	    PANEL_NOTIFY_PROC, buttonHandler,
	    XV_KEY_DATA, BUTTON_CALLBACK, callback,
	    XV_KEY_DATA, BUTTON_CALL_DATA, call_data,
	    NULL);
}

void menuNotify(Menu menu, Menu_item menu_item)
{
  char *option = (char *)xv_get(menu_item, MENU_STRING);
  MenuItem *list = (MenuItem *)xv_get(menu, XV_KEY_DATA, MENU_LIST_KEY);
  void (*callback)(void *, void *) = (void (*)(void*,void*))xv_get(menu, XV_KEY_DATA, MENU_CALLBACK);

  for (int i = 0;; i++)
    if (!strcmp(option, list[i].line)) {
      callback(list[i].return_data,
	       (void *)xv_get(menu, XV_KEY_DATA, MENU_CALL_DATA));
      return;
    }
}

void XvDisplayData::AddMenu(char *name, MenuItem *list,
			    void (*callback)(void *, void *), void *call_data)
{
  Menu menu = (Menu)xv_create(XV_NULL, MENU,
			      MENU_CLIENT_DATA, this,
			      XV_KEY_DATA, MENU_CALLBACK, callback,
			      XV_KEY_DATA, MENU_LIST_KEY, list,
			      XV_KEY_DATA, MENU_CALL_DATA, call_data,
			      MENU_NOTIFY_PROC, menuNotify,
			      NULL);
  for (int i = 0; list[i].line != NULL; i++) {
    xv_set(menu, MENU_ITEM,
	   MENU_STRING, list[i].line, NULL,
	   NULL);
  }

  xv_create(topPanel, PANEL_BUTTON,
	    PANEL_LABEL_STRING,  name,
	    PANEL_ITEM_MENU,     menu, /* attach menu to button */
	    NULL);
}

// MapDisplay

XvMapDisplay::XvMapDisplay(World *w, Player *p) : MapDisplay(w, p) {
  CreateWindow();
}

XvMapDisplay::XvMapDisplay() : MapDisplay() {
  CreateWindow();
}

XvMapDisplay::~XvMapDisplay()
{ ; }

void XvMapDisplay::CreateWindow()
{
  data = new XvDisplayData((X11Screen *)screen, Xvscreen->dpy, "Civ");
  Setup();

#define data ((XvDisplayData *)data)
  mesg = (Panel_item)xv_create(data->topPanel, PANEL_MESSAGE,
			       PANEL_LABEL_STRING, "Initializing",
			       PANEL_LABEL_WIDTH, 200,
			       NULL);
  data->Map();
};

void
XvDisplayData::CreateDrawingArea(int w, int h, WDisplay *win)
{
  width = w; height = h;

  window_fit(topPanel);
  xv_set(topPanel, XV_WIDTH, width, NULL);

  canvas = (Canvas)xv_create(XvFrame, CANVAS,
			     XV_WIDTH, width,
			     XV_HEIGHT, height,
			     WIN_BACKGROUND_COLOR, BlackPixel(dpy, DefaultScreen(dpy)),
			     CANVAS_X_PAINT_WINDOW, TRUE,
			     XV_X, 0,
			     XV_Y, xv_get(topPanel, XV_HEIGHT),
			     NULL);
  
  window = (Xv_Window)xv_get(canvas_paint_window(canvas), XV_XID);
  xv_set(canvas_paint_window(canvas),
	 WIN_EVENT_PROC, XvGetEvent,
	 WIN_CLIENT_DATA, win,
	 WIN_CONSUME_EVENTS,
	 WIN_NO_EVENTS,
	 WIN_ASCII_EVENTS, WIN_MOUSE_BUTTONS,
	 NULL,
	 NULL);
  window_fit(XvFrame);

  pix = XCreatePixmap(dpy, window,
		      width, height,
		      xv_get(XvFrame, XV_DEPTH));
  XFillRectangle(dpy, pix, screen->gc, 0, 0, width, height);
}

void XvDisplayData::Map()
{
  xv_set(XvFrame, XV_SHOW, TRUE, NULL);
  frame = xv_get(XvFrame, XV_XID);
}

void XvDisplayData::ExposeNotify(int x, int y, int width, int height) {
  XCopyArea(dpy, pix, window, screen->gc, x, y, width, height, x, y);
}

void XvMapDisplay::DisplayMessage(char *text, int color) {
  xv_set(mesg, PANEL_LABEL_STRING, text, NULL);
}

void XvMapDisplay::BlitMap(int x1, int y1, int w, int h, int x2, int y2)
{
  /*  XCopyArea(dpy, window, window, screen->gc,
	    x1*SquareWidth+HorizSpace, y1*SquareHeight+VertSpace,
	    w*SquareWidth, h*SquareHeight,
	    x2*SquareWidth+HorizSpace, y2*SquareHeight+VertSpace);*/
}

// citydisplay
void changeHandler(Panel_item item, int /*value*/)
{
  ((XvCityDisplay *)xv_get(xv_get(item , XV_OWNER), PANEL_CLIENT_DATA))->GetEvent(KEYBOARD, 'c', 0, NULL);
}

void buyHandler(Panel_item item, int /*value*/)
{
  ((XvCityDisplay *)xv_get(xv_get(item , XV_OWNER), PANEL_CLIENT_DATA))->GetEvent(KEYBOARD, 'b', 0, NULL);
}

#ifdef BIGPIXMAPS
static char *line[] = {
"50 1 1 1",
"X c #000",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
};
#else
static char *line[] = {
"100 1 1 1",
"X c #000",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
};
#endif

XvCityDisplay::~XvCityDisplay() {;}

XvCityDisplay::XvCityDisplay(City *cityp, Player *owner) : CityDisplay(cityp, owner)
{
  data = new XvDisplayData((X11Screen *)screen, Xvscreen->dpy, cityp->name);

  Setup();
  Panel rightPanel = (Panel)xv_create(data->XvFrame, PANEL,
				      PANEL_LAYOUT, PANEL_VERTICAL,
				      PANEL_CLIENT_DATA, this,
				      XV_X, xv_get(data->canvas, XV_X)+CityScreenWidth,
				      XV_Y, xv_get(data->topPanel, XV_HEIGHT),
				      NULL);
  buildingList = (Panel_item)xv_create(rightPanel, PANEL_LIST,
					  PANEL_LIST_ROW_HEIGHT, 16,
					  PANEL_LIST_DISPLAY_ROWS, 8,
					  PANEL_LIST_TITLE, "Buildings",
					  NULL);
  xv_create(rightPanel, PANEL_MESSAGE,
	    PANEL_ITEM_Y_GAP, 15,
	    PANEL_LABEL_IMAGE, xv_create(XV_NULL, SERVER_IMAGE,
					 SERVER_IMAGE_PIXMAP, ((PixmapInfo *)screen->CompilePixmap(line))->pixmap,
					 NULL),
	    NULL);
  
  xv_create(rightPanel, PANEL_BUTTON,
	    PANEL_LABEL_STRING, "Change",
	    PANEL_NOTIFY_PROC, changeHandler,
	    NULL);
  xv_set(rightPanel, PANEL_LAYOUT, PANEL_HORIZONTAL, NULL);
  xv_create(rightPanel, PANEL_BUTTON,
	    PANEL_LABEL_STRING, "Buy",
	    PANEL_NOTIFY_PROC, buyHandler,
	    NULL);
  xv_set(rightPanel, PANEL_LAYOUT, PANEL_VERTICAL, NULL);
  currentBuild = (Panel_item)xv_create(rightPanel, PANEL_MESSAGE, NULL);
  xv_create(rightPanel, PANEL_MESSAGE,
	    PANEL_LABEL_IMAGE, xv_create(XV_NULL, SERVER_IMAGE,
					 SERVER_IMAGE_PIXMAP, shield_pic.Handle()->pixmap,
					 NULL),
	    NULL);
  xv_set(rightPanel, PANEL_LAYOUT, PANEL_HORIZONTAL, NULL);
  buildingProgress = (Panel_item)xv_create(rightPanel, PANEL_MESSAGE,
					      NULL);

  window_fit(rightPanel);
  xv_set(rightPanel, XV_HEIGHT, CityScreenHeight, NULL);
  xv_set(data->topPanel, XV_WIDTH, CityScreenWidth+ xv_get(rightPanel, XV_WIDTH), NULL);
  
  window_fit(data->XvFrame);

  data->Map();
  Update();
}

void XvCityDisplay::ShowBuildings(List<charp> buildings)
{
  Panel_item list = buildingList; 
  xv_set(list, PANEL_LIST_DELETE_ROWS, 0, xv_get(list, PANEL_LIST_NROWS),
	 NULL);

  Lister<charp> buildl(buildings);
  int row = 0;
  while (buildl) {
    xv_set(list, PANEL_LIST_INSERT, row, NULL);
    xv_set(list, PANEL_LIST_STRING, row, buildl.Elem(), NULL);
    ++row;
    buildl.Next();
  }
}

void XvCityDisplay::ShowWorkInProgress(char *text)
{
  xv_set(currentBuild, PANEL_LABEL_STRING, text, NULL);
}

void XvCityDisplay::ShowBuildingProgress(char *text)
{
  xv_set(buildingProgress, PANEL_LABEL_STRING, text, NULL);
}

// textDisplay

XvTextDisplay::XvTextDisplay(int x, int y) : TextDisplay(x,y)
{
  data = new XvDisplayData((X11Screen *)screen, Xvscreen->dpy, "Civ");
  Setup();
  data->Map();
}

XvTextDisplay::~XvTextDisplay() {;}
