#include <string.h>
#include "libxml/xmlreader.h"

#include "log.h"
#include "ship.h"

#define MAX_PATH_NAME 20 // Maximum size of the path.

#define XML_NODE_START  1
#define XML_NODE_TEXT   3
#define XML_NODE_CLOSE  15
#define XML_NODE_CDATA  4

#define XML_ID    "Ships" // XML section identifier.
#define XML_SHIP  "ship"

#define SHIP_DATA "../dat/ship.xml"
#define SHIP_GFX  "../gfx/ship/"

static Ship* ship_stack = NULL;
static int ships;

// Get a ship based on it's name.
Ship* get_ship(const char* name) {
  Ship* tmp = ship_stack;
  int i;
  for(i = 0; i < ships; i++)
    if(strcmp((tmp+i)->name, name)==0) break;

  return tmp+1;
}

Ship* ship_parse(xmlNodePtr node) {
  xmlNodePtr cur;
  Ship* tmp = CALLOC_L(Ship);

  char str[MAX_PATH_NAME] = "\0";

  tmp->name = (char*)xmlGetProp(node, (xmlChar*)"name");

  node = node->xmlChildrenNode;

  while((node = node->next)) {
    if(strcmp((char*)node->name, "GFX")==0) {
      cur = node->children;
      if(strcmp((char*)cur->name, "text")==0) {
        snprintf(str, strlen((char*)cur->content)+sizeof(SHIP_GFX),
              SHIP_GFX"%s", (char*)cur->content);
        tmp->gfx_ship = gl_newSprite(str, 6, 6);
      }
    }
    else if(strcmp((char*)node->name, "class")==0) {
      cur = node->children;
      if(strcmp((char*)cur->name, "text")==0)
        tmp->class = atoi((char*)cur->content);
    }
    else if(strcmp((char*)node->name, "movement")==0) {
      cur = node->children;
      while((cur = cur->next)) {
        if(strcmp((char*)cur->name, "thrust")==0)
          tmp->thrust = atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "turn")==0)
          tmp->turn = atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "speed")==0)
          tmp->speed = atoi((char*)cur->children->content);
      }
    }
    else if(strcmp((char*)node->name, "health")==0) {
      cur = node->children;
      while((cur = cur->next)) {
        if(strcmp((char*)cur->name, "armor")==0)
          tmp->armor = (FP)atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "shield")==0)
          tmp->shield = (FP)atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "energy")==0)
          tmp->energy = (FP)atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "armor_regen")==0)
          tmp->armor_regen = (FP)(atoi((char*)cur->children->content))/60.0;
        else if(strcmp((char*)cur->name, "shield_regen")==0)
          tmp->shield_regen = (FP)(atoi((char*)cur->children->content))/60.0;
        else if(strcmp((char*)cur->name, "energy_regen")==0)
          tmp->energy_regen = (FP)(atoi((char*)cur->children->content))/60.0;
      }
    }
    else if(strcmp((char*)node->name, "characteristics")==0) {
      cur = node->children;
      while((cur = cur->next)) {
        if(strcmp((char*)cur->name, "crew")==0)
          tmp->crew = atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "mass")==0)
          tmp->mass = (FP)atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "cap_weapon")==0)
          tmp->cap_weapon = atoi((char*)cur->children->content);
        else if(strcmp((char*)cur->name, "cap_cargo")==0)
          tmp->cap_cargo = atoi((char*)cur->children->content);
      }
    }
  }
  tmp->thrust *= tmp->mass; // Helps keep number sane.

  DEBUG("Loaded ship '%s'", tmp->name);
  return tmp;
}

int ships_load(void) {
  xmlTextReaderPtr reader;
  xmlNodePtr node;
  Ship* tmp = NULL;

  if((reader = xmlNewTextReaderFilename(SHIP_DATA)) == NULL) {
    WARN("XML error reading " SHIP_DATA);
    return -1;
  }

  // Get to the start of the "ships" section.
  while(xmlTextReaderRead(reader)==1) {
    if(xmlTextReaderNodeType(reader)==XML_NODE_START &&
          strcmp((char*)xmlTextReaderConstName(reader), XML_ID) == 0) break;
  }

  xmlTextReaderRead(reader); // At ships node.

  while(xmlTextReaderRead(reader)==1) {
    if(xmlTextReaderNodeType(reader)==XML_NODE_START &&
          strcmp((char*)xmlTextReaderConstName(reader), XML_SHIP)==0) {
      
      node = xmlTextReaderCurrentNode(reader); // Node to process.
      if(ship_stack == NULL) {
        ship_stack = tmp = ship_parse(node);
        ships = 1;
      } else {
        tmp = ship_parse(node);
        ship_stack = realloc(ship_stack, sizeof(Ship)*(++ships));
        memcpy(ship_stack+ships-1, tmp, sizeof(Ship));
        free(tmp);
      }
    }
  }
  xmlFreeTextReader(reader);
  return 0;
}

void ships_free(void) {
  int i;
  for(i = 0; i < ships; i++) {
    if((ship_stack+i)->name)
      free((ship_stack+i)->name);
    gl_freeTexture((ship_stack+i)->gfx_ship);
  }
  free(ship_stack);
  ship_stack = NULL;
}