#include "shippingHandler.h"

void shippingHandler :: drawFrame (Param & hash, AffineTransformationMatrix & atm)
{
  string keyName = "NULL_INDEX";
  int xPos = 0, yPos = 0;
  bool respectCamera=true;

  hash.getString("Resource Name", keyName);
  hash.getInt("X", xPos);
  hash.getInt("Y", yPos);
  hash.getBool("Relative to Camera", respectCamera);

  if (keyName.empty() || keyName == "NULL_INDEX")
    return;

  map <string, GraphicFrame> :: iterator iter2;
  iter2 = graphicFrames.find (keyName);

  if (iter2 == graphicFrames.end())
    return;

  int32_t destX = xPos, destY = yPos;

  destX = xPos;
  destY = yPos;

  //delegate drawing to the subobjects.
  int i, limit = iter2->second.getNumberOfElements();

  string name, type;
  AffineTransformationMatrix atmInProgress;
  Param hash2;

  for (i=0; i < limit; i++)
    {
      atmInProgress.clear();
      iter2->second.getReference(i, type, name, atmInProgress);
      atmInProgress.multiplyMatrix(atm);

      hash2.setString("Resource Name", name);
      hash2.setInt("X", destX);
      hash2.setInt("Y", destY);
      hash2.setBool("Relative to Camera", respectCamera);

      if (type == "Primitive")
        drawPrimitive(hash2, atmInProgress);
      else if (type == "Bitmap")
        drawBitmap(hash2, atmInProgress);
    }
}

void shippingHandler::getFrameDimensions (const string & name, uint16_t & width, uint16_t & height)
{
  width=0, height=0;

  if (name.empty() || name == "NULL_INDEX")
    return;

  map <string, GraphicFrame> :: iterator iter2;
  iter2 = graphicFrames.find (name);

  if (iter2 == graphicFrames.end())
    return;

  uint16_t wa, ha, wa2=0, ha2=0;
  string gab;
  vector <string> :: iterator listIter;

  listIter=iter2->second.getGraphicPrimitiveList().begin();

  wa=iter2->second.getGraphicPrimitiveList().size();

  while (listIter !=iter2->second.getGraphicPrimitiveList().end())
    {
      gab = (*listIter);
      getPrimitiveDimensions(gab,wa,ha);
      if (wa>wa2)
        wa2=wa;
      if (ha>ha2)
        ha2=ha;
      listIter++;
    }

  //later do stuff for bitmaps

  width=wa2;
  height=ha2;
}

void shippingHandler :: releaseFrame (const string & keyName)
{
  if (keyName.empty() || keyName == "NULL_INDEX")
    return;

  map <string, GraphicFrame> :: iterator iter2;
  iter2 = graphicFrames.find (keyName);

  if (iter2 == graphicFrames.end())
    return;

  iter2->second.decRefCount();

  vector<string> :: iterator frameReferenceIter, frameReferenceEndPoint;

  if (iter2->second.getRefCount()==0)
    {
      frameReferenceIter=iter2->second.getGraphicPrimitiveList().begin();
      frameReferenceEndPoint=iter2->second.getGraphicPrimitiveList().end();
      while (frameReferenceIter != frameReferenceEndPoint)
        {
          releasePrimitive(*frameReferenceIter);
          frameReferenceIter++;
        }

      frameReferenceIter=iter2->second.getGraphicBitmapList().begin();
      frameReferenceEndPoint=iter2->second.getGraphicBitmapList().end();

      while (frameReferenceIter != frameReferenceEndPoint)
        {
          releaseBitmap(*frameReferenceIter);
          frameReferenceIter++;
        }
      graphicFrames.erase(iter2);
    }
}


bool shippingHandler :: loadFrame (string & keyName)
{
  //simply a front to loadResource.
  if (keyName.empty() || keyName == "NULL_INDEX")
    {
      keyName="NULL_INDEX";
      return false;
    }

  return loadResource (keyName, "frame");
}

bool shippingHandler :: loadFrameHelper (const string & keyName, GraphicFrame & newFrame)
{
  //attempts to read the file and load the object.

  //parse the xml file and find the filename for the given index
  xmlDocPtr doc;
  xmlXPathContextPtr xpathCtx;
  string xpathStart="/FrameManifest/Frame[@ID='";
  xpathStart+=keyName;
  xpathStart+="']/Element";

  if (!prepareXMLFile (doc, xpathCtx, "resources/FrameManifest.xml", xpathStart))
    {
      writeToErrorLog("LoadFrame: Failed to open FrameManifest or find XPath for "+keyName, 0);
      return false;
    }

  xmlXPathObjectPtr xpathObj;
  xpathObj=getElementsUsingXPath (doc, xpathCtx, xpathStart, "", "");

  if (xpathObj==NULL)
    {
      //Failed to load shape. Cleanup and exit.
      xmlXPathFreeContext(xpathCtx);
      xmlFreeDoc (doc);
      writeToErrorLog ("LoadFrame: Failed to find XML entry for "+keyName, 1);
      return false;
    }

  string idString;
  char searchString [255];

  for (int i=0; i<xpathObj->nodesetval->nodeNr; i++)
    {
      sprintf (searchString, "[%u]", i+1);
      idString=xpathStart+searchString;
      loadFrameHelper2 (doc, xpathCtx, idString, newFrame);
    }

  xmlXPathFreeContext(xpathCtx);
  xmlXPathFreeObject(xpathObj);
  xmlFreeDoc(doc);

  //if there are 0 elements, do not add this object.
  if (newFrame.getNumberOfElements()>0)
    return true;

  writeToErrorLog("LoadFrame: There were no legal elements in the description for "+keyName, 0);
  return false;
}

bool shippingHandler :: loadFrameHelper2 (xmlDocPtr doc, xmlXPathContextPtr xpathCtx, const string & xpath, GraphicFrame & gf)
{
  string frameType, frameName;
  xmlChar *element;
  int16_t xCoord, yCoord;
  AffineTransformationMatrix atm;

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Type", "");
  if (element == NULL)
    return false;

  frameType = (const char *)element;
  xmlFree(element);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Name", "");
  if (element == NULL)
    {
      writeToErrorLog("LoadFrameHelper2: No /Name was found for the element of the XML path "+xpath, 1);
      return false;
    }

  frameName = (const char *)element;
  xmlFree(element);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/X", "");
  if (element == NULL)
    xCoord=0;
  else
    xCoord=int16_t(xmlXPathCastStringToNumber(element));
  xmlFree(element);

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Y", "");
  if (element == NULL)
    yCoord=0;
  else
    yCoord=int16_t(xmlXPathCastStringToNumber(element));
  xmlFree(element);
  atm.shift(xCoord,yCoord);

  if (frameType=="Primitive")
    loadPrimitive(frameName);
  else if (frameType=="Bitmap")
    loadBitmap(frameName);
  else
    writeToErrorLog("LoadFrameHelper2: Unrecognized element type, will probably be rejected: "+xpath, 1);

  return gf.addReference(frameType, frameName, atm);
}
