#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

#ifdef HAVE_SDL_MIXER
# include <SDL/SDL_mixer.h>
#endif

#include <math.h>

#include "timers.h"
#include "world_geometry.h"
#include "hut.h"
#include "bonus.h"
#include "mango.h"
#include "world_building.h"
#include "texture.h"
#include "world_geometry.h"
#include "sector.h"
#include "map.h"

#define TEMPS_MIN_RESPAWN 10 // in seconds

extern game_data_t *world;
extern player_t *player;
extern const char *pathMondes[4];
extern GLUquadricObj *quadratic;

const char *i_foyer = 
  {
    SHXMAN_DATA "textures/foyer.png",
  };

const char *i_Shmol[2] = 
  {
    SHXMAN_DATA "textures/characters/shmollux_0.png",
    SHXMAN_DATA "textures/characters/shmollux_1.png",
  };

int register_huts()
{
  hut_t *hut;
  world->huts = new hut_t [world->num_huts];
  if (!(world->huts))
    {
      fprintf(stderr, "\nFatal error : memory error.\n");
      exit(1);
    }

  for (int i=0; i < world->num_huts; i++)
    {
      hut = &world->huts[i];
      hut->square = world->hut_squares[i];
      hut->total_num_shmol = world->map[hut->square].paramSpecial;
      hut->num_shmol_here = hut->total_num_shmol;
      hut->pos_x = square_to_map_x(hut->square) * SCALE_FACTOR +1.5;
      hut->pos_z = square_to_map_z(hut->square) *SCALE_FACTOR +1.5;

      hut->status = ETAT_FONCTIONNE;
      hut->coordTriangles[0][0] = hut->pos_x - 1.5;
      hut->coordTriangles[0][1] = hut->pos_z - 1.5;
      hut->coordTriangles[1][0] = hut->coordTriangles[0][0];
      hut->coordTriangles[1][1] = hut->coordTriangles[0][1] + SCALE_FACTOR;
      hut->coordTriangles[2][0] = hut->coordTriangles[0][0] + SCALE_FACTOR;
      hut->coordTriangles[2][1] = hut->coordTriangles[1][1];
      hut->coordTriangles[3][0] = hut->coordTriangles[2][0];
      hut->coordTriangles[3][1] = hut->coordTriangles[0][1];

      hut->timer = new CHRONOMETRE;
      if (!(hut->timer))
	{
	  fprintf(stderr, "\nFatal error : memory error.\n");
	  exit(1);
	}

      hut->shmollux = new shmollux_t [hut->total_num_shmol];
      if (!(hut->shmollux))
	{
	  fprintf(stderr, "\nFatal error : memory error.\n");
	  exit(1);
	}

    }
  return 1;
}

void cleanup_huts_and_shmolluxes()
{
  hut_t *hut=0;
  for (int i=0; i < world->num_huts; i++)
    {
      hut = &world->huts[i];
      delete hut->timer; hut->timer=0;
      delete [] hut->shmollux; hut->shmollux = 0;
    }

  cleanup_huts_geom();

  delete [] world->huts;
  world->huts=0;
}

void load_huts_geom()
{
  hut_t *hut;
  quadratic = gluNewQuadric( );
/*  gluQuadricNormals( quadratic, GLU_SMOOTH ); */
  gluQuadricTexture( quadratic, GL_TRUE );

  for (int i=0; i < world->num_huts; i++)
    {
      hut = &world->huts[i];
      build_hut_texture(hut);

      hut->shmol_tex = new GLuint [2];
      LoadTexture(i_Shmol[0], &hut->shmol_tex[0]);
      LoadTexture(i_Shmol[1], &hut->shmol_tex[1]);
    }
}

void cleanup_huts_geom()
{
  hut_t *hut;
  for (int i=0; i < world->num_huts; i++)
    {
      hut = &world->huts[i];
      glDeleteTextures(2, hut->shmol_tex);
      delete [] hut->shmol_tex;
    }
  gluDeleteQuadric(quadratic);
}

void init_shmollux()
{
  hut_t *hut;
  shmollux_t *shmollux;
  for (int a=0; a < world->num_huts; a++)
    {
      hut = &world->huts[a];
      for (int i=0; i < hut->total_num_shmol; i++)
	{
	  shmollux = &hut->shmollux[i];
	  shmollux->need_choice = 1;
  	  for (int j=0; j<4; j++) {shmollux->possible_dir_before[j]=0;}
  	  shmollux->speed[ETAT_POURSUIVANT] = VITESSE_TRANS_V_SHMOL;
  	  shmollux->speed[ETAT_POURSUIVI] = VITESSE_TRANS_L_SHMOL;

  	  shmollux->my_address = hut->square;
  	  shmollux->square_last_test = hut->square;
  	  shmollux->pos_x = hut->pos_x;
	  shmollux->pos_z = hut->pos_z;
  	  shmollux->map_x = square_to_map_x(hut->square);
	  shmollux->map_z = square_to_map_z(hut->square);

	  shmollux->my_textures = new GLuint [2];
  	  shmollux->my_textures[0] = hut->shmol_tex[0];
  	  shmollux->my_textures[1] = hut->shmol_tex[1];

	  shmollux->status = ETAT_NAISSANCE;
	}
    }
}

void build_hut_texture(hut_t *hut)
{
  char *pathFloor=0;
  SDL_Surface *floor_s;
  SDL_Surface *hut_s;
  SDL_PixelFormat fmt;
  SDL_Rect dest;

  pathFloor = new char[255];
  sprintf(pathFloor, SHXMAN_DATA "textures/%s/sol%02d.png",
            pathMondes[world->country], world->map[hut->square].tex_sol);

  floor_s = IMG_Load(pathFloor);
  if (!(floor_s))
  {
    fprintf(stderr, "Unable to load %s: %s\n", pathFloor, SDL_GetError());
    exit(1);
  }

  hut_s = IMG_Load(i_foyer);
  if (!(hut_s))
  {
    fprintf(stderr, "Unable to load %s: %s\n", i_foyer, SDL_GetError());
    exit(1);
  }

  fmt = *(hut_s->format);
  fmt.Rmask = 16711680;
  fmt.Gmask = 65280;
  fmt.Bmask = 255;

  dest.x=0;
  dest.y=0;
  dest.h = floor_s->h;
  dest.w = floor_s->w;

  SDL_SetColorKey(hut_s,SDL_SRCCOLORKEY,SDL_MapRGB(&fmt,0,0,0));
  SDL_BlitSurface(hut_s, NULL, floor_s, &dest);

  SDL_FreeSurface(hut_s);
  Img2Texture(floor_s, &hut->hut_tex[0]);
  SDL_FreeSurface(floor_s);

  LoadTexture(pathFloor, &hut->hut_tex[1]);
  delete [] pathFloor;
}

void manage_shmollux_exit(hut_t *hut)
{
  int i=0;
  shmollux_t *shmollux;

  for (i=0; i < hut->total_num_shmol; i++)
    {
      shmollux = &hut->shmollux[i];
      if (shmollux->status == ETAT_NAISSANCE) 
	{
	  if (hut->doors_open) 
	    {
	      shmol_procreation(shmollux);
	      shmollux->status = ETAT_POURSUIVANT; // FIXME (pousuivant)
	      hut->doors_open=0;
	      hut->timer->resetTemps();
	      hut->num_shmol_here--;
	     // printf("A shmollux exits, %d remaining in the hut.\n", 
		     //hut->num_shmol_here);
	    }
	}
    }
}

void update_shmollux(hut_t *hut)
{
  int i=0;
  shmollux_t *shmollux;

  hut->timer->update_temps();
  if (hut->timer->getSecondes() >= TEMPS_MIN_RESPAWN) 
    {
      hut->doors_open=1;
    }
  
  for (i=0; i<hut->total_num_shmol; i++)
    {
      shmollux = &hut->shmollux[i];
      if ((shmollux->status != ETAT_NAISSANCE)
	&& (shmollux->status != ETAT_MORT))
	interaction_player_shmol(shmollux);

      if (hut->status == ETAT_FONCTIONNE) 
	{
	  switch (shmollux->status)
	    {
	    case ETAT_NAISSANCE:
	      break;

	    case ETAT_POURSUIVANT:
	      shmol_hunt(shmollux);
	      break;

	    case ETAT_POURSUIVI:
	      shmol_escape(shmollux);
	      break;

	    case ETAT_MORT:
	      return_home(shmollux);
	      hut->num_shmol_here++;
	      shmollux->status = ETAT_NAISSANCE;
	      break;

	    case ETAT_STOP:
	      break;
	    }

	  if (hut->num_shmol_here) manage_shmollux_exit(hut);
	}
    }
}

void draw_hut(hut_t *hut)
{
  glEnable(GL_TEXTURE_2D);
 
  if (hut->status==ETAT_DETRUIT) glBindTexture(GL_TEXTURE_2D, hut->hut_tex[1]);
  else glBindTexture(GL_TEXTURE_2D, hut->hut_tex[0]);
  glBegin(GL_TRIANGLES);

  glNormal3f(0, 1, 0);
  glTexCoord2f(0, 1);
  glVertex3f(hut->coordTriangles[0][0], 0,hut->coordTriangles[0][1]);
  glTexCoord2f(0, 0);
  glVertex3f(hut->coordTriangles[1][0], 0,hut->coordTriangles[1][1]);
  glTexCoord2f(1, 0);
  glVertex3f(hut->coordTriangles[2][0], 0,hut->coordTriangles[2][1]);

  glTexCoord2f(0, 1);
  glVertex3f(hut->coordTriangles[0][0], 0,hut->coordTriangles[0][1]);
  glTexCoord2f(1, 0);
  glVertex3f(hut->coordTriangles[2][0], 0,hut->coordTriangles[2][1]);
  glTexCoord2f(1, 1);
  glVertex3f(hut->coordTriangles[3][0], 0,hut->coordTriangles[3][1]);
  
  glEnd();
  glDisable(GL_TEXTURE_2D);
}

void change_hut_status(hut_t *hut,char new_status)
{
  if (hut->status != ETAT_DETRUIT) hut->status = new_status;
}

void change_shmol_status(hut_t *hut,char new_status)
{
  int i=0;
  shmollux_t *shmollux;

  for (i=0; i<hut->total_num_shmol; i++)
    {
      shmollux = &hut->shmollux[i];
      if ((shmollux->status != ETAT_MORT)
	  ||(shmollux->status != ETAT_NAISSANCE))
	{
	  shmollux->old_status = shmollux->status;
	  shmollux->status = new_status;
	}
    }
}

void shockWave(hut_t *hut, int range)
{
  double distance=0;
  shmollux_t *shmollux;

  for (int i=0; i< hut->total_num_shmol; i++)
    {
      shmollux = &hut->shmollux[i];
      distance = (player->pos_x-shmollux->pos_x)*(player->pos_x-shmollux->pos_x)
	+ (player->pos_z-shmollux->pos_z)*(player->pos_z-shmollux->pos_z);
      
      if (distance < ((double)range*(double)range))
	{
	  shmollux->status = ETAT_MORT;
	  player->score+=50;
	}
    }
}

void all_shmol_go_home()
{
  hut_t *hut;
  for (int i=0; i < world->num_huts; i++)
    {
      hut = &world->huts[i];
      hut->num_shmol_here = hut->total_num_shmol;
      for (int j=0; j < hut->total_num_shmol; j++)
	{
	  return_home(&hut->shmollux[j]);
	}
    }
}
