/*
 * Atom-4 X11 client: scoreboard panel
 * Implementation file
 *
 * $Id: xscoreboard.cc,v 1.13 2003/04/15 21:52:48 hsteoh Exp hsteoh $
 */

#include <stdio.h>			// DEBUG ONLY!!!!
#include <string.h>			// DEBUG ONLY!!!!

#include "color4.h"
#include "exception.h"
#include "interface.h"
#include "xscoreboard.h"


#define BORDER_WIDTH		3

// FIXME: we really should implement a sane font-handling framework
#define TITLE_Y			0	// (this excludes the border)
#define SCORES_START_Y		40
#define PL1_START_Y		SCORES_START_Y
#define PL2_START_Y		(height() - PL_HEIGHT)
#define PL_X			7
#define PL_HEIGHT		90
#define PL_TITLE_Y		0	// relative to start of score block
#define PL_SCORE_Y		14
#define PL_MSG_Y		45

#define WHEEL_X			(width()/2)
#define WHEEL_Y			(height()/2)

// FIXME: we should implement a saner text-typesetting framework instead of
// this ugly mess. We'll get to it some day...! :-)
#define TEXTBUF_MAX		128


#ifndef DATADIR				// should be defined by build script
#define DATADIR		"."		// search current dir if undefined
#endif

static char *wheelnames[NUM_WHEELS] = {
  DATADIR "/wheel12-1.xpm",
  DATADIR "/wheel12-2.xpm",
  DATADIR "/wheel12-3.xpm",
  DATADIR "/wheel12-4.xpm",
  DATADIR "/wheel12-5.xpm",
  DATADIR "/wheel12-6.xpm"
};

xscoreboard::xscoreboard(xconnection *conn, xsprite_engine *engine,
                         xwindow *parent, atom4 *g, int x, int y,
                         int w, int h) :
	xwindow(conn, parent, x,y, w-BORDER_WIDTH*2,h-BORDER_WIDTH*2,
                BORDER_WIDTH, conn->black(), conn->black()),
	game(g), eng(engine) {
  Display *disp = conn->display();
  XGCValues gcvals;
  int i;

  for (i=0; i<NUM_WHEELS; i++) {
    wheels[i] = new xflatsprite(eng, wheelnames[i]);
    if (!wheels[i])
      throw exception("@Error while loading %s\n", wheelnames[i]);
  }

  // "Backing store"
  buffer = XCreatePixmap(disp, win, width(), height(), conn->scrn_depth());
  gcvals.foreground = conn->black();
  erasegc = XCreateGC(disp, buffer, GCForeground, &gcvals);

  // TESTING CODE
  // Load a font to write in
  titlefont = XLoadQueryFont(disp, "9x15bold");
  if (!titlefont) throw exception("Unable to load title font");

  // GC for title font
  gcvals.foreground = conn->white();
  gcvals.background = conn->black();
  gcvals.font = titlefont->fid;
  titlegc = XCreateGC(disp, win, GCForeground | GCBackground | GCFont,
                      &gcvals);

  scorefont = XLoadQueryFont(disp, "7x13");
  if (!scorefont) throw exception("Unable to load font");

  // GC for regular font
  gcvals.foreground = conn->white();
  gcvals.background = conn->black();
  gcvals.font = scorefont->fid;
  textgc = XCreateGC(disp, win, GCForeground | GCBackground | GCFont,
                     &gcvals);

  // Do initial render into buffer
  refresh();

  XSelectInput(conn->display(), win, ExposureMask | FocusChangeMask);
}

xscoreboard::~xscoreboard() {
  Display *disp = conn->display();

  XFreeGC(disp, erasegc);
  XFreePixmap(disp, buffer);
  XFreeGC(disp, textgc);
  XFreeGC(disp, titlegc);
  XFreeFont(disp, scorefont);
  XFreeFont(disp, titlefont);
}

void xscoreboard::draw_center(XFontStruct *font, GC gc, char *text, int y) {
  XCharStruct result;
  int dummy, x;
  int textlen = strlen(text);

  // Measure extent of text
  XTextExtents(font, text, textlen, &dummy, &dummy, &dummy, &result);

  x = (wd - result.width)/2;
  XDrawString(conn->display(), buffer, gc, x, y+font->ascent, text, textlen);
}

void xscoreboard::render_score(int player, int starty) {
  Display *disp = conn->display();
  char buf[TEXTBUF_MAX+1];

  snprintf(buf, TEXTBUF_MAX, "Player %d", player);
  XDrawString(disp, buffer, textgc, PL_X, starty+PL_TITLE_Y+scorefont->ascent,
              buf, strlen(buf));

  snprintf(buf, TEXTBUF_MAX, "Score: %d", game->score(player));
  XDrawString(disp, buffer, textgc, PL_X, starty+PL_SCORE_Y+scorefont->ascent,
              buf, strlen(buf));

  if (player==game->current_player()) {
    if (player==game->local_playernum()) {
      snprintf(buf, TEXTBUF_MAX, "*** YOUR TURN ***");
    } else {
      snprintf(buf, TEXTBUF_MAX, "*** OPPONENT'S TURN ***");
    }
    XDrawString(disp, buffer, textgc, PL_X, starty+PL_MSG_Y+scorefont->ascent,
                buf, strlen(buf));
  } else if (player==game->winner()) {
    snprintf(buf, TEXTBUF_MAX, "!!! Player %d WINS !!!", player);
    XDrawString(disp, buffer, textgc, PL_X, starty+PL_MSG_Y+scorefont->ascent,
                buf, strlen(buf));
  } else if (game->winner()==STALEMATE) {
    snprintf(buf, TEXTBUF_MAX, "=== DRAW: no more moves left ===", player);
    XDrawString(disp, buffer, textgc, PL_X, starty+PL_MSG_Y+scorefont->ascent,
                buf, strlen(buf));
  }
}

void xscoreboard::render_wheel(int wheel) {
  if (wheel<0 || wheel>=NUM_WHEELS)
    throw exception("@Illegal wheel number: %d\n", wheel);

  wheels[wheel]->draw(buffer, WHEEL_X, WHEEL_Y);
}

void xscoreboard::refresh() {
  static int tiletowheel[8] = { -1, 0, 2, 1, 4, 5, 3, -1 };
  int wheel = tiletowheel[game->current_tile()-'a'];

  // Erase any stuff that may be outdated
  XFillRectangle(conn->display(), buffer, erasegc, 0,0, width(), height());

  // Render everything
  draw_center(titlefont, titlegc, "XAtom-4 " VERSION_STRING, TITLE_Y);
  render_wheel(wheel);
  render_score(1, PL1_START_Y);
  render_score(2, PL2_START_Y);

  // Copy to screen in case this update is being triggered internally
  XCopyArea(conn->display(), buffer, win, eng->get_copygc(), 0,0, wd,ht, 0,0);
}

void xscoreboard::expose(XExposeEvent ev) {
  XCopyArea(conn->display(), buffer, win, eng->get_copygc(), ev.x, ev.y,
            ev.width, ev.height, ev.x, ev.y);
}

