/*  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 <stdlib.h>
#include <time.h>
#include <string.h>

#include <stdarg.h>
#include <sys/stat.h>
#include <limits.h>

#include <errno.h>

#ifndef WIN32
#   include <unistd.h>
#   include <sys/types.h>
#   include <pwd.h>
#   include <dirent.h>
#   include <sys/time.h>
#   include <sys/types.h>
#   include <dirent.h>
#endif

#if defined (_MSC_VER)
#    include <io.h>
#endif

#ifdef WIN32
#   define SHXMAN_DATA "game_data/"
#endif


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

#include <stdio.h>
#include <math.h>

#include "world_building.h"
#include "map.h"
#include "timers.h"
#include "world_geometry.h"
#include "hut.h"
#include "bonus.h"
#include "mango.h"
#include "game_loop.h"
#include "system_gl.h"
#include "draw_scene_gl.h"
#include "sector.h"
#include "move.h"
#include "hud.h"
#include "sounds.h"
#include "map_seeking.h"
#include "file_utils.h"
#include "menus.h"

#define MAX_MAP_NAME 255

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

map_names_t *map_names;

int register_map_names()
{
  int i=0, j=0;
  printf("Looking for maps... ");
  map_names = new map_names_t;
  map_names->num_builtins = count_builtin_maps();
  map_names->num_customs = count_custom_maps();

  printf("found %d official %s and %d custom %s\n",
	 map_names->num_builtins,map_names->num_builtins > 1 ?"maps":"map",
	 map_names->num_customs,map_names->num_customs > 1 ?"maps":"map");

  if ((map_names->num_builtins == 0) && (map_names->num_customs == 0)) {
    fprintf(stderr,"Warning: no map found in standard directories\n");
  }

  if (map_names->num_builtins > 0) {
    map_names->builtins = new char * [map_names->num_builtins];
    if (map_names->builtins == NULL) {
      fprintf(stderr,"Memory error (map names)\n");
      exit(1);
    }

    for (i=0; i < map_names->num_builtins; i++) {
      map_names->builtins[i] = new char [MAX_MAP_NAME];
    }
  }

  if (map_names->num_customs > 0) {
    map_names->customs = new char * [map_names->num_customs];
    if (map_names->builtins == NULL) {
      fprintf(stderr,"Memory error (map names)\n");
      exit(1);
    }

    for (j=0; j < map_names->num_customs; j++) {
      map_names->customs[j] = new char [MAX_MAP_NAME];
    }
  }

  fill_map_names();

  return 0;
}

void cleanup_map_names()
{
  if (map_names->num_builtins) {
    for (int i=0; i<map_names->num_builtins; i++)
      delete [] map_names->builtins[i];
    delete [] map_names->builtins;
  }
  if (map_names->num_customs) {
    for (int j=0; j<map_names->num_customs; j++)
      delete [] map_names->customs[j];
    delete [] map_names->customs;
  }

  delete map_names;
}

void fill_map_names()
{
  int i=0, j=0;
  char buff[MAX_PATH];

  if (get_private_dir_name( buff, MAX_PATH ) != 0) {

  }

#ifndef WIN32

  char curdir[MAX_PATH];
  DIR *dirp;
  struct dirent *dp;
  struct stat buf;

  /* built-in maps */

  if ( getcwd( curdir, MAX_PATH - 1 ) == NULL ) {
	fprintf(stderr, "Error: getcwd failed");
	exit(1);
  }

  chdir(BUILTIN_MAPS);
  dirp = opendir(".");
  if (!dirp) {
    fprintf(stderr,"Error: couldn't open directory\n");
    exit(1);
  }
  while ((dp = readdir(dirp))!=0) {
    if (stat(dp->d_name,&buf) == 0)
      if (strstr(dp->d_name, ".bmq")) {
	if (strlen(dp->d_name) > MAX_MAP_NAME) {
	  fprintf(stderr,"Error: map name is too long\n");
	  exit(1);
	}
	strncpy(map_names->builtins[i],(const char *)dp->d_name,MAX_MAP_NAME);
	i++;
      }
  }
  closedir(dirp);

  chdir(curdir);

  /* custom maps (user made) */

  if ( strlen( buff ) + strlen( "maps" ) +2> (unsigned)MAX_PATH ) {

  }
  strcat( buff, "/" );
  strcat( buff, "maps");

  chdir(buff);
  dirp = opendir(".");
  if (!dirp) {
    fprintf(stderr,"Error: couldn't open directory\n");
    exit(1);
  }
  while ((dp = readdir(dirp))!=0) {
    if (stat(dp->d_name,&buf) == 0)
      if (strstr(dp->d_name, ".bmq")) {
	if (strlen(dp->d_name) > MAX_MAP_NAME) {
	  fprintf(stderr,"Error: map name is too long\n");
	  exit(1);
	}
	strncpy(map_names->customs[j],(const char *)dp->d_name,MAX_MAP_NAME);
	j++;
      }
  }
  closedir(dirp);

  chdir(curdir);

#else
  struct _finddata_t c_file;
  long hFile;

  //chdir(BUILTIN_MAPS);
  /* Find first file in current directory */
  if((hFile = _findfirst(BUILTIN_MAPS "*.*", &c_file)) == -1L) { }
  //printf("No subdirectories in current directory!\n");
  else{
    if((c_file.attrib & _A_SUBDIR )){
      if (strstr(c_file.name, ".bmq")) {
	strncpy(map_names->builtins[i],(const char *)c_file.name,MAX_MAP_NAME);
	i++;
      }
    }

    /* Find the rest of the *.* files */
    while(_findnext(hFile, &c_file) == 0){
      if (strstr(c_file.name, ".bmq")) {
	strncpy(map_names->builtins[i],(const char *)c_file.name,MAX_MAP_NAME);
	i++;
      }
      
    }

    _findclose(hFile);
  }

  strcat(buff,"/maps/*.*");
  /* Find first file in current directory */
  if((hFile = _findfirst(buff, &c_file)) == -1L) { }
  //printf("No subdirectories in current directory!\n");
  else{
    if((c_file.attrib & _A_SUBDIR )){
      if (strstr(c_file.name, ".bmq")) {
	strncpy(map_names->customs[j],(const char *)c_file.name,MAX_MAP_NAME);
	j++;
      }
    }

    /* Find the rest of the *.* files */
    while(_findnext(hFile, &c_file) == 0){
      if (strstr(c_file.name, ".bmq")) {
	strncpy(map_names->customs[j],(const char *)c_file.name,MAX_MAP_NAME);
	j++;
      }
      
    }

    _findclose(hFile);
  }
#endif
}

int count_builtin_maps()
{
  int n_builtins=0;

#ifndef WIN32

  char curdir[MAX_PATH];
  DIR *dirp;
  struct dirent *dp;
  struct stat buf;
  
  if ( getcwd( curdir, MAX_PATH - 1 ) == NULL ) {
    fprintf(stderr, "Error: getcwd failed");
    exit(1);
  }

  chdir(BUILTIN_MAPS);
  dirp = opendir(".");
  if (!dirp) {
    fprintf(stderr,"Error: could'nt open directory\n");
    exit(1);
  }
  while ((dp = readdir(dirp))!=0) {
    if (stat(dp->d_name,&buf) == 0)
      //if(!(buf.st_mode & S_IFDIR))
      if (strstr(dp->d_name, ".bmq")) {
	n_builtins++;
      }
  }
  closedir(dirp);

  chdir(curdir);

#else
  struct _finddata_t c_file;
  long hFile;

  //chdir(BUILTIN_MAPS);
  /* Find first file in current directory */
  if((hFile = _findfirst(BUILTIN_MAPS "*.*", &c_file)) == -1L) { }
  //printf("No subdirectories in current directory!\n");
  else{
    if((c_file.attrib & _A_SUBDIR )){
      if ((strstr(c_file.name, ".bmq"))||(strstr(c_file.name, ".BMQ"))) {
	//printf("found %s\n",c_file.name);
	n_builtins++;
      }
    }

    /* Find the rest of the *.* files */
    while(_findnext(hFile, &c_file) == 0){
      if ((strstr(c_file.name, ".bmq"))||(strstr(c_file.name, ".BMQ"))) {
	//printf("found %s\n",c_file.name);
	n_builtins++;
      }
      
    }

    _findclose(hFile);
  }
#endif

  return n_builtins;
}

int count_custom_maps()
{
  int n_customs=0;

  char buff[MAX_PATH];

  if (get_private_dir_name( buff, MAX_PATH ) != 0) {
    //return -1;
  }
  if ( strlen( buff ) + strlen( "maps" ) +2> (unsigned)MAX_PATH ) {
    //return -1;
  }

#ifndef WIN32
  char curdir[MAX_PATH];
  DIR *dirp;
  struct dirent *dp;
  struct stat buf;

  if ( getcwd( curdir, MAX_PATH - 1 ) == NULL ) {
    fprintf(stderr, "Error: getcwd failed");
    exit(1);
  }

  
  strcat( buff, "/" );
  strcat( buff, "maps");

  chdir(buff);
  dirp = opendir(".");
  if (!dirp) {
    fprintf(stderr,"Error: could'nt open directory\n");
    exit(1);
  }
  while ((dp = readdir(dirp))!=0) {
    if (stat(dp->d_name,&buf) == 0)
      //if(!(buf.st_mode & S_IFDIR))
      if (strstr(dp->d_name, ".bmq")) {
	n_customs++;
      }
  }
  closedir(dirp);

  chdir(curdir);

#else
  struct _finddata_t c_file;
  long hFile;

  //chdir(buff);

  strcat(buff,"/maps/*.*");
  /* Find first file in current directory */
  if((hFile = _findfirst(buff, &c_file)) == -1L) { }
  //printf("No subdirectories in current directory!\n");
  else{
    if((c_file.attrib & _A_SUBDIR )){
      if (strstr(c_file.name, ".bmq")) {
	printf("found %s\n",c_file.name);
	n_customs++;
      }
    }

    /* Find the rest of the *.* files */
    while(_findnext(hFile, &c_file) == 0){
      if (strstr(c_file.name, ".bmq")) {
	printf("found %s\n",c_file.name);
	n_customs++;
      }
      
    }

    _findclose(hFile);
  }
#endif

  return n_customs;
}

void map_name_to_builtin_path(char *map_name, char *complete_path)
{
  strcat(complete_path, BUILTIN_MAPS);
  strcat(complete_path, map_name);

  if (!file_exists (complete_path)) 
    {
      fprintf(stderr,"Error when looking for file %s.\n",complete_path);
      exit(1);
    }

}

void map_name_to_custom_path(char *map_name, char *complete_path)
{
  if (get_private_map_file_name(complete_path, map_name, MAX_PATH))
    {
      fprintf(stderr,"Error when looking for file %s.\n",complete_path);
      exit(1);
    }
}

void read_map_infos(int type, map_list_item_t *map_desc)
{
  char complete_path[MAX_PATH];
  memset (complete_path,0,(MAX_PATH-1)*sizeof(char));

  if (type == SK_LIST_BUILTINS)
    map_name_to_builtin_path(map_desc->text,complete_path);

  else map_name_to_custom_path(map_desc->text,complete_path);

  gzFile map_file=0;
  int compatibility_n=0;

  char *verification=0;

  //printf("Reading map properties\n");

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

  verification = new char[3];

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

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

  gzread(map_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");
    fprintf(stderr,"We continue loading, since this map will work (but you will loose on-floor teleports).\n");

    //exit(1);
  }
  
  gzread(map_file,&map_desc->map_size, sizeof(int)*1);
  gzread(map_file,&map_desc->map_world, sizeof(int)*1);
  gzread(map_file,&map_desc->map_time_limit, sizeof(int)*1);
  gzread(map_file,&map_desc->map_num_huts, sizeof(int)*1);
  gzread(map_file,&map_desc->map_num_shmolluxes, sizeof(int)*1);
  gzread(map_file,&map_desc->map_num_lives, sizeof(int)*1);
  gzread(map_file,&map_desc->map_winning_square, sizeof(int)*1);

  gzclose(map_file);
}
