/*
    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 <float.h>
#include "MG_lib.h"
#include "WRMS_include.h"
#include <limits.h>

typedef struct WRMS_fire_selection
{
  VECTOR angle;
  int GUN;
  float intensity;
  POINT impact_point;
  float max_damage;
  SPRITE *worm_brain;
  DIRECTION initial_direction;
  DIRECTION worm_current_direction;
  int was_move_p;
  POINT bariers[2];
} WRMS_fire_selection;

WRMS_fire_selection best_wfs;

float
WRMS_ai_get_damages (SPRITE * attacker, SPRITE * gun, POINT impact_point)
{
  LIST *worms = WRMS_rules_worms ();
  WRMS_team *at = WRMS_worm_team (attacker);
  float out_dmg = 0.0f;

  while (worms)
    {
      SPRITE *worm = worms->value;
      WRMS_team *t = WRMS_worm_team (worm);
      float dmg = WRMS_gun_compute_damage (gun, worm, impact_point);

      if (at == t)
	{
	  dmg = -dmg;
	}

      out_dmg += dmg;
      worms = worms->node;
    }

  return out_dmg;
}

WRMS_fire_selection
WRMS_ai_target_best (SPRITE * worm, SPRITE * gun)
{
  WRMS_fire_selection out = best_wfs;	//{{0.0f , 0.0f} , 0 , 0.0f , {0 , 0}};

  VECTOR estimation = { 1.0f, 0.0f };
  VECTOR working_vect = vector_normalize (estimation, 1.0f);

  float working_power = 1.0f;	/* startup at max */

  int y;
  double max_radians = deg_to_radians (360.0f);

  int max_steps_count = (max_radians / ANGLE_STEP);
  POINT detonation_position;

  float best_damage = -FLT_MAX;

  out.intensity = working_power;

  for (y = 0; y < max_steps_count - 1; y++)
    {
      do
	{
	  detonation_position =
	    WRMS_gun_simulate_fire (gun, working_vect, working_power);
	  float current_damage =
	    WRMS_ai_get_damages (worm, gun, detonation_position);

	  if (current_damage > best_damage)
	    {
	      best_damage = current_damage;
	      out.angle = working_vect;
	      out.intensity = working_power;
	      out.impact_point = detonation_position;
	    }

	  working_power -= POWER_STEP;
	}
      while (working_power > 0.0f);

      working_power = 1.0f;
      working_vect =
	vector_normalize (rotate_vector (working_vect, -ANGLE_STEP), 1.0f);
    }

  out.GUN = 0;
  out.max_damage = best_damage;
  return out;
}

/* ai controller */
int
WRMS_ai_micro_brain (SPRITE * worm, WORM_STATES * ws, int gun_controlling_p)
{
  int change_p = 0;

  if (!worm)
    return change_p;

  /* heuristics for targeting */
  WRMS_fire_selection wfs;
  SPRITE *gun = WRMS_worm_get_current_gun (worm);

  wfs = best_wfs;

  if (!gun_controlling_p)
    {
      if (!best_wfs.worm_brain)
	{
	  best_wfs = WRMS_ai_target_best (worm, gun);
	  best_wfs.worm_brain = worm;

	  if (!best_wfs.was_move_p)
	    {
	      POINT wrm_mid = sprite_mid (worm);

	      printf ("ai: initing direction\n");
	      /* find the nearest enemy worm */
	      LIST *wrm = WRMS_rules_worms ();
	      float nearest = FLT_MAX;
	      WRMS_team *my_team = WRMS_worm_team (worm);
	      VECTOR v = { 0, 0 };

	      while (wrm)
		{
		  SPRITE *worm_e = wrm->value;
		  if (worm_e && (WRMS_worm_team (worm_e) != my_team))
		    {
		      POINT e_mid = sprite_mid (worm_e);
		      VECTOR v_wrms = vector_from_points (wrm_mid, e_mid);
		      float len = vector_length (v_wrms);

		      if (len < nearest)
			{
			  v = v_wrms;
			  nearest = len;
			}
		    }
		  wrm = wrm->node;
		}

	      best_wfs.worm_current_direction = (v.x < 0 ? LEFT : RIGHT);
	      best_wfs.initial_direction = best_wfs.worm_current_direction;
	    }
	}

      if (best_wfs.max_damage < WRMS_AI_DAMAGE_THRESHOLD)
	{
	  SDL_Rect landscape_r = WRMS_landscape_get ()->dest;
	  DIRECTION d = best_wfs.worm_current_direction;
	  int move_style = JUMPING;
	  best_wfs.was_move_p = 1;
	  int border = -1;

	  /* check for landscape borders - dangerous */
	  if (d == RIGHT)
	    {
	      if ((worm->dest.x - landscape_r.x) > 0.8 * (landscape_r.w))
		{
		  d = LEFT;
		  best_wfs.bariers[1] = sprite_mid (worm);
		  border = RIGHT;
		}
	    }
	  else
	    {
	      if (worm->dest.x - landscape_r.x < 0.2 * (landscape_r.w))
		{
		  d = RIGHT;
		  best_wfs.bariers[0] = sprite_mid (worm);
		  border = LEFT;
		}
	    }

	  /* check for looping worm */
	  if (MG_get_key (worm, "top_col"))
	    {
	      d = ws->direction;
	      POINT wrmm = sprite_mid (worm);

	      if (d == LEFT)
		{
		  VECTOR lrb = vector_from_points (wrmm, best_wfs.bariers[1]);
		  if (vector_length (lrb) > 100)
		    best_wfs.bariers[0] = wrmm;
		}
	      else
		{
		  VECTOR lrb = vector_from_points (wrmm, best_wfs.bariers[0]);
		  if (vector_length (lrb) > 100)
		    best_wfs.bariers[1] = wrmm;
		}

	      d = (d == LEFT ? RIGHT : LEFT);
	      move_style = IDLING;
	    }

	  int lbarier_p = (best_wfs.bariers[0].x != INT_MIN &&
			   best_wfs.bariers[0].x != INT_MIN);
	  int rbarier_p = (best_wfs.bariers[1].x != INT_MIN &&
			   best_wfs.bariers[1].x != INT_MIN);

	  if (lbarier_p && rbarier_p)
	    {
	      /* mmm ... we can't move anywhere */
	      /* destroy one of the bariers */
	      best_wfs.max_damage = 2 * WRMS_AI_DAMAGE_THRESHOLD;
	      /* destroy the farther */
	      POINT lb = best_wfs.bariers[0];
	      POINT rb = best_wfs.bariers[1];
	      POINT wmd = sprite_mid (worm);
	      VECTOR l = vector_from_points (wmd, lb);
	      VECTOR r = vector_from_points (wmd, rb);

	      float llen = vector_length (l);
	      float rlen = vector_length (r);

	      if (llen < 100 && rlen < 100)
		{
		  //nothing to do we have to wait :/
		  ws->action = IDLING;
		  best_wfs.worm_brain = NULL;
		  return 1;
		}

	      if (vector_length (l) > vector_length (r))
		{
		  l.y -= 0.5f * worm->dest.h;
		  best_wfs.angle = vector_normalize (l, 1.0f);
		}
	      else
		{
		  r.y -= 0.5f * worm->dest.h;
		  best_wfs.angle = vector_normalize (r, 1.0f);
		}
	      best_wfs.intensity = 1.0f;
	      return 0;
	    }
	  else if (lbarier_p && !rbarier_p)
	    {
	      d = RIGHT;
	    }
	  else if (rbarier_p && !lbarier_p)
	    {
	      d = LEFT;
	    }

	  best_wfs.worm_current_direction = d;
	  ws->direction = best_wfs.worm_current_direction;

	  if (move_style == MOVING)
	    ws->action = MOVING;
	  else
	    {
	      if (move_style == JUMPING && (ws->action != JUMPING))
		ws->action = JUMPING;
	      else
		ws->action = IDLING;
	    }

	  change_p = 1;

	  best_wfs.worm_brain = NULL;
	  return 1;
	}
      else
	{
	  ws->action = IDLING;

	  if (best_wfs.angle.x < 0.0f)
	    ws->direction = LEFT;
	  else
	    ws->direction = RIGHT;
	  change_p = 1;
	}
    }
  else
    {
      if (wfs.max_damage < WRMS_AI_DAMAGE_THRESHOLD)
	return 0;

      DIRECTION dir = WRMS_gun_get_direction (gun);

      /* while not set it correctly set it through iterations */
      /* first change angle */
      VECTOR current_angle = WRMS_gun_get_angle (gun);
      double angle = vector_angle (current_angle);
      double needed_angle = vector_angle (wfs.angle);

      if (angle < (needed_angle - (ANGLE_STEP)))
	{
	  WRMS_gun_set_angle (gun, WRMS_gun_decrease_angle (gun), dir);
	  return 1;
	}
      else if (angle > needed_angle + (ANGLE_STEP))
	{
	  WRMS_gun_set_angle (gun, WRMS_gun_increase_angle (gun), dir);
	  return 1;
	}

      /* ok ... now we have good angle */
      /* so let set up power */
      double current_power = WRMS_gun_get_power (gun);
      double needed_power = wfs.intensity;

      if (current_power < needed_power - POWER_STEP / 2)
	{
	  WRMS_gun_increase_power (gun);
	  return 1;
	}

      /* all is set go to fire */

      WRMS_gun_set_angle (gun, wfs.angle, WRMS_gun_get_direction (gun));
      //WRMS_gun_set_power( gun , wfs.intensity );
      WRMS_gun_fire (worm);
      WRMS_arrow_unset ();

      return 1;
    }

  return change_p;
}

void
WRMS_ai_reset ()
{
  printf ("AI reseted\n");
  //  current_victim = NULL;
  memset (&best_wfs, 0, sizeof (WRMS_fire_selection));
  best_wfs.bariers[0] = (POINT)
  {
  INT_MIN, INT_MIN};
  best_wfs.bariers[1] = (POINT)
  {
  INT_MIN, INT_MIN};

}
