#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include "lephisto.h"
#include "xml.h"
#include "pack.h"
#include "log.h"
#include "spfx.h"
#include "pilot.h"
#include "rng.h"
#include "economy.h"

#define XML_COMMODITY_ID  "Commodities" /* XML section identifier. */
#define XML_COMMODITY_TAG  "commodity"
#define COMMODITY_DATA   "../dat/commodity.xml"

/* Commodity stack. */
static Commodity* commodity_stack = NULL;
static int commodity_nstack = 0;

static void commodity_freeOne(Commodity* com);
static Commodity* commodity_parse(xmlNodePtr parent);

/* Convert credits to a usable string for displaying. */
/* str must have 10 characters allocated. */
void credits2str(char* str, unsigned int credits, int decimals) {
  if(decimals < 0)
    snprintf(str, 32, "%d", credits);
  else if(credits >= 1000000000)
    snprintf(str, 16, "%.*fB", decimals, (double)credits / 1000000000.);
  else if(credits >= 1000000)
    snprintf(str, 16, "%*fM", decimals, (double)credits / 1000000.);
  else if(credits >= 1000)
    snprintf(str, 16, "%.*fK", decimals, (double)credits / 1000.);
  else snprintf(str, 16, "%d", credits);
}

/* Get a commodity. */
Commodity* commodity_get(const char* name) {
  int i;
  for(i = 0; i < commodity_nstack; i++)
    if(strcmp(commodity_stack[i].name, name)==0)
      return &commodity_stack[i];

  WARN("Commodity '%s' not found in stack", name);
  return NULL;
}

/* Free a commodity. */
static void commodity_freeOne(Commodity* com) {
  if(com->name) free(com->name);
  if(com->description) free(com->description);
}

static Commodity* commodity_parse(xmlNodePtr parent) {
  xmlNodePtr node;
  Commodity* tmp = CALLOC_L(Commodity);

  tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name");
  if(tmp->name == NULL)
    WARN("Commodity from "COMMODITY_DATA" has invalid or noname");

  node = parent->xmlChildrenNode;

  do {
    if(xml_isNode(node, "description"))
      tmp->description = strdup(xml_get(node));
    else if(xml_isNode(node, "high"))
      tmp->high = xml_getInt(node);
    else if(xml_isNode(node, "medium"))
      tmp->medium = xml_getInt(node);
    else if(xml_isNode(node, "low"))
      tmp->low = xml_getInt(node);
  } while((node = node->next));
#if 0 /* Let's kill this for now. */
#define MELEMENT(o,s)if(o)WARN("Commodity '%s' missing '"s"' element",tmp->name)
  MELEMENT(tmp->high==0,        "high");
  MELEMENT(tmp->description==NULL,   "description");
  MELEMENT(tmp->medium==0,       "medium");
  MELEMENT(tmp->low==0,        "low");
#undef MELEMENT
#endif

  return tmp;
}

/* Throw cargo out into space (graphically). */
void commodity_Jettison(int pilot, Commodity* com, int quantity) {
  (void)com;
  int i;
  Pilot* p;
  int n, effect;
  double px, py, bvx, bvy, r, a, vx, vy;

  p = pilot_get(pilot);

  n = MAX(1, RNG(quantity/10, quantity/5));
  px = p->solid->pos.x;
  py = p->solid->pos.y;
  bvx = p->solid->vel.x;
  bvy = p->solid->vel.y;

  for(i = 0; i < n; i++) {
    effect = spfx_get("cargo");

    /* Radial distribution gives much nicer results. */
    r = RNGF()*25 - 12.5;
    a = (double)RNG(0,259);
    vx = bvx + r*cos(a);
    vy = bvy + r*sin(a);

    /* Add the cargo effect. */
    spfx_add(effect, px, py, vx, vy, SPFX_LAYER_BACK);
  }
}

/* Init/exit */
int commodity_load(void) {
  uint32_t bufsize;
  char* buf = pack_readfile(DATA, COMMODITY_DATA, &bufsize);

  xmlNodePtr node;
  xmlDocPtr doc = xmlParseMemory(buf, bufsize);

  Commodity* tmp = NULL;

  node = doc->xmlChildrenNode; /* Commoditys node. */
  if(strcmp((char*)node->name, XML_COMMODITY_ID)) {
    ERR("Malformed "COMMODITY_DATA
        " file: Missing root element '"XML_COMMODITY_ID"'");
    return -1;
  }

  node = node->xmlChildrenNode; /* First faction node. */
  if(node == NULL) {
    ERR("Malformed "COMMODITY_DATA" file: does not contain elements");
    return -1;
  }

  do {
    if(node->type == XML_NODE_START) {
      if(strcmp((char*)node->name, XML_COMMODITY_TAG)==0) {
        tmp = commodity_parse(node);
        commodity_stack = realloc(commodity_stack,
                                  sizeof(Commodity)*(++commodity_nstack));
        memcpy(commodity_stack+commodity_nstack-1, tmp, sizeof(Commodity));
        free(tmp);
      }
    }
  } while((node = node->next));

  xmlFreeDoc(doc);
  free(buf);
  xmlCleanupParser();

  DEBUG("Loaded %d commodit%s",
        commodity_nstack, (commodity_nstack==1) ? "y" : "ies");

  return 0;
}

void commodity_free(void) {
  int i;
  for(i = 0; i < commodity_nstack; i++)
    commodity_freeOne(&commodity_stack[i]);
  free(commodity_stack);
  commodity_stack = NULL;
  commodity_nstack = 0;
}

