#include "Item.h"

Item::Item ()
{
  clear ();
}

Item::~Item ()
{
}

bool Item::loadItem (const string & name)
{
  xmlDocPtr doc;
  xmlXPathContextPtr xpathCtx;

  if (!prepareXMLFile (doc, xpathCtx, "resources/game/ItemManifest.xml", ""))
    return false;

  bool validBasicItem = false, validItem=false, triedToLoad=false;
  string xpathStart;

  //first check if the item is equipment.
  if (!triedToLoad)
    {
      xpathStart="/ItemManifest/Equipment[@ID='";
      xpathStart+=name;
      xpathStart+="']";

      if (xPathExists (doc, xpathCtx, xpathStart, "", ""))
	{
	  triedToLoad=true;
	  validBasicItem=loadItemHelper(doc, xpathCtx, xpathStart);
	  if (validBasicItem)
	    validItem = loadEquipment (doc, xpathCtx, xpathStart);
	}
      if (validItem)
	setItemType(ITEM_TYPE_EQUIPMENT);
    }
  //Now try a consumable.
  else if (!triedToLoad)
    {
      xpathStart="/ItemManifest/Consumable[@ID='";
      xpathStart+=name;
      xpathStart+="']";

      if (xPathExists (doc, xpathCtx, xpathStart, "", ""))
	{
	  triedToLoad=true;
	  validBasicItem=loadItemHelper(doc, xpathCtx, xpathStart);
	  if (validBasicItem)
	    validItem = loadConsumable (doc, xpathCtx, xpathStart);
	}
      if (validItem)
	setItemType(ITEM_TYPE_CONSUMABLE);
    }
  
  xmlXPathFreeContext(xpathCtx);
  xmlFreeDoc(doc);

  //set the name of the item.
  if (validBasicItem)
    setName(name);
  return validItem;
}

void Item::clear()
{
  if (itemType==ITEM_TYPE_EQUIPMENT)
    clearEquipment();
  else if (itemType==ITEM_TYPE_CONSUMABLE)
    clearConsumbale();
  itemName="NULL_INDEX";
  price=100;
  quantity=1;
}

//loads specific fields common to all types of objects.
bool Item::loadItemHelper (xmlDocPtr doc, xmlXPathContextPtr xpathCtx, const string & xpath)
{
  xmlChar * element;
  int intToLoad;
  string stringToLoad;

  //Price. default value of 0.
  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Price", "");
  if (element == NULL)
    intToLoad = 0;
  else
    intToLoad = int(xmlXPathCastStringToNumber(element));
  xmlFree(element);
  setPrice(intToLoad);
  return true;
}
  
//setters and getters for fields common to all items
int Item::getPrice ()
{
  return price;
}
void Item::setPrice (int x)
{
  price=x;
}
  
const string & Item::getName()
{
  return itemName;
}
void Item::setName(const string & name)
{
  itemName=name;
}
  
int Item::getQuantity ()
{
  return quantity;
}
void Item::setQuantity (int x)
{
  quantity=x;
}
void Item::addQuantity (int x)
{
  quantity+=x;
}
  
int Item::getItemType ()
{
  return itemType;
}
void Item::setItemType (int i)
{
  itemType=i;
}

//Equipment-specific stuff
void Item::clearEquipment()
{
  accuracyBoost=0; damageBoost=0; hpBoost=0; pierceBoost=0; armorBoost=0; luckBoost=0; evadeBoost=0; rechargeBoost=0;
  levelRequirements.resize(PLAYER_CLASS_NUMBER, 0);
}

int Item::getAccuracyBoost ()
{
  return accuracyBoost;
}
void Item::setAccuracyBoost (int x)
{
  accuracyBoost=x;
}

int Item::getDamageBoost ()
{
  return damageBoost;
}
void Item::setDamageBoost (int x)
{
  damageBoost=x;
}

int Item::getHealthBoost ()
{
  return hpBoost;
}
void Item::setHealthBoost (int x)
{
  hpBoost=x;
}

int Item::getPierceBoost ()
{
  return pierceBoost;
}
void Item::setPierceBoost (int x)
{
  pierceBoost=x;
}

int Item::getArmorBoost ()
{
  return armorBoost;
}
void Item::setArmorBoost (int x)
{
  armorBoost=x;
}

int Item::getLuckBoost ()
{
  return luckBoost;
}
void Item::setLuckBoost (int x)
{
  luckBoost=x;
}

int Item::getEvadeBoost ()
{
  return evadeBoost;
}
void Item::setEvadeBoost (int x)
{
  evadeBoost=x;
}

int Item::getRechargeBoost ()
{
  return rechargeBoost;
}
void Item::setRechargeBoost (int x)
{
  rechargeBoost=x;
}

int Item::getLevelRequirement (int classID)
{
  if (classID<0 || classID>int(levelRequirements.size()))
    return -1;
  return levelRequirements[classID];
}
void Item::setLevelRequirement (int x, int classID)
{
  if (classID<0 || classID>int(levelRequirements.size()))
    return;

  levelRequirements[classID]=x;
}

bool Item::loadEquipment (xmlDocPtr doc, xmlXPathContextPtr xpathCtx, const string & xpath)
{
  xmlChar * element;
  int temp;

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/AccuracyBoost", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setAccuracyBoost (temp);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/DamageBoost", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setDamageBoost (temp);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/HealthBoost", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setHealthBoost (temp);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/PierceBoost", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setPierceBoost (temp);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/LuckBoost", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setLuckBoost (temp);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/EvadeBoost", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setEvadeBoost (temp);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/RechargeBoost", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setRechargeBoost (temp);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/LevelWarrior", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setLevelRequirement (temp, PLAYER_CLASS_WARRIOR);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/LevelArcher", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setLevelRequirement (temp, PLAYER_CLASS_ARCHER);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/LevelMage", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setLevelRequirement (temp, PLAYER_CLASS_MAGE);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/LevelSwashbuckler", "");
  if (element == NULL)
    temp = 0;
  else
    temp = int(xmlXPathCastStringToNumber(element));
  xmlFree (element);
  setLevelRequirement (temp, PLAYER_CLASS_SWASHBUCKLER);
  return true;
}

int Item::getNumberEquipped ()
{
  return numberEquipped;
}

//Increments numberEquipped, unless numberEquipped == quantity.
//Return false if numberEquipped == quantity.
bool Item::equip ()
{
  if (numberEquipped == quantity)
    return false;

  numberEquipped++;
  return true;
}

//Decrements numberEquipped, unless numberEquipped == 0
//returns false if numberEquipped == 0
bool Item::unequip()
{
  if (numberEquipped == 0)
    return false;

  numberEquipped--;
  return true;
}

//Consumable-specific stuff
void Item::clearConsumbale()
{
  consumableAbility="NULL_INDEX";
}

const string & Item::getConsumableAbility()
{
  return consumableAbility;
}

void Item::setConsumableAbility(const string & name)
{
  consumableAbility=name;
}

bool Item::loadConsumable (xmlDocPtr doc, xmlXPathContextPtr xpathCtx, const string & xpath)
{
  xmlChar * element;
  string gab;

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/AbilityName", "");
  if (element!=NULL)
    {
      gab=((const char *)element);
      xmlFree (element);
      setConsumableAbility (gab);
    }
  return true;
}
