/*
 * main.c
 * 
 * Copyright (C) 2006  Josef Kufner <jk@myserver.cz>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "message.h"

#define DEBUG 5
#include "debug.h"

#define FIELD_SIZE	24
#define FIELD_COUNT	15

#define send(arg...) {							\
	MESSAGE *msg;							\
	msg = message_create(0, 0);					\
	message_append(msg, MESSAGE_PART_DATA, ##arg, MESSAGE_END);	\
	message_to_file(msg, stdout, 1);				\
	message_destroy(msg);						\
}

#define send_add_obj(id, img, x, y) {					\
	send(MESSAGE_STRING, "Boa",					\
			MESSAGE_INTEGER, (id), MESSAGE_INTEGER, (img),	\
			MESSAGE_INTEGER, (x), MESSAGE_INTEGER, (y),	\
			MESSAGE_INTEGER, -1, MESSAGE_INTEGER, -1);	\
}

#define send_add_obj_wsize(id, img, x, y, w, h) {			\
	send(MESSAGE_STRING, "Boa",					\
			MESSAGE_INTEGER, (id), MESSAGE_INTEGER, (img),	\
			MESSAGE_INTEGER, (x), MESSAGE_INTEGER, (y),	\
			MESSAGE_INTEGER, (w), MESSAGE_INTEGER, (h));	\
}

#define send_delete_obj(id) {						\
	send(MESSAGE_STRING, "Bod", MESSAGE_INTEGER, (id));		\
}

#define send_move_obj(id, x, y) {					\
	send(MESSAGE_STRING, "Bom",					\
			MESSAGE_INTEGER, (id),				\
			MESSAGE_INTEGER, (x), MESSAGE_INTEGER, (y));	\
}


static void initialize_board(void);
static void process_message (MESSAGE *msg);
	
enum {
	PLAYER_NONE, PLAYER_O, PLAYER_X, PLAYER__MAX
};
enum {	IMAGE_NONE,
	PIECE_BISHOP_W, PIECE_KING_W, PIECE_KNIGHT_W, PIECE_PAWN_W, PIECE_QUEEN_W, PIECE_ROOK_W,
	PIECE_BISHOP_B, PIECE_KING_B, PIECE_KNIGHT_B, PIECE_PAWN_B, PIECE_QUEEN_B, PIECE_ROOK_B,

	CURSOR_LAST,
	CURSOR_FOCUS,
	CURSOR_SELECT,
	IMAGE_MAX
};
enum {
	OBJ_BACKGROUND,
	OBJ_CURSOR_LAST,
	OBJ_CURSOR_FOCUS,
	OBJ_CURSOR_SELECT,
	OBJ_PIECES_BEGIN
};

static int game_started = 0;
static int selected_obj = 0;
static int have_last = 0;
static const int field_size = 64;

static int obj_out[16];

static void initialize_board(void)
{
	int obj, i;
	
	/* load board */
	send(MESSAGE_STRING, "Bst", MESSAGE_STRING, "Solitaire Chess");
	send(MESSAGE_STRING, "Br");
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "boards/chess-wsb.png", MESSAGE_INTEGER, 0);
	send(MESSAGE_STRING, "Boa", MESSAGE_INTEGER, 0, MESSAGE_INTEGER, 0, MESSAGE_INTEGER, 0,
			MESSAGE_INTEGER, 0, MESSAGE_INTEGER, -1, MESSAGE_INTEGER, -1);

	/* load pieces */
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-bishop-black.png", MESSAGE_INTEGER, PIECE_BISHOP_B);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-bishop-white.png", MESSAGE_INTEGER, PIECE_BISHOP_W);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-king-black.png",   MESSAGE_INTEGER, PIECE_KING_B);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-king-white.png",   MESSAGE_INTEGER, PIECE_KING_W);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-knight-black.png", MESSAGE_INTEGER, PIECE_KNIGHT_B);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-knight-white.png", MESSAGE_INTEGER, PIECE_KNIGHT_W);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-pawn-black.png",   MESSAGE_INTEGER, PIECE_PAWN_B);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-pawn-white.png",   MESSAGE_INTEGER, PIECE_PAWN_W);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-queen-black.png",  MESSAGE_INTEGER, PIECE_QUEEN_B);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-queen-white.png",  MESSAGE_INTEGER, PIECE_QUEEN_W);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-rook-black.png",   MESSAGE_INTEGER, PIECE_ROOK_B);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "pieces/chess-rook-white.png",   MESSAGE_INTEGER, PIECE_ROOK_W);
	
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "cursors/chess-last.png",        MESSAGE_INTEGER, CURSOR_LAST);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "cursors/chess-focus.png",       MESSAGE_INTEGER, CURSOR_FOCUS);
	send(MESSAGE_STRING, "Bil", MESSAGE_STRING, "cursors/chess-selected.png",    MESSAGE_INTEGER, CURSOR_SELECT);

	/* build default set */
	obj = OBJ_PIECES_BEGIN;

	send_add_obj(obj, PIECE_ROOK_B, 0 * field_size, 0 * field_size); obj_out[obj++] = 2;
	send_add_obj(obj, PIECE_ROOK_W, 0 * field_size, 7 * field_size); obj_out[obj++] = 12;
	send_add_obj(obj, PIECE_ROOK_B, 7 * field_size, 0 * field_size); obj_out[obj++] = 2;
	send_add_obj(obj, PIECE_ROOK_W, 7 * field_size, 7 * field_size); obj_out[obj++] = 12;
	
	send_add_obj(obj, PIECE_KING_B, 4 * field_size, 0 * field_size); obj_out[obj++] = 0;
	send_add_obj(obj, PIECE_KING_W, 4 * field_size, 7 * field_size); obj_out[obj++] = 10;
	
	send_add_obj(obj, PIECE_QUEEN_B, 3 * field_size, 0 * field_size); obj_out[obj++] = 1;
	send_add_obj(obj, PIECE_QUEEN_W, 3 * field_size, 7 * field_size); obj_out[obj++] = 11;
	
	send_add_obj(obj, PIECE_KNIGHT_B, 1 * field_size, 0 * field_size); obj_out[obj++] = 4;
	send_add_obj(obj, PIECE_KNIGHT_W, 1 * field_size, 7 * field_size); obj_out[obj++] = 14;
	send_add_obj(obj, PIECE_KNIGHT_B, 6 * field_size, 0 * field_size); obj_out[obj++] = 4;
	send_add_obj(obj, PIECE_KNIGHT_W, 6 * field_size, 7 * field_size); obj_out[obj++] = 14;

	send_add_obj(obj, PIECE_BISHOP_B, 2 * field_size, 0 * field_size); obj_out[obj++] = 3;
	send_add_obj(obj, PIECE_BISHOP_W, 2 * field_size, 7 * field_size); obj_out[obj++] = 13;
	send_add_obj(obj, PIECE_BISHOP_B, 5 * field_size, 0 * field_size); obj_out[obj++] = 3;
	send_add_obj(obj, PIECE_BISHOP_W, 5 * field_size, 7 * field_size); obj_out[obj++] = 13;

	for (i = 0; i < 8; i++) {
		send_add_obj(obj, PIECE_PAWN_W, i * field_size, 6 * field_size); obj_out[obj++] = 15;
		send_add_obj(obj, PIECE_PAWN_B, i * field_size, 1 * field_size); obj_out[obj++] = 5;
	}
	
	/* all done */
	send(MESSAGE_STRING, "Bu");

	send(MESSAGE_STRING, "Sgr", MESSAGE_STRING, "hrac");

	/* ready */
	send(MESSAGE_STRING, "Sgl");

	return;
}


static void process_message (MESSAGE *msg)
{
	char *cmd, *cat, *mod, *opt, *val;
	int btn, x, y, obj, obj2, is_remote;
	
	if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_STRING, &cmd, MESSAGE_END)) {
		switch (cmd[0]) {
			case 'G': /* game */
				switch (cmd[1]) {
					case 'c': /* game check request */
						send(MESSAGE_STRING, "Sga");
						break;

					case 's': /* game start */
						game_started = 1;
						break;

					case 'o': /* game over */
						exit(0);
				}
				break;

			case 'S': /* Session */
				switch (cmd[1]) {
					case 't': /* turn */
						if (game_started && message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP, MESSAGE_SKIP,
									MESSAGE_INTEGER, &obj,
									MESSAGE_INTEGER, &obj2,
									MESSAGE_INTEGER, &x,
									MESSAGE_INTEGER, &y,
									MESSAGE_END)
							&& message_get(msg, MESSAGE_PART_SENDER_INFO,
									MESSAGE_SKIP,
									MESSAGE_INTEGER, &is_remote,
									MESSAGE_END))
						{	
							DBG_MSG(3, "Received turn: %d -> [ %d, %d ]", obj, x, y);
							send_move_obj(obj, x - (x % field_size), y - (y % field_size));
							if (have_last) {
								send_move_obj(OBJ_CURSOR_LAST,
										x - (x % field_size), y - (y % field_size));
							} else {
								send_add_obj(OBJ_CURSOR_LAST, CURSOR_LAST,
										x - (x % field_size), y - (y % field_size));
								have_last = 1;
							}
							if (obj2 >= OBJ_PIECES_BEGIN) {
								send_move_obj(obj2, (9 + obj_out[obj2] % 2) * field_size,
										obj_out[obj2] / 2 * field_size);
							}
							send(MESSAGE_STRING, "Bu");
						}
						break;
						
					case 'u': /* surrender */
						{
							int is_remote;

							if(message_get(msg, MESSAGE_PART_SENDER_INFO,
										MESSAGE_SKIP,
										MESSAGE_INTEGER, &is_remote,
										MESSAGE_END))
							{
								if (is_remote) {
									send(MESSAGE_STRING, "Bst", MESSAGE_STRING, "Vyhrál jsi, soupeř se vzdal.");
								} else {
									send(MESSAGE_STRING, "Bst", MESSAGE_STRING, "Vzdal jsi se.");
								}
								send(MESSAGE_STRING, "Sgo");
								exit(0);
							}
						}
						break;
				}
				break;

			case 'B': /* Board */
				/*
				if (!game_started)
					break;
				*/

				switch (cmd[1]) {
					case 'b': /* mouse button */
						switch (cmd[2]) {
							case 'p': /* presed */
								if (message_get(msg, MESSAGE_PART_DATA,
											MESSAGE_SKIP,
											MESSAGE_INTEGER, &btn,
											MESSAGE_INTEGER, &obj,
											MESSAGE_INTEGER, &x,
											MESSAGE_INTEGER, &y,
											MESSAGE_END))
								{
									char *str;

									if (selected_obj) {
										if (btn == 1) {
											DBG_MSG(3, "Object %d moved to [ %d, %d ]", selected_obj, x, y);
											
											str = g_strdup_printf("Figurka %d na [ %d, %d ]", selected_obj, x, y);
											send(MESSAGE_STRING, "St", MESSAGE_STRING, str,
													MESSAGE_INTEGER, selected_obj,
													MESSAGE_INTEGER, obj,
													MESSAGE_INTEGER, x,
													MESSAGE_INTEGER, y);
											g_free(str);
										}
										
										send_delete_obj(OBJ_CURSOR_SELECT);
										selected_obj = 0;
										
									} else if (obj >= OBJ_PIECES_BEGIN && btn == 1) {
										selected_obj = obj;
										send_add_obj(OBJ_CURSOR_SELECT, CURSOR_SELECT,
												x - (x % field_size), y - (y % field_size));
										DBG_MSG(3, "Selected object: %d", selected_obj);
									}
									send(MESSAGE_STRING, "Bu");
								}
								break;
						}	
						break;
				}
				break;


			case 'O': /* Option */
				switch (cmd[1]) {
					case 'r':
						if (message_get(msg, MESSAGE_PART_DATA, MESSAGE_SKIP, MESSAGE_STRING, &cat, MESSAGE_STRING, &mod,
									MESSAGE_STRING, &opt, MESSAGE_STRING, &val, MESSAGE_END)) {
							DBG_MSG(2, "Received option value: [ %s :: %s :: %s ] = \"%s\"", cat, mod, opt, val);
							/*
							if (strcmp(cat, "main") == 0 && strcmp(mod, "game") == 0 && strcmp(opt, "my_role") == 0) {
							}
							*/
						}
				}
		}
	}
	return;
}


int main (void)
{
	MESSAGE *msg = NULL;
	int ch;
	
	DBG_MSG(1, "Initializing...");
	initialize_board();

	while ((ch = fgetc(stdin)) != EOF) {
		if (message_from_stream(0, 0, ch, &msg) == 1) {
			DBG_MSG(1, "Received message...");
			process_message(msg);
			message_destroy(msg);
			msg = NULL;
			DBG_MSG(1, "Message processed.");
		}
	}
	
	return 0;
}

/* vim:set encoding=utf8: */
