#include <allegro.h>
#include <string.h>
#include <stdio.h>
#include "assert.h"
#include "ctsparse.h"
#include "tileset.h"
#include "global.h"
#include "str.h"

typedef enum { ANY_SECTION = 0, SECTION_NONE, SECTION_NAME, SECTION_TILES, SECTION_VERSION, SECTION_START, NUM_SECTIONS } CTS_SECTION;

static CTS_FILE_INFO *cts_files = NULL;
static int num_cts_files = 0;
static int max_cts_files = 0;

void unload_cts_file_info(void)
{
   int c;
   
   for(c=0; c<num_cts_files; c++) {
      free(cts_files[c].name);
      free(cts_files[c].filename);
      free(cts_files[c].versionstr);
   }
   free(cts_files);

   cts_files = NULL;
   num_cts_files = 0;  
   max_cts_files = 0;
}

static void cts_filter_callback(const char *filename, int attrib, int param)
{
   char *s;
   
   s = str_to_lower(filename);
   
   if (strstr(s, ".cts")) {
      if (num_cts_files>=max_cts_files) {
         max_cts_files+=10;
         cts_files = realloc(cts_files, max_cts_files*sizeof *cts_files);
      }
      cts_files[num_cts_files].filename = strdup(filename);
      cts_files[num_cts_files].name = NULL;
      cts_files[num_cts_files].versionstr = NULL;
      cts_files[num_cts_files].num_start_tiles = 0;
      cts_files[num_cts_files].num_tiles = 0;
      cts_files[num_cts_files].num_tile_types = 0;
      cts_files[num_cts_files].num_start_tile_types = 0;
      num_cts_files++;
   }
   
   free(s);
}

static void parse_cts_file(CTS_FILE_INFO *cts)
{
   int section = SECTION_NONE;
   PACKFILE *f;
   char *s = malloc(256);
   char *eol;
   int n;

   f = pack_fopen(cts->filename, "r");
   if (!f) {
      return;
   }

   while (pack_fgets(s, 256, f)) {
      if (s[0] != '#') {
         /* remove trailing \n */
         eol = strstr(s, "\n");
         if (eol)
            eol[0] = '\0';
         
         /* Strip comments */
         eol = strstr(s, "#");
         if (eol)
            eol[0] = '\0';
         

         strflushl(s);
         strflushr(s);

         if (s[0]) {            /* skip empty lines */
            if (s[0] == '[') {  /* new section */
               if (!strcmp(s, "[name]")) {
                  section = SECTION_NAME;
               } else if (!strcmp(s, "[version]")) {
                  section = SECTION_VERSION;
               } else if (!strcmp(s, "[tiles]")) {
                  section = SECTION_TILES;
               } else if (!strcmp(s, "[start]")) {
                  section = SECTION_START;
               } else {
                  section = SECTION_NONE;
               }
            } else {
               switch (section) {
                  case SECTION_NAME:
                     free(cts->name);
                     cts->name = strdup(s);
                     break;
                  case SECTION_VERSION:
                     free(cts->versionstr);
                     cts->versionstr = strdup(s);
                     break;
                  case SECTION_TILES:
                     sscanf(s, "%d", &n);
                     cts->num_tiles += n;
                     cts->num_tile_types++;
                     break;
                  case SECTION_START:
                     sscanf(s, "%d", &n);
                     cts->num_start_tiles += n;
                     cts->num_start_tile_types++;
                     break;
                  default:
                     TRACE("Warning: statement outside section:\n%s", s);
               }
            }
         }
      }
   }

   free(s);
   pack_fclose(f);
}

void read_cts_file_info(void)
{
   int n;
   
   unload_cts_file_info();

   for_each_file("*", FA_RDONLY|FA_HIDDEN|FA_ARCH, cts_filter_callback, 0);

   for(n=0; n<num_cts_files; n++) {
      parse_cts_file(cts_files + n);
   }
   
   /*
   for(n=0; n<num_cts_files; n++) {
      printf("%s\t%s (%s) [%d/%d]\n", cts_files[n].filename, 
             cts_files[n].name, cts_files[n].versionstr,
             cts_files[n].num_tiles, cts_files[n].num_start_tiles);
   }
   */
}

int get_num_cts_files(void)
{
   return num_cts_files;
}

CTS_FILE_INFO *get_cts_info(int num)
{
   assert(num<num_cts_files);
   
   return cts_files+num;
}

CTS_FILE_INFO *get_cts_name(const char *name)
{
   int n;
   
   for (n=0; n<num_cts_files; n++)
      if(strcmp(name, cts_files[n].name) == 0)
         return cts_files+n;
   
   return NULL;
}

int load_cts_tileset(char *filename, DEFAULT_TILESET *tileset)
{
   int section = SECTION_NONE;
   PACKFILE *f;
   char *s = malloc(256);
   char *eol;
   int n = 0;

   f = pack_fopen(filename, "r");
   if (!f) {
      return 0;
   }

   while (pack_fgets(s, 256, f)) {
      if (s[0] != '#') {
         /* remove trailing \n */
         eol = strstr(s, "\n");
         if (eol)
            eol[0] = '\0';
         
         /* Strip comments */
         eol = strstr(s, "#");
         if (eol)
            eol[0] = '\0';
         

         strflushl(s);
         strflushr(s);

         if (s[0]) {            /* skip empty lines */
            if (s[0] == '[') {  /* new section */
               if (!strcmp(s, "[name]")) {
                  section = SECTION_NAME;
               } else if (!strcmp(s, "[version]")) {
                  section = SECTION_VERSION;
               } else if (!strcmp(s, "[tiles]")) {
                  section = SECTION_TILES;
               } else if (!strcmp(s, "[start]")) {
                  section = SECTION_START;
               } else {
                  section = SECTION_NONE;
               }
            } else {
               switch (section) {
                  case SECTION_NAME:
                     break;
                  case SECTION_VERSION:
                     break;
                  case SECTION_TILES:
                     sscanf(s, "%d,%x,%x,%x,%x,%x", &(tileset[n].amount),
                              &(tileset[n].up), &(tileset[n].left), 
                              &(tileset[n].right), &(tileset[n].down),
                                 &(tileset[n].flags));
                     n++;
                     break;
                  case SECTION_START:
                     break;
                  default:
                     TRACE("Warning: statement outside section:\n%s", s);
               }
            }
         }
      }
   }

   free(s);
   pack_fclose(f);
   
   return n;
}

int load_cts_startset(char *filename, DEFAULT_TILESET *tileset)
{
   int section = SECTION_NONE;
   PACKFILE *f;
   char *s = malloc(256);
   char *eol;
   int n = 0;

   f = pack_fopen(filename, "r");
   if (!f) {
      return 0;
   }

   while (pack_fgets(s, 256, f)) {
      if (s[0] != '#') {
         /* remove trailing \n */
         eol = strstr(s, "\n");
         if (eol)
            eol[0] = '\0';
         
         /* Strip comments */
         eol = strstr(s, "#");
         if (eol)
            eol[0] = '\0';
         

         strflushl(s);
         strflushr(s);

         if (s[0]) {            /* skip empty lines */
            if (s[0] == '[') {  /* new section */
               if (!strcmp(s, "[name]")) {
                  section = SECTION_NAME;
               } else if (!strcmp(s, "[version]")) {
                  section = SECTION_VERSION;
               } else if (!strcmp(s, "[tiles]")) {
                  section = SECTION_TILES;
               } else if (!strcmp(s, "[start]")) {
                  section = SECTION_START;
               } else {
                  section = SECTION_NONE;
               }
            } else {
               switch (section) {
                  case SECTION_NAME:
                     break;
                  case SECTION_VERSION:
                     break;
                  case SECTION_TILES:
                     break;
                  case SECTION_START:
                     sscanf(s, "%d,%x,%x,%x,%x,%x", &(tileset[n].amount),
                              &(tileset[n].up), &(tileset[n].left), 
                              &(tileset[n].right), &(tileset[n].down),
                                 &(tileset[n].flags));
                     n++;
                     break;
                  default:
                     TRACE("Warning: statement outside section:\n%s", s);
               }
            }
         }
      }
   }

   free(s);
   pack_fclose(f);
   
   return n;
}
