/*   Copyright 2005,2006 Paweł Niegowski
*
*    This file is part of Fenrir.
*
*    Fenrir 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.
*
*    Fenrir 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 Fenrir; if not, write to the Free Software
*    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "main.h"
#include "map.h"
#include "edit.h"
#include "player.h"
#include "palette.h"
#include "network.h"
#include "lookup.h"
#include "sky.h"
#include "gui.h"
#include <stdio.h>
#include <string.h>
#define MAX_MAPS 5000
#define MAP_NONE 1337

unsigned char upper_layer[256][256];
unsigned char mid_layer[256][256];
unsigned char lower_layer[256][256];
int map_w = 0, map_h = 0;
unsigned int map_num;
char current_path[50];
char tileset_path[50];
char tileset_current_path[50];
DATAFILE *map_datafile = 0;
DATAFILE *tileset_datafile = 0;
BITMAP *tileset = 0;
Object *objects[256];
unsigned int next_charnum, next_map, next_x, next_y, next_map_flags;
bool map_loaded = false;
char map_flags = 0;

struct MapLocation { unsigned int index; char path[50]; };
MapLocation map_locations[MAX_MAPS];

void map_init()
{
 for(int i=0; i<MAX_MAPS; i++)
  map_locations[i].index = MAP_NONE;
 map_num = 0;
 FILE *f = fopen("data/maps.txt","r");
 if(!f) allegro_message("data/maps.txt not found. Uh oh.");
 int index = 0;
 char path[50];
 map_w = 0;
 map_h = 0;
 tileset_datafile = 0;
 map_datafile = 0;
 fscanf(f,"%d %s",&index,path);
 int i = 0;
 while(index > -1)
 {
  map_locations[i].index = index;
  strcpy(map_locations[i].path,path);
  fscanf(f,"%d %s",&index,path);
  i++;
 }
 fclose(f);
 current_path[0] = 0;
 tileset_path[0] = 0;
 tileset_current_path[0] = 0;
 for(int i=0; i<256; i++)
  objects[i] = 0;
}

void map_think()
{
}

void map_draw_lower()
{
 for(int i=0; i<map_h; i++)
  for(int j=0; j<map_w; j++)
   if(lower_layer[i][j])
    blit(tileset,buf,(lower_layer[i][j] & 15) << 4,lower_layer[i][j] & 240, (j << 4) - cam_x, (i << 4) - cam_y,16,16);
}

void map_draw_mid()
{
 for(int i=0; i<map_h; i++)
  for(int j=0; j<map_w; j++)
   if(mid_layer[i][j])
    masked_blit(tileset,buf,(mid_layer[i][j] & 15) << 4,(mid_layer[i][j] & 240) + 256, (j << 4) - cam_x, (i << 4) - cam_y,16,16);
}

void map_draw_upper()
{
 for(int i=0; i<map_h; i++)
  for(int j=0; j<map_w; j++)
   if(upper_layer[i][j])
    masked_blit(tileset,buf,(upper_layer[i][j] & 15) << 4,(upper_layer[i][j] & 240) + 256, (j << 4) - cam_x, (i << 4) - cam_y,16,16);
}

void map_cleanup()
{
 if(tileset_datafile) { unload_datafile(tileset_datafile); tileset_datafile = 0; }
 if(map_datafile) { unload_datafile(map_datafile); map_datafile = 0; }
}

void map_change(int charnum, unsigned int num)
{
 next_charnum = charnum;
 next_map = num;
 map_change();
}

void map_change()
{
 map_loaded = true;
 map_num = next_map;
 map_flags = next_map_flags;
 if(game_state == GAME_EDIT)
  for(int i=0; i<256; i++)
   for(int j=0; j<256; j++)
   {
    lower_layer[i][j] = 1;
    mid_layer[i][j] = 0;
    upper_layer[i][j] = 0;
   }
 static char path[40];
 sprintf(path,"data/maps/%d.map",next_map);
 FILE *f  = fopen(path,"rb");
 if(f)
 {
  fgets(tileset_path,50,f);
  for(int i=0; i<50; i++)
   if(tileset_path[i] == '\n')
   { tileset_path[i] = 0; break; }
  map_w = fgetc(f);
  map_h = fgetc(f);
  for(int i=0; i<map_h; i++)
   //this actually jumps to lower_layer + (i*256 bytes). Yay for multi-dimensional arrays.
   fread(lower_layer+i,map_w,1,f);
  for(int i=0; i<map_h; i++)
   fread(mid_layer+i,map_w,1,f);
  for(int i=0; i<map_h; i++)
   fread(upper_layer+i,map_w,1,f);
  fclose(f);
 }
 else
 //datafile handling
 if(map_locations[map_num].index != MAP_NONE)
 {
  if(strcmp(current_path,map_locations[map_num].path))
  {
   if(map_datafile) unload_datafile(map_datafile);
   map_datafile = load_datafile(map_locations[map_num].path);
   if(!map_datafile) allegro_message("ERROR: couldn't find map datafile.\n");
   strcpy(current_path,map_locations[map_num].path);
  }
  char *ptr = (char*)(map_datafile[map_locations[map_num].index].dat);
  int l = strchr(ptr,'\n')-ptr;
  strncpy(tileset_path,ptr,l);
  tileset_path[l] = 0;
  ptr += l+1;
  map_w = ptr[0];
  map_h = ptr[1];
  ptr += 2;
  for(int i=0; i<map_h; i++, ptr += map_w)
   memcpy(lower_layer+i,ptr,map_w);
  for(int i=0; i<map_h; i++, ptr += map_w)
   memcpy(mid_layer+i,ptr,map_w);
  for(int i=0; i<map_h; i++, ptr += map_w)
   memcpy(upper_layer+i,ptr,map_w);
 } else
 //empty map
 {
 map_w = 40;
 map_h = 40;
 for(int i=0; i<map_w; i++)
  for(int j=0; j<map_h; j++)
  {
   lower_layer[i][j] = 1;
   mid_layer[i][j] = 0;
   upper_layer[i][j] = 0;
  }
 strcpy(tileset_path,"shrine");
 }

 for(list<Object*>::iterator it = object_list.begin(); it != object_list.end(); it++)
 {
  if((*it)->newmap)
   (*it)->newmap = false;
  else
  (*it)->kill_counter = 2;
 }
 objects[next_charnum] = player;
 player->obj_num = next_charnum;
 player->stunlock = 0;
 player->setx(next_x); player->net_x = next_x;
 player->sety(next_y); player->net_y = next_y;
 player->set_cam();
 object_list_think();
 if(strcmp(tileset_path,tileset_current_path))
 {
  strcpy(tileset_current_path,tileset_path);
  static char tpath[100];
  sprintf(tpath,"gfx/tilesets/%s.dat",tileset_path);
  unload_datafile(tileset_datafile);
  tileset_datafile = load_datafile(tpath);
  lookup_gen();
  if(!tileset_datafile)
  {
   allegro_message("Tileset datafile couldn't be found.");
   tileset_datafile = load_datafile("gfx/tilesets/shrine.dat");
  }
 }
 tileset = (BITMAP*)tileset_datafile[1].dat;
 RGB *ptr = (RGB*)tileset_datafile[0].dat;
 for(int i=1; i<256; i++)
 {
  base_palette[i].r = current_palette[i].r = ptr[i].r;
  base_palette[i].g = current_palette[i].g = ptr[i].g;
  base_palette[i].b = current_palette[i].b = ptr[i].b;
 }
 //we want black backgrounds, don't we?
 base_palette[0].r = base_palette[0].g = base_palette[0].b = current_palette[0].r = current_palette[0].g = current_palette[0].b = 0;
 //gui background colors
 gui_loadpalette();
 for(int i=208; i < 224; i++)
 {
  base_palette[i].r = current_palette[i].r = sky_palette[i].r;
  base_palette[i].g = current_palette[i].g = sky_palette[i].g;
  base_palette[i].b = current_palette[i].b = sky_palette[i].b;
 }
// set_palette(current_palette);
 palette_set_backup();
 static RGB black = { 0,0,0 };
 palette_fade_in(black);
 palette_update_time();
 network_disabled = false;
}

void map_save(unsigned int num)
{
 static char path[40];
 sprintf(path,"data/maps/%d.map",num);
 FILE *f = fopen(path,"wb");
 fputs(tileset_path,f);
 fputc('\n',f);
 fputc(map_w,f);
 fputc(map_h,f);
 for(int i=0; i<map_h; i++)
  fwrite(lower_layer+i,map_w,1,f);
 for(int i=0; i<map_h; i++)
  fwrite(mid_layer+i,map_w,1,f);
 for(int i=0; i<map_h; i++)
  fwrite(upper_layer+i,map_w,1,f);
 fclose(f);
 strcpy(edit_message,"Map saved.");
 edit_message_timeout = 60;
}

// returns true if the point on the map can be passed
bool map_check(int x, int y)
{
 static int type;
 type = tileset->line[lower_layer[y/16][x/16]/16] [lower_layer[y/16][x/16]&15];
 switch(type)
 {
  //solid rectangle
  case 2 : return false;
 }
 return true;
}

void map_putpixel(int x, int y, int tile, int layer)
{
 if(layer == LAYER_LOWER)
 {  lower_layer[y&255][x&255] = tile&255; return; }
 if(layer == LAYER_MID)
 {  mid_layer[y&255][x&255] = tile&255; return; }
 if(layer == LAYER_UPPER)
 {  upper_layer[y&255][x&255] = tile&255; return; }
}

int map_getpixel(int x, int y, int layer)
{
 if(layer == LAYER_LOWER) return lower_layer[y&255][x&255];
 if(layer == LAYER_MID) return mid_layer[y&255][x&255];
 if(layer == LAYER_UPPER) return upper_layer[y&255][x&255];
 return 0;
}
