/*
 * X11 client for Atom-4
 * Implementation file
 *
 * $Id: xatom4.cc,v 1.29 2003/04/08 09:57:43 hsteoh Exp hsteoh $
 */

#include <stdio.h>			// FOR NOW ONLY
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/xpm.h>

#include "exception.h"
#include "xatom4.h"


#define WIN_WIDTH		640
#define WIN_HEIGHT		480

#define BOARD_X			0	// location of board pane
#define BOARD_Y			0

#define XCELLS			16	// board dimensions
#define YCELLS			16

#define COLOR_CLOSENESS		32768


/*
 *
 * Class XAtom4
 *
 */

void XAtom4::gamestate_notifier::notify_move(atom4 *src, int player,
                                             elist<boardchange> &chg) {
  app->refresh();

  // TBD: print message about player's move

  XFlush(app->conn->display());		// update display now
}

void XAtom4::gamestate_notifier::notify_clear(atom4 *src) {
  app->refresh();
  XFlush(app->conn->display());		// update display now
}

XAtom4::XAtom4(xconnection *xconn, atom4 *gm, int *indicator) :
	appwindow(xconn, "Atom4 X11 Client", "XAtom4",
	          WIN_WIDTH, WIN_HEIGHT, "XAtom4", "XAtom4"),
	conn(xconn), game(gm), exitflag(indicator), notifier(this) {
  Display *disp = conn->display();
  unsigned int score_x;

  eng = new xsprite_engine(conn, win, COLOR_CLOSENESS);
  if (!eng) throw exception("Unable to initialize sprite engine");

  boardpane = new xtriboard(conn, eng, this, game, BOARD_X, BOARD_Y);
  score_x = BOARD_X+boardpane->ext_width();
  scorepane = new xscoreboard(conn, eng, this, game, score_x, 0,
                              WIN_WIDTH-score_x, boardpane->height());

  // Select events we're interested in
  XSelectInput(disp, win, KeyPressMask | KeyReleaseMask |
                          ButtonPressMask | ButtonReleaseMask |
                          PointerMotionMask |
                          ExposureMask |
                          FocusChangeMask);

  // Map sub-windows
  XMapSubwindows(disp, win);

  *exitflag=0;

  // Register game state watcher
  game->add_notifier(&notifier);
}

XAtom4::~XAtom4() {
  game->remove_notifier(&notifier);
  delete scorepane;
  delete boardpane;
}

void XAtom4::refresh() {
  boardpane->refresh();
  scorepane->refresh();
}

void XAtom4::expose(XExposeEvent ev) {
  int x=ev.x, y=ev.y, w=ev.width, h=ev.height;

  // nothing for now
}

void XAtom4::key_press(XKeyPressedEvent ev) {
  KeySym keysym = XLookupKeysym(&ev, 0);
  switch(keysym) {
  case XK_k:	case XK_K:
    game->reset();
    break;
  case XK_n:	case XK_N:
    if (game->round_over()) {
      game->newround();
    }
    break;
  case XK_q:	case XK_Q:
    *exitflag=1;			// signal event loop to quit
    break;
  }
}

void XAtom4::mouse_buttondown(XButtonPressedEvent ev) {
  int x=ev.x, y=ev.y;
  int bx,by;				// board coors

  if (*boardpane==ev.subwindow) {	// Event is on board window
    if (!game->is_local_turn()) return;	// not playing, nothing to do

    if (ev.button==1) {
      boardpane->calc_bcoor(x,y,bx,by);

      if (game->check_legal(bx,by)) {
        boardpane->cursor_off();
        game->move(game->current_player(), bx,by);

        // Update cursor if there's still a next turn
        if (!game->round_over()) {
          boardpane->set_cursor(game->current_tile());
        }
      } else {
        // TODO: print error message
      }
    } // endif(ev.button)
  } else {
    // For now, ignore button events anywhere else
  }
}



/*
 *
 * Class x11ui
 *
 */

x11ui::x11ui(char *xserver, atom4 *game, eventloop *loop, int *exitflag) :
	interface(game),
	conn(xserver,loop),
	game_app(&conn, game, exitflag) {

  // Make sure that all initialization X requests are sent out before we
  // enter event loop; else we might end up in a deadlock.
  XFlush(conn.display());
}

x11ui::~x11ui() {}

