/*  The Blue Mango Quest
 *  Copyright (c) Clément 'phneutre' Bourdarias (code)
 *                   email: phneutre@users.sourceforge.net
 *                Guillaume 'GuBuG' Burlet (graphics)
 *                   email: gubug@users.sourceforge.net
 *
 *  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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.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"
#include "geom_bonus.h"
#include "hud.h"
#include "config_file.h"
#include "sounds.h"
#include "map_seeking.h"
#include "menus.h"

player_t *player;
game_data_t *world;
options_t *options;

extern CUBE *polys;

const char *pathMondes[4] = {
    "indus",
    "caraibes",
    "mines",
    "inconnu"
};

B_VIE *b_vie;
B_NUIT *b_nuit;
B_HASARD *b_hasard;
B_GLACON *b_glacon;
B_COUPDEBOL *b_coupdebol;
B_ONDEDECHOC *b_ondedechoc;
B_BOUCLIER *b_bouclier;
B_PERDBONUS *b_perdbonus;
B_ARMAGGEDON *b_armaggedon;
B_RAPIDE *b_rapide;
B_LENT *b_lent;
B_ULTRAPOINTS *b_ultrapoints;
B_INVERTTOUCHES *b_inverttouches;
B_PLAFOND *b_plafond;
B_FOG *b_fog;
B_MALUSMAP *b_malusmap;
B_ANTIBOITES *b_antiboites;
B_FREEZESHX *b_freezeshx;

int register_world()
{ 
  player = new player_t;
  world = new game_data_t;

  world->game_sync = new SYNCHRONIZER;
  world->game_timer = new CHRONOMETRE;

  world->num_dituboites=0;
  options = new options_t;
  fill_default_options();

  return 1;
}


void load_shared_objects()
{
  printf("\n-- STEP 2: Loading shared objects -- \n");

  printf("Loading menus... ");
  load_menu_main();
  load_menu_skirmish();
  load_menu_credits();
  load_menu_options();
  load_menu_campaign();
  load_menu_ingame();
  printf("done!\n");

  printf("Loading bonus... ");
  load_bonus();
  printf("done!\n");

  printf("Loading misc sounds and musics... ");
  load_misc_sounds();
  load_music();
  printf("done!\n");

  printf("Loading HUD... ");
  load_hud();
  printf("done!\n");

  world->warning_radius=options->proximity_setting*options->proximity_setting;

#ifdef HAVE_SDL_MIXER
  if (options->use_sound) {
    Mix_Volume(-1, options->sound_volume * 128 / 100);
    Mix_VolumeMusic(options->music_volume * 128 / 100);
  }
#endif

  world->game_paused=0;
  world->in_ingame_menu=0;
  world->need_to_restart_map=1; 
  /* must be initialized to 1 for the first while test */

  world->mat_amb_diff[0] = 0.937;
  world->mat_amb_diff[1]= 0.937;
  world->mat_amb_diff[2] = 0.937;
  world->mat_amb_diff[3] = 1.0;

}

void unload_shared_objects()
{
  printf("\n-- STEP 4: Destroying all shared things -- \n");
  printf("Deleting bonus... ");
  cleanup_bonus();
  delete [] world->tab_bonus;
  printf("done!\n");

  printf("Deleting HUD... ");
  cleanup_hud();
  printf("done!\n");

  printf("Deleting menus... ");
  cleanup_map_names();
  cleanup_menu_options();
  cleanup_menu_credits();
  cleanup_menu_skirmish();
  cleanup_menu_campaign();
  cleanup_menu_ingame();
  cleanup_menu_main();
  printf("done!\n");

  delete world->game_sync;
  delete world->game_timer;

  delete player;
  delete world;
}


void register_sectors(int number)
{
  world->sectors = new sector_t [number];
  if (!(world->sectors))
    {
      fprintf(stderr, "\nFatal error : memory error.\n");
      exit(1);
    }
  for (int i=0; i< number; i++) world->sectors[i].visible=0;
}

void register_portals(int number)
{ 
  world->portals = new portal_t [number];
  if (!(world->portals))
    {
      fprintf(stderr, "\nFatal error : memory error.\n");
      exit(1);
    }
  for (int i=0; i< number; i++)
    world->portals[i].visible=0;

}

void register_portals_indices(int sector_indice)
{
  int number = world->sectors[sector_indice].num_portals;
  world->sectors[sector_indice].portal_indices = new int [number];
  if (!(world->sectors[sector_indice].portal_indices))
    {
      fprintf(stderr, "\nFatal error : memory error.\n");
      exit(1);
    }
}

void register_triangles(int sector_indice)
{
  int number = world->sectors[sector_indice].num_triangles;
  world->sectors[sector_indice].triangles = new triangle_t [number];
  if (!(world->sectors->triangles))
    {
      fprintf(stderr, "\nFatal error : memory error.\n");
      exit(1);
    }
}

void register_bonus(int sector_indice)
{
  int number = world->sectors[sector_indice].num_bonus;
  world->sectors[sector_indice].bonus = new bonus_t [number];
  if (!(world->sectors->bonus))
    {
      fprintf(stderr, "\nFatal error : memory error.\n");
      exit(1);
    }

  for (int i=0; i < number; i++)
    {
      world->sectors[sector_indice].bonus[i].still_here = 1;
    }
}

void load_world_textures()
{
  int i=0, j=0, tex_number=0;
  SDL_Surface *images[36];
  char **paths = new char *[36];

  for (i = 0; i < 36; i++)
  {
    images[i] = 0;
  }

  for (i = 0; i < 36; i++)
  {
    paths[i] = new char[255];

    if (i<12) 
      sprintf(paths[i], SHXMAN_DATA "textures/%s/sol%02d.png",
            pathMondes[world->country], i);
    if ( (i>=12) && (i < 24)) 
      sprintf(paths[i], SHXMAN_DATA "textures/%s/pla%02d.png",
            pathMondes[world->country], i - 12);

    if ( (i>=24) && (i < 36)) 
      sprintf(paths[i], SHXMAN_DATA "textures/%s/mur%02d.png",
            pathMondes[world->country], i - 24);
  }

   for (i=0; i<world->num_sectors; i++)
    {
      for (j = 0; j < world->sectors[i].num_triangles; j++)
	{
	  tex_number = world->sectors[i].triangles[j].texture;
	  if (tex_number > -1)
	    {
	      if (!(images[tex_number]))
		{
		   if (!(images[tex_number] = ImageLoad(paths[tex_number])))
		    {
		      fprintf(stderr, "Error loading %s\n",paths[tex_number]);
		      SDL_Quit();
		      exit(1);
		    }
		}
	    }
	}
    }
  
  for (i = 0; i < 36; i++)
    {
      delete[]paths[i];
    }
  delete[]paths;

   glGenTextures(36, world->base_tex);

  for (i = 0; i < 36; i++)
  {
    if (images[i] != 0)
    {
      glBindTexture(GL_TEXTURE_2D, world->base_tex[i]);
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                      GL_LINEAR_MIPMAP_LINEAR);

      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);      
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

      gluBuild2DMipmaps(GL_TEXTURE_2D, 3, images[i]->w,
                        images[i]->h, GL_RGB, GL_UNSIGNED_BYTE,
                        images[i]->pixels);
      

    SDL_FreeSurface(images[i]);
    images[i] = 0;

    }
  }
}

void init_characters()
{
  player->score=0;
  player->num_lives = world->num_lives_beginning;

  player->teleporting=-1;

  player->status = STATUS_WAITING;

  player->stockBonus[2]=0;
  player->stockBonus[0]=0;
  player->stockBonus[3]=0;
  player->stockBonus[1]=0;
  player->paramStocks[2]=0;
  player->paramStocks[0]=0;
  player->paramStocks[3]=0;
  player->paramStocks[1]=0;

  player->rotat_speed[0]=VITESSE_ROTAT_MARCHE;
  player->rotat_speed[1]=VITESSE_ROTAT_COURSE;

  player->trans_speed[0]=VITESSE_TRANS_MARCHE;
  player->trans_speed[1]=VITESSE_TRANS_COURSE;

  player->theKeys[KEY_UP]=SDLK_UP;
  player->theKeys[KEY_DOWN]=SDLK_DOWN;
  player->theKeys[KEY_LEFT]=SDLK_LEFT;
  player->theKeys[KEY_RIGHT]=SDLK_RIGHT;

  player->x_rot=0;

  player->pos_y[AU_SOL] = 1.1;
  player->pos_y[AU_PLAFOND] = 3.0;

  reset_player_pos(); 

  player->sees_minimap = 1;

  player->run = 1; // player now always runs (0.6.2 change)

  player->highlander = 0;
  player->selected_stocked_bonus=-1;

  for (int i=0; i < NUM_BONUS; i++)
    {
      world->tab_bonus[i]->actif=0;
    }

  world->current_bonus = -1;
  world->bonus_rotat = 0;
  world->bonus_updown = 0;
  world->winning_post_object.updown=0;
  world->bonus_up=1;
}

void reset_player_pos()
{
  player->elevation=AU_SOL;

  switch (world->map[world->start_square].special)
    {
    case SHMIXMAN_G: player->y_rot=90; 
      break;
    case SHMIXMAN_D: player->y_rot=270;
      break;
    case SHMIXMAN_H: player->y_rot=0;
      break;
    case SHMIXMAN_B: player->y_rot=180;
      break;
    }

  player->square = world->start_square;

  player->map_x = square_to_map_x(player->square);
  player->map_z = square_to_map_z(player->square);

  player->pos_x = player->map_x * SCALE_FACTOR + 1.5;
  player->pos_z = player->map_z * SCALE_FACTOR + 1.5;

  player->u.x = -sin(player->y_rot * pi_sur_180);
  player->u.z = -cos(player->y_rot * pi_sur_180);

  player->x_rot = 0;
}

void load_bonus()
{  
  GLint list_shmixgum = 0;
  GLint list_ditubox = 0;
  GLint list_bonus = 0;

  list_shmixgum = genListeStar();
  //list_ditubox = genListeDemiSphere();
  //list_ditubox = genListeTuna();
  list_ditubox = genListeTunasBox();
  list_bonus = genListeCubeRond();

  world->dituboite = new DITUBOITE();
  b_vie = new B_VIE;
  b_nuit = new B_NUIT;
  b_hasard = new B_HASARD;
  b_glacon = new B_GLACON;
  b_coupdebol = new B_COUPDEBOL;
  b_ondedechoc = new B_ONDEDECHOC;
  world->b_shmixgomme = new B_SHMIXGOMME;
  b_bouclier = new B_BOUCLIER;
  b_perdbonus = new B_PERDBONUS;
  b_armaggedon = new B_ARMAGGEDON;
  b_rapide = new B_RAPIDE;
  b_lent = new B_LENT;
  world->b_stoptemps = new B_STOPTEMPS;
  b_ultrapoints = new B_ULTRAPOINTS;
  b_inverttouches = new B_INVERTTOUCHES;
  b_plafond = new B_PLAFOND;
  b_fog = new B_FOG;
  b_malusmap = new B_MALUSMAP;
  b_antiboites = new B_ANTIBOITES;
  b_freezeshx = new B_FREEZESHX;

  world->tab_bonus = new BONUS * [NUM_BONUS];

  world->tab_bonus[E_VIE] = b_vie;
  world->tab_bonus[E_NUIT] = b_nuit;
  world->tab_bonus[E_HASARD] = b_hasard;
  world->tab_bonus[E_GLACON] = b_glacon;
  world->tab_bonus[E_COUPDEBOL] = b_coupdebol;
  world->tab_bonus[E_ONDEDECHOC] = b_ondedechoc;
  world->tab_bonus[E_SHMIXGOMME] = world->b_shmixgomme;
  world->tab_bonus[E_BOUCLIER] = b_bouclier;
  world->tab_bonus[E_PERDBONUS] = b_perdbonus;
  world->tab_bonus[E_ARMAGGEDON] = b_armaggedon;
  world->tab_bonus[E_RAPIDE] = b_rapide;
  world->tab_bonus[E_LENT] = b_lent;
  world->tab_bonus[E_STOPTEMPS] = world->b_stoptemps;
  world->tab_bonus[E_ULTRAPOINTS] = b_ultrapoints;
  world->tab_bonus[E_INVERTTOUCHES] = b_inverttouches;
  world->tab_bonus[E_PLAFOND] = b_plafond;
  world->tab_bonus[E_FOG] = b_fog;
  world->tab_bonus[E_MALUSMAP] = b_malusmap;
  world->tab_bonus[E_ANTIBOITES] = b_antiboites;
  world->tab_bonus[E_FREEZESHX] = b_freezeshx;

  world->dituboite->construit(list_ditubox);
  for (int i=0; i < NUM_BONUS; i++)
    {
      if (i == E_SHMIXGOMME)
	world->tab_bonus[i]->construit(list_shmixgum);
      else
	world->tab_bonus[i]->construit(list_bonus);

      world->tab_bonus[i]->actif=0;
    }

  world->current_bonus = -1;
}

void cleanup_bonus()
{
  delete world->dituboite;
  delete b_vie ;
  delete b_nuit;
  delete b_hasard;
  delete b_glacon;
  delete b_coupdebol;
  delete b_ondedechoc;
  delete world->b_shmixgomme;
  delete b_bouclier;
  delete b_perdbonus;
  delete b_armaggedon;
  delete b_rapide;
  delete b_lent;
  delete world->b_stoptemps;
  delete b_ultrapoints;
  delete b_inverttouches;
  delete b_plafond;
  delete b_fog;
  delete b_malusmap;
  delete b_antiboites;
  delete b_freezeshx;
}
