#include "game.h"
#include "mathutils.h"
#include "drawutils.h"
#include "debug.h"
#include "itos.h"
#include <SDL.h>


Game::Game(stack<GameState*>* state_stack, SDL_Surface* display)
    : GameState(state_stack, display)
{
    background = NULL;
    font = NULL;

    attacker_icon = NULL;
    defender_icon = NULL;
    producer_icon = NULL;
}


Game::~Game()
{
    if (background != NULL)
	SDL_FreeSurface(background);
    if (font != NULL)
	TTF_CloseFont(font);

    for (list<MenuButton*>::iterator cursor = buttons.begin();
	 cursor != buttons.end(); cursor++)
    {
	delete *cursor;
    }
}


bool Game::init()
{
    background = DrawUtils::load("background.bmp");
    font = TTF_OpenFont("res/LiberationSans-Regular.ttf", 12);
    attacker_icon = DrawUtils::load("attacker_icon.bmp");
    defender_icon = DrawUtils::load("defender_icon.bmp");
    producer_icon = DrawUtils::load("producer_icon.bmp");

    if (background == NULL || font == NULL || attacker_icon == NULL ||
	defender_icon == NULL || producer_icon == NULL)
    {
	debug("Game::init(): error: Couldn't load some resource(s)");
	return false;
    }

    DrawUtils::transpare(attacker_icon);
    DrawUtils::transpare(defender_icon);
    DrawUtils::transpare(producer_icon);

    int row1 = display->h - 95;
    int row2 = display->h - 65;
    int row3 = display->h - 35;
    int col1 = 155;
    int col2 = 255;
    int col3 = 355;
    int col4 = 455;

    buttons.push_back(new MenuButton("Move (m)", font, col1, row1,
				     BUTTON_MOVE));
    buttons.push_back(new MenuButton("Build (b)", font, col1, row2,
				     BUTTON_BUILD));
    buttons.push_back(new MenuButton("Attack (a)", font, col1, row3,
				     BUTTON_ATTACK));
    buttons.push_back(new MenuButton("Attacker (t)", font, col2, row1,
				     BUTTON_BUILD_ATTACKER));
    buttons.push_back(new MenuButton("Defender (d)", font, col2, row2,
				     BUTTON_BUILD_DEFENDER));
    buttons.push_back(new MenuButton("Producer (p)", font, col2, row3,
				     BUTTON_BUILD_PRODUCER));
    buttons.push_back(new MenuButton("End Turn (e)", font, col4, row3,
				     BUTTON_END_TURN));


    return GameState::init();
}


void Game::render()
{
    int range = data.get_range();
    int range_colour = 0x888888;

    switch(data.get_mode())
    {
    case MODE_BUILD:
	range_colour = 0x0000ff;
	break;
    case MODE_MOVE:
	range_colour = 0x00ff00;
	break;
    case MODE_ATTACK:
	range_colour = 0xff0000;
	break;
    }

    // Background image first
    DrawUtils::draw(display, background, 0, 0);

    // Now paint on the targeting circle
    if (data.get_current_vertex(true) != NULL)
    {
	GameVertex* v = data.get_current_vertex();
	DrawUtils::draw_circle_filled(display, v->x, v->y, range,
				      range_colour);
    }

    // First draw the edges, so that they don't obscure any data
    list<Vertex*> vertices = data.get_vertices();
    for (list<Vertex*>::iterator cursor = vertices.begin();
	 cursor != vertices.end(); cursor++)
    {
	Vertex* v = *cursor;

	for (list<Vertex*>::iterator subcursor = v->neighbors.begin();
	     subcursor != v->neighbors.end(); subcursor++)
	{
	    Vertex* v1 = *subcursor;
	    DrawUtils::draw_line(display, v->x, v->y, v1->x, v1->y, 2,
				 v->colour);
	}
    }

    // highlight the selected vertex and write info about it
    if (data.get_current_vertex() != NULL)
    {
	GameVertex* v = data.get_current_vertex();
	DrawUtils::draw_circle(display, v->x, v->y, v->r + 5, 0x000000);
	draw_stats(v);
    }

    // Draw each node
    for (list<Vertex*>::iterator cursor = vertices.begin();
	 cursor != vertices.end(); cursor++)
    {
	GameVertex* v = dynamic_cast<GameVertex*>(*cursor);
	draw_node(v);
    }

    // draw the rest of the bottom menu

    // horizontal line across the whole thing
    DrawUtils::draw_line(display, 0, display->h - 100,
			 display->w, display->h - 100, 2, 0x000000);

    // vertical lines to separate info panes from button pane
    DrawUtils::draw_line(display, 150, display->h - 100, 150, display->h, 2,
			 0x000000);
    DrawUtils::draw_line(display, 540, display->h - 100, 540, display->h, 2,
			 0x000000);
    DrawUtils::draw_line(display, display->w - 100, display->h - 100,
			 display->w - 100, display->h, 2,
			 0x000000);
    
    for (list<MenuButton*>::iterator cursor = buttons.begin();
	 cursor != buttons.end(); cursor++)
    {
	MenuButton* button = *cursor;
	
	if (!(button->get_action() & BUTTON_END_TURN) &&
	    (data.get_current_vertex() == NULL ||
	     data.get_current_vertex()->player != data.get_turn()))
	    continue;

	if ((button->get_action() & (BUTTON_BUILD_ATTACKER |
				     BUTTON_BUILD_DEFENDER |
				     BUTTON_BUILD_PRODUCER)) &&
	    data.get_mode() != MODE_BUILD)
	    continue;

	draw_button(button);
    }

    draw_player_info();

    SDL_Flip(display);
}


void Game::draw_button(MenuButton* button)
{
    int colour = 0x000000;
    ButtonAction action = button->get_action();
    Mode mode = data.get_mode();
    VertexType build_type = data.get_build_type();

    // fixme - there's really got to be a better way...
    if ((action == BUTTON_BUILD && mode == MODE_BUILD) ||
	(action == BUTTON_ATTACK && mode == MODE_ATTACK) ||
	(action == BUTTON_MOVE && mode == MODE_MOVE) ||
	(action == BUTTON_BUILD_ATTACKER && build_type == VERTEX_ATTACKER) ||
	(action == BUTTON_BUILD_DEFENDER && build_type == VERTEX_DEFENDER) ||
	(action == BUTTON_BUILD_PRODUCER && build_type == VERTEX_PRODUCER)
	)
	colour = 0x0000ff;
    else if (button->is_at(cursor_x, cursor_y)) colour = 0xff0000;

    button->draw(display, colour);
}


void Game::draw_node(GameVertex* v)
{
    DrawUtils::draw_circle_filled(display, v->x, v->y, v->r,
				  v->colour);

    DrawUtils::draw_text(display, itos(v->score), v->x, v->y, font,
			 0x00ff00, true, true);

    switch (v->type)
    {
    case VERTEX_ATTACKER:
	DrawUtils::draw(display, attacker_icon, v->x + 5, v-> y + 5);
	break;
    case VERTEX_DEFENDER:
	DrawUtils::draw(display, defender_icon, v->x + 5, v-> y + 5);
	break;
    case VERTEX_PRODUCER:
	DrawUtils::draw(display, producer_icon, v->x + 5, v-> y + 5);
	break;
    }
}


void Game::draw_player_info()
{
    Player* player = data.get_turn();

    DrawUtils::draw_text(display, player->get_name(), 10, display->h - 95,
			 font);

    string temp = "Energy: ";
    temp += itos(player->get_energy());
    DrawUtils::draw_text(display, temp, 10, display->h - 80, font);
}


void Game::handle_button_press(ButtonAction action)
{
    switch (action)
    {
    case BUTTON_BUILD:
	data.set_mode(MODE_BUILD);
	break;
    case BUTTON_ATTACK:
	data.set_mode(MODE_ATTACK);
	break;
    case BUTTON_MOVE:
	data.set_mode(MODE_MOVE);
	break;
    case BUTTON_BUILD_ATTACKER:
	data.set_build_type(VERTEX_ATTACKER);
	break;
    case BUTTON_BUILD_DEFENDER:
	data.set_build_type(VERTEX_DEFENDER);
	break;
    case BUTTON_BUILD_PRODUCER:
	data.set_build_type(VERTEX_PRODUCER);
	break;
    case BUTTON_END_TURN:
	data.toggle_turn();
	break;
    }
}


void Game::draw_stats(GameVertex* v)
{
    int line_num = 0;
    int line_height = 14;
    int x = 550;
    int y = display->h - 95;
    int adj_y = y;

    DrawUtils::draw_text(display, "owner:", x, adj_y, font);
    DrawUtils::draw_text(display, v->player->get_name(), x + 50, adj_y, font);

    line_num++;
    adj_y = y + line_num * line_height;
    DrawUtils::draw_text(display, "type:", x, adj_y, font);
    string type;
    switch(v->type)
    {
    case VERTEX_ATTACKER:
	type = "attacker";
	break;
    case VERTEX_DEFENDER:
	type = "defender";
	break;
    case VERTEX_PRODUCER:
	type = "producer";
	break;
    }
    DrawUtils::draw_text(display, type, x + 50, adj_y, font);

    line_num++;
    adj_y = y + line_num * line_height;
    DrawUtils::draw_text(display, "atk:", x, adj_y, font);
    DrawUtils::draw_text(display, itos(v->calculate_attack()),
			 x + 50, adj_y, font);
    
    line_num++;
    adj_y = y + line_num * line_height;
    DrawUtils::draw_text(display, "armor:", x, adj_y, font);
    DrawUtils::draw_text(display, itos(v->calculate_armor()),
			 x + 50, adj_y, font);

    line_num++;
    adj_y = y + line_num * line_height;
    DrawUtils::draw_text(display, "hp:", x, adj_y, font);
    DrawUtils::draw_text(display, itos(v->score), x + 50, adj_y, font);

    if (v->type == VERTEX_PRODUCER)
    {
	line_num++;
	adj_y = y + line_num * line_height;
    
	DrawUtils::draw_text(display, "energy:", x, adj_y, font);
	DrawUtils::draw_text(display, "25", x + 50, adj_y, font);
    }
}


void Game::on_lbutton_down(int x, int y)
{
    for (list<MenuButton*>::iterator cursor = buttons.begin();
	 cursor != buttons.end(); cursor++)
    {
	MenuButton* button = *cursor;
	if (button->is_at(x, y)) handle_button_press(button->get_action());
    }

    if (y > display->h - 110) return;
    if (!data.endgame()) data.handle_click(x, y);
}


void Game::on_rbutton_down(int mX, int mY)
{
    data.clear_current_vertex();
}


void Game::on_key_down(SDLKey sym, SDLMod mod, Uint16 unicode)
{
    if (sym == SDLK_q && mod & KMOD_CTRL) throw StateExit();
    else if (sym == SDLK_a) data.set_mode(MODE_ATTACK);
    else if (sym == SDLK_m) data.set_mode(MODE_MOVE);
    else if (sym == SDLK_b) data.set_mode(MODE_BUILD);
    else if (sym == SDLK_d) data.set_build_type(VERTEX_DEFENDER);
    else if (sym == SDLK_p) data.set_build_type(VERTEX_PRODUCER);
    else if (sym == SDLK_t) data.set_build_type(VERTEX_ATTACKER);
    else if (sym == SDLK_s || sym == SDLK_ESCAPE) data.set_mode(MODE_SELECT);
    else if (sym == SDLK_e) data.toggle_turn();

#ifdef DEBUG
    if (sym == SDLK_d && mod & (KMOD_ALT | KMOD_CTRL)) print_debug_info();
#endif
}


void Game::on_mouse_move(int mX, int mY, int relX, int relY, bool left, bool right, bool middle)
{
    cursor_x = mX;
    cursor_y = mY;
}


#ifdef DEBUG
void Game::print_debug_info()
{
    fprintf(stderr, "Mode: %d\n", data.get_mode());
    fprintf(stderr, "Turn: %s\n", data.get_turn()->get_name().c_str());
}
#endif