/*  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 <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

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

#include "font.h"  


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

extern game_data_t *world;
extern hud_t *hud;

void load_map(char *filename)
{
  gzFile map_file=0;
  printf("+ Reading map file\n");

  if (!(map_file = gzopen(filename, "rb9")))
  {
    fprintf(stderr, "\nError opening file %s.\n", filename);
    exit(1);
  }

  if (verify_map(map_file) == 0)
    {
      fprintf(stderr, "\nError while verifying file %s.\n", filename);
    exit(1);
    }
  
  else printf("this seems to be good!\n");

  load_description(map_file);
  load_geometry(map_file);

  gzclose(map_file);
  map_file = 0;

  printf("+ Building world\n");
  printf(" Connecting sectors... ");
  connect_sectors();
  printf("done!\n");

  printf(" Loading world textures... ");
  load_world_textures();
  printf("done!\n");

  printf(" Loading huts, Shmolluxs and teleports... ");
  register_huts();
  load_huts_geom();

  register_teleports();
  load_teleports_geometry();

  register_winning_post();
  load_winning_post_geometry();
  printf("done!\n");

  load_map_minimap_only();

  reset_all_states();
}

void reset_all_states()
{
  init_shmollux();
  locate_dituboites();
  init_characters();

  hud_delete_all_messages();
}

void unload_map()
{
  printf("\n<-- Cleaning up map\n");
  printf(" Unloading map from memory... ");
  unload_description();
  unload_geometry();
  printf("done !\n");

  /* to be optimized (texture proxy ?)*/
  printf(" Unloading world textures... ");
  glDeleteTextures(36, world->base_tex);
  printf("done!\n");

  printf(" Deleting hut, shmollux and teleports... ");
  cleanup_huts_and_shmolluxes();

  cleanup_teleports();
  cleanup_winning_post();

  unload_map_minimap_only();
  delete [] world->teleports;
  printf("done!\n\n");

}

void unload_description()
{
  delete [] world->map;
  world->map = 0;
}

void unload_geometry()
{
  int i=0;
  for (i=0; i < world->num_sectors; i++)
    {
      delete [] world->sectors[i].portal_indices;
      world->sectors[i].portal_indices=0;

      delete [] world->sectors[i].triangles;
      world->sectors[i].triangles=0;

      delete [] world->sectors[i].bonus;
      world->sectors[i].bonus=0;
    }

  delete [] world->portals;
  world->portals = 0;

  delete [] world->sectors;
  world->sectors = 0;

}

int verify_map(gzFile the_file)
{
  int compatibility_n=0;
  char *verification=0;

  printf(" Verifying map... ");
  verification = new char[3];

  gzread(the_file, verification, sizeof(char)*3);

  if ((verification[0] != 'B') || (verification[1] != 'M')
      || (verification[2] != 'Q'))
  {
    printf("\nError: file is not a map for MangoQuest\n");
    delete[]verification;
    return 0;
  }
  delete[]verification;

  gzread(the_file,&compatibility_n, sizeof(int)*1);

  if (compatibility_n < COMPAT_NUMBER)
  {
    fprintf(stderr,"\nError: This map is not compatible with current version.\n");
    fprintf(stderr,"Load it in mangopeeler and save it to convert it.\n");
    fprintf(stderr,"You really should do it, or download the data package for your version.\n");
    //exit(1);
  }
  return 1;
}

void load_description(gzFile the_file)
{
  int j = 0, k = 0, i = 0;
  int *temp_data=0;

  world->finish_square = -1;

  printf(" Loading header and grid data... ");
  gzread(the_file,&world->size, sizeof(int)*1);
  gzread(the_file,&world->country, sizeof(int)*1);
  gzread(the_file,&world->time_limit, sizeof(int)*1);
  gzread(the_file,&world->num_huts, sizeof(int)*1);
  gzread(the_file,&world->num_shmolluxes, sizeof(int)*1);
  gzread(the_file,&world->num_lives_beginning, sizeof(int)*1);
  gzread(the_file,&world->finish_square, sizeof(int)*1);

  if (world->num_huts == 0)
  {
    fprintf(stderr, "\nFatal error: there is no Shmollux in here !\n");
    exit(1);
  }
  world->size_square = world->size * world->size;
  world->hut_squares = new int[world->num_huts];

  temp_data = new int[world->size_square * 7];
  gzread(the_file, temp_data, sizeof(int)* world->size_square * 7);

  world->map = new SQUARE[world->size_square];

  k = 0;
  for (j = 0; j < world->size_square; j++)
  {
    world->map[j].tex_sol = temp_data[k];
    world->map[j].tex_pla = temp_data[k + 1];
    world->map[j].tex_mur = temp_data[k + 2];
    world->map[j].bonus = temp_data[k + 3];
    world->map[j].paramBonus = temp_data[k + 4];
    world->map[j].special = temp_data[k + 5];
    world->map[j].paramSpecial = temp_data[k + 6];

    if ((world->map[j].special > -1)
        && (world->map[j].special <= SHMIXMAN_B))
    {
      world->start_square = j;
    }

    if (world->map[j].special == FINISH_POS)
    {
      if (world->finish_square != j) {
	fprintf(stderr, "!!WARNING!! Winning post is bad!\n");
	exit(1);
      }
    }

    if (world->map[j].special == FOYER)
    {
      if (i > world->num_huts)
      {
        fprintf(stderr, "\nFatal error : bad map.\n");
        exit(1);
      }
      world->hut_squares[i] = j;
      i++;
    }

    k += 7;
  }
  delete[]temp_data;
  printf("done!\n");
  if (world->finish_square >= 0) 
    printf(" This map contains a winning post on square %d\n",world->finish_square);
  else printf(" This map does not contain a winning square\n");


}

void load_geometry(gzFile the_file)
{
  int i=0;
  printf(" Loading geometry data... ");

  gzread(the_file, &world->total_num_portals, sizeof(int)*1);
  register_portals(world->total_num_portals);
  read_all_portals(the_file);
  
  gzread(the_file, &world->num_sectors, sizeof(int)*1);
  register_sectors(world->num_sectors);

  for (i=0; i < world->num_sectors; i++)
    {

      gzread(the_file, &world->sectors[i].xmin, sizeof(double)*1);
      gzread(the_file, &world->sectors[i].zmin, sizeof(double)*1);
      gzread(the_file, &world->sectors[i].xmax, sizeof(double)*1);
      gzread(the_file, &world->sectors[i].zmax, sizeof(double)*1);

      gzread(the_file, &world->sectors[i].num_portals, sizeof(int)*1);
      register_portals_indices(i);
      read_portals_numbers(the_file, i);

      gzread(the_file, &world->sectors[i].num_triangles, sizeof(int)*1);
      register_triangles(i);
      read_triangles(the_file, i);
      

      gzread(the_file, &world->sectors[i].num_bonus, sizeof(int)*1);
      register_bonus(i);
      read_bonus(the_file, i);

    }

  printf("done!\n");
  printf(" Map has %d sectors.\n", world->num_sectors);
}

void read_all_portals(gzFile the_file)
{
  for (int j=0; j < world->total_num_portals; j++)
    {
      gzread(the_file, &world->portals[j].x1, sizeof(double)*1);
      gzread(the_file, &world->portals[j].z1, sizeof(double)*1);
      gzread(the_file, &world->portals[j].x2, sizeof(double)*1);
      gzread(the_file, &world->portals[j].z2, sizeof(double)*1);
      gzread(the_file, &world->portals[j].TYPE, sizeof(char)*1);
      gzread(the_file, &world->portals[j].number, sizeof(int)*1);
    }

}

void read_portals_numbers(gzFile the_file, int indice)
{
  for (int j=0; j < world->sectors[indice].num_portals; j++)
    {
      gzread(the_file, &world->sectors[indice].portal_indices[j], sizeof(int)*1);
    }

}


void read_triangles(gzFile the_file, int indice)
{
  for (int j=0; j < world->sectors[indice].num_triangles; j++)
    {

      for (int k=0; k < 3; k++)
	{
	  gzread(the_file, &world->sectors[indice].triangles[j].vertex[k].x, 
		sizeof(double)*1);
	  gzread(the_file, &world->sectors[indice].triangles[j].vertex[k].y, 
		sizeof(double)*1);
	  gzread(the_file, &world->sectors[indice].triangles[j].vertex[k].z, 
		sizeof(double)*1);
	  gzread(the_file, &world->sectors[indice].triangles[j].vertex[k].u, 
		sizeof(double)*1);
	  gzread(the_file, &world->sectors[indice].triangles[j].vertex[k].v, 
		sizeof(double)*1);
	}
      gzread(the_file, &world->sectors[indice].triangles[j].normal_x, 
	    sizeof(double)*1);
      gzread(the_file, &world->sectors[indice].triangles[j].normal_y, 
	    sizeof(double)*1);
      gzread(the_file, &world->sectors[indice].triangles[j].normal_z, 
	    sizeof(double)*1);
      gzread(the_file, &world->sectors[indice].triangles[j].texture, 
	    sizeof(int)*1);
      gzread(the_file, &world->sectors[indice].triangles[j].type, 
	    sizeof(char)*1);
    }
}

void read_bonus(gzFile the_file, int indice)
{
  for (int j=0; j < world->sectors[indice].num_bonus; j++)
    {
      gzread(the_file, &world->sectors[indice].bonus[j].square,sizeof(int)*1);
      gzread(the_file, &world->sectors[indice].bonus[j].x,sizeof(double)*1);
      gzread(the_file, &world->sectors[indice].bonus[j].y,sizeof(double)*1);
      gzread(the_file, &world->sectors[indice].bonus[j].z,sizeof(double)*1);

      gzread(the_file, &world->sectors[indice].bonus[j].type,sizeof(int)*1);
      gzread(the_file, &world->sectors[indice].bonus[j].parameter,sizeof(int)*1);
    }

}
