/*
    Bazoo_worms the game
    Copyright (C) 2011  Pavel Prochazka

    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 3 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.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "MG_lib.h"
#include "WRMS_include.h"

SPRITE *_hud = NULL;

static void
remove_and_detach (SPRITE * self)
{
  MG_remove_sprite (self);
}

static void
hud_destroy (SPRITE * hud)
{
  LIST *wis = MG_get_key (hud, "wind_indicators");
  LIST *his = MG_get_key (hud, "life_indicators");

  MG_remove_list (wis, NULL);
  MG_remove_list (his, NULL);
  MG_remove_list (hud->attached_sprites, NULL);
  hud->attached_sprites = NULL;
}

static void
hud_clear (SPRITE * hud)
{
  SPRITE *clock = MG_get_key (hud, "clock");
  if (clock)
    {
      MG_remove_sprite (clock);
    }

  LIST *wis = MG_get_key (hud, "wind_indicators");
  MG_destructive_map (wis, (void (*)(void *)) remove_and_detach);

  LIST *his = MG_get_key (hud, "life_indicators");
  MG_destructive_map (his, (void (*)(void *)) remove_and_detach);

  SPRITE *fire_ind = MG_get_key (hud, "fire_indicator");
  MG_remove_sprite (fire_ind);

  hud_destroy (hud);
}

/* show remaining time, wind and swing */
char *
format_time (Uint32 i_time)
{
  Uint32 time = i_time;
  if (i_time > TIME_LIMIT / 1000)
    time = TIME_LIMIT / 1000;

  char *time_str = (char *) malloc (sizeof (char) * 12);
  if (time < 10)
    sprintf (time_str, "0%d", time);
  else
    sprintf (time_str, "%d", time);

  return time_str;
}

static void
clock_destroy (SPRITE * clock)
{
  free (MG_get_key (clock, "prev_time"));
  SDL_FreeSurface (clock->img);
}

static SDL_Surface *
clock_time (int time)
{
  char *txt = format_time (time);

  SDL_Surface *txt_surf = render_text (txt, CLOCK_TEXT_COLOR, 24, WRMS_FONT);

  free (txt);
  return txt_surf;
}

static void
clock_refresh (SPRITE * clock)
{
  int *time_prev = MG_get_key (clock, "prev_time");
  int now_time = WRMS_rules_remaining () / 1000;

  if (now_time != *time_prev)
    {
      SDL_Surface *s_prev = clock->img;
      *time_prev = now_time;
      MG_set_img (clock, clock_time (now_time));
      SDL_FreeSurface (s_prev);
    }
}

static SPRITE *
clock_make ()
{
  SPRITE *clock = MG_make_sprite (clock_time (0), NULL);

  MG_set_key (clock, "prev_time", make_int (-1));
  MG_install_callback (clock, "on_iter", clock_refresh);
  MG_install_callback (clock, "on_destroy", clock_destroy);

  clock->type = -1;

  return clock;
}

/* wind indicator */
static LIST *
wind_indicators_make (SPRITE * hud)
{
#define MAX_WIS 5.0f
  LIST *wis = NULL;
  VECTOR v = WRMS_wind_get ();

  double ratio = v.x / WIND_MAX_POWER;

  int wis_count = abs ((int) (MAX_WIS * ratio));
  int i = 0;

  for (; wis_count > 0; wis_count--)
    {
      SDL_Surface *s_wi = NULL;
      if (ratio < 0)
	{
	  s_wi = MG_get_img ("wind_ind_left." WRMS_PIXMAP_SUFFIX);
	}
      else
	{
	  s_wi = MG_get_img ("wind_ind_right." WRMS_PIXMAP_SUFFIX);
	}

      SPRITE *wi = MG_make_sprite (s_wi, NULL);
      MG_attach_sprite (hud, wi, 16 + (i * (wi->img->w + 8)), 4);
      MG_add (&wis, wi);
      i++;
    }

  return wis;
}

/* swing indicator */
#define SWING_MAX_WIDTH 168

static void
check_swing (SPRITE * self)
{
  SPRITE *active_worm = WRMS_rules_active_worm ();

  if (!active_worm)
    return;

  float power = WRMS_gun_get_power (WRMS_worm_get_gun (active_worm));

  int *prev_count = MG_get_key (self, "count");
  double k = (power / 1.0f);
  int cur_count = (int) (k * (float) SWING_MAX_WIDTH);

  if (cur_count != *prev_count)
    {
      *prev_count = cur_count;
      SDL_Rect r = { 0, 0, cur_count, self->img->h };

      SDL_FillRect (self->img,
		    &r,
		    SDL_MapRGB (self->img->format,
				(1.0f * k) * 255,
				(1.0f - (1.0f * k)) * 255, 0));
      MG_invalidate_rect (self->dest);

    }
}

static void
swing_clear (SPRITE * self)
{
  SDL_FreeSurface (self->img);
  free (MG_get_key (self, "count"));
}

static SPRITE *
swing_ind_make ()
{
  SDL_Surface *indicator = surface_new (SWING_MAX_WIDTH, 8, SDL_SRCCOLORKEY);

  SPRITE *out = MG_make_sprite (indicator, NULL);
  MG_set_key (out, "count", make_int (0));

  MG_install_callback (out, "on_iter", check_swing);
  MG_install_callback (out, "on_destroy", swing_clear);

  return out;
}

/* life indicator */
static void
hi_destroy (SPRITE * self)
{
  SDL_FreeSurface (self->img);
}

static SPRITE *
health_indicator_make (WRMS_team * t)
{
#define MAX_WIDTH 168
#define MAX_HEALTH 100
#define HI_HEIGHT 9

  int max_health = t->initial_teammates_count * MAX_HEALTH;
  int curr_health = WRMS_team_health (t);
  double w =
    (int) (((double) MAX_WIDTH) *
	   ((double) curr_health / (double) max_health));

  SDL_Surface *s = surface_new (w, HI_HEIGHT, SDL_SRCCOLORKEY);

  SDL_FillRect (s, NULL, SDL_MapRGB (s->format, 0, 0, 0));

  SDL_Rect r = rect (1, 1, s->w - 2, s->h - 2);
  SDL_FillRect (s, &r, SDL_MapRGB (s->format, t->c.r, t->c.g, t->c.b));

  SPRITE *out = MG_make_sprite (s, NULL);
  MG_install_callback (out, "on_destroy", hi_destroy);
  return out;
}

static LIST *
lifeindicators_make (SPRITE * hud)
{
  LIST *list = NULL;
  LIST *teams = WRMS_rules_teams ();

  int y = 12;

  while (teams)
    {
      WRMS_team *t = (WRMS_team *) teams->value;
      SPRITE *hi = health_indicator_make (t);
      MG_attach_sprite (hud, hi, (MG_get_machine ()->screen->w) - 190, y);
      MG_add (&list, hi);
      y += 10;

      teams = teams->node;
    }

  return list;
}


static void
on_turn (SPRITE * hud)
{
  hud_clear (hud);

  SPRITE *clock = clock_make ();
  MG_set_key (hud, "clock", clock);
  MG_attach_sprite (hud, clock, hud->img->w - clock->img->w - 22, 6);

  MG_set_key (hud, "wind_indicators", wind_indicators_make (hud));

  SPRITE *fi = swing_ind_make ();
  MG_set_key (hud, "fire_indicator", fi);
  MG_attach_sprite (hud, fi, 18, 28);

  LIST *li = lifeindicators_make (hud);
  MG_set_key (hud, "life_indicators", li);
}

SPRITE *
WRMS_hud_init ()
{
  _hud = NULL;

  _hud = MG_make_sprite (MG_get_img ("hud_bckg.bmp"), NULL);
  MG_install_callback (_hud, "on_turn", on_turn);
  MG_install_callback (_hud, "on_destroy", hud_destroy);

  MG_move_sprite (_hud, 30, 0);
  MG_send_msg (_hud, "on_turn");

  return _hud;
}

SPRITE *
WRMS_hud ()
{
  return _hud;
}
