#include <stdio.h> /* remove() */
#include "lephisto.h"
#include "log.h"
#include "xml.h"
#include "player.h"
#include "toolkit.h"
#include "dialogue.h"
#include "menu.h"
#include "lfile.h"
#include "hook.h"
#include "save.h"

#define LOAD_WIDTH    400
#define LOAD_HEIGHT   300

#define BUTTON_WIDTH  50
#define BUTTON_HEIGHT 30

/* Externs. */
extern int  player_save(xmlTextWriterPtr writer);         /* A lot of stuff. */
extern int  player_load(xmlNodePtr parent);
extern int  missions_saveActive(xmlTextWriterPtr writer); /* Active missions. */
extern int  missions_loadActive(xmlNodePtr parent);
extern int  var_save(xmlTextWriterPtr writer);            /* misn var. */
extern int  var_load(xmlNodePtr parent);
extern int  pfaction_save(xmlTextWriterPtr writer);       /* Faction data. */
extern int  pfaction_load(xmlNodePtr parent);
extern int  hook_save(xmlTextWriterPtr writer);           /* Hooks. */
extern int  hook_load(xmlNodePtr parent);
extern int  space_sysSave(xmlTextWriterPtr writer);       /* Space stuff. */
extern int  space_sysLoad(xmlNodePtr parent);
extern int  diff_save(xmlTextWriterPtr writer);
extern int  diff_load(xmlNodePtr parent);
extern void menu_main_close(void);
/* Static. */
static int  save_data(xmlTextWriterPtr writer);
static void load_menu_close(unsigned int wdw, char* str);
static void load_menu_load(unsigned int wdw, char* str);
static void load_menu_delete(unsigned wdw, char* str);
static int  load_game(char* file);

/* Save all the game data. */
static int save_data(xmlTextWriterPtr writer) {
  /* The data itself. */
  if(diff_save(writer) < 0)             return -1; /* Must save first or can get cleared. */
  if(player_save(writer) < 0)           return -1;
  if(missions_saveActive(writer) < 0)   return -1;
  if(var_save(writer) < 0)              return -1;
  if(pfaction_save(writer) < 0)         return -1;
  if(hook_save(writer) < 0)             return -1;
  if(space_sysSave(writer) < 0)         return -1;
  return 0;
}

/* Save the current game. */
int save_all(void) {
  char file[PATH_MAX];
  xmlDocPtr doc;
  xmlTextWriterPtr writer;

  writer = xmlNewTextWriterDoc(&doc, 0);
  if(writer == NULL) {
    ERR("testXmlwriterDoc: Error creating the xml writer.");
    return -1;
  }

  xmlw_start(writer);
  xmlw_startElem(writer, "lephisto_save");

  /* Save the version or something.. */
  xmlw_startElem(writer, "version");
  xmlw_elem(writer, "lephisto", "%d.%d.%d", VMAJOR, VMINOR, VREV);
  xmlw_elem(writer, "data", dataname);
  xmlw_endElem(writer); /* Version. */

  if(save_data(writer) < 0) {
    ERR("Trying to save game data");
    xmlFreeTextWriter(writer);
    xmlFreeDoc(doc);
    return -1;
  }

  xmlw_endElem(writer); /* lephisto_save. */
  xmlw_done(writer);

  if(lfile_dirMakeExist("%ssaves", lfile_basePath()) < 0) {
    WARN("Aborting save...");
    xmlFreeTextWriter(writer);
    xmlFreeDoc(doc);
    return -1;
  }
  snprintf(file, PATH_MAX, "%ssaves/%s.ls", lfile_basePath(), player_name);

  /* Critical section, if crashes, the players save game gets screwed!!!
   * HAHAHAHAHA!!!!! -- NOT!
   */
  xmlFreeTextWriter(writer);
  xmlSaveFileEnc(file, doc, "UTF-8");
  xmlFreeDoc(doc);

  return 0;
}

/* Open the load game menu. */
void load_game_menu(void) {
  unsigned int wid;
  char** files;
  int lfiles, i, len;

  /* Window. */
  wid = window_create("Load Game", -1, -1, LOAD_WIDTH, LOAD_HEIGHT);

  /* Load the saves. */
  files = lfile_readDir(&lfiles, "%ssaves", lfile_basePath());
  for(i = 0; i < lfiles; i++) {
    len = strlen(files[i]);

    /* No save extension. */
    if((len < 6) || strcmp(&files[i][len-3], ".ls")) {
      free(files[i]);
      memmove(&files[i], &files[i+1], sizeof(char*) * (lfiles-i-1));
      lfiles--;
      i--;
    }
    else /* Remove the extension. */
      files[i][len-3] = '\0';
  }

  /* Again.. What if there is no files? */
  if(files == NULL) {
    files = malloc(sizeof(char*));
    files[0] = strdup("None");
    lfiles = 1;
  }

  window_addList(wid, 20, -50,
      LOAD_WIDTH-BUTTON_WIDTH-50, LOAD_HEIGHT-90,
      "lstSaves", files, lfiles, 0, NULL);

  /* Buttons. */
  window_addButton(wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
      "btnBack", "Back", load_menu_close);

  window_addButton(wid, -20, 30 + BUTTON_HEIGHT, BUTTON_WIDTH, BUTTON_HEIGHT,
      "btnLoad", "Load", load_menu_load);

  window_addButton(wid, -20, 20+2*(10+BUTTON_HEIGHT), BUTTON_WIDTH, BUTTON_HEIGHT,
      "btnDelete", "Del", load_menu_delete);

  /* Default action. */
  window_setAccept(wid, load_menu_load);
}

static void load_menu_close(unsigned int wdw, char* str) {
  (void)str;

  window_destroy(wdw);
}

static void load_menu_load(unsigned int wdw, char* str) {
  (void)str;
  char* save, path[PATH_MAX];
  int wid;

  wid = window_get("Load Game");

  save = toolkit_getList(wid, "lstSaves");

  if(strcmp(save, "None")==0)
    return;

  snprintf(path, PATH_MAX, "%ssaves/%s.ls", lfile_basePath(), save);

  /* Close menus before loading for proper rendering. */
  load_menu_close(wdw, NULL);
  menu_main_close();

  load_game(path);
}

static void load_menu_delete(unsigned int wdw, char* str) {
  (void)str;
  char* save, path[PATH_MAX];
  int wid;

  wid = window_get("Load Game");
  save = toolkit_getList(wid, "lstSaves");

  if(strcmp(save, "None") == 0)
    return;

  if(dialogue_YesNo("Permanently Delete?",
        "Are you sure you want to permanently delete '%s'?", save) == 0)
    return;

  snprintf(path, PATH_MAX, "%ssaves/%s.ls", lfile_basePath(), save);
  remove(path); /* Remove is more portable and will call unlink on Linux. */

  /* Need to reload the menu. */
  load_menu_close(wdw, NULL);
  load_game_menu();
}

/* Load a new game. */
static int load_game(char* file) {
  xmlNodePtr node;
  xmlDocPtr doc;

  doc = xmlParseFile(file);
  node = doc->xmlChildrenNode; /* Base node. */
  if(node == NULL) {
    WARN("Savegame '%s' invalid!", file);
    return -1;
  }

  diff_load(node);    /* Must load first to work properly. */
  player_load(node);
  var_load(node);
  missions_loadActive(node);
  pfaction_load(node);
  hook_load(node);
  space_sysLoad(node);

  /* Need to run takeoff hooks since player just "took off". */
  hooks_run("takeoff");
  hooks_run("enter");

  xmlFreeDoc(doc);
  xmlCleanupParser();

  return 0;
}