#ifndef SHIPPINGHANDLER_H
#define SHIPPINGHANDLER_H

#include <stdint.h>

#include "SDL.h"
#include "SDL_ttf.h"
#include "sge.h"
#include "SDL_mixer.h"
#include "SDL_image.h"

#include "GraphicFont.h"
#include "GraphicBitmap.h"
#include "GraphicPrimitive.h"
#include "GraphicFrame.h"
#include "AudioBuffer.h"
#include "AudioStream.h"
#include "AudioTransformation.h"
#include "AnimatedToon.h"
#include "AnimatedAnimation.h"
#include "AnimatedState.h"
#include "AffineTransformationMatrix.h"

#include "../util/fileUtils.h"
#include "../util/mathUtils.h"
#include "../util/Param.h"
#include "../util/FixedInt.h"

#include "../interface/FormattedText.h"
#include "../interface/TextContainer.h"

#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/tree.h>

#include <vector>
#include <string>
#include <map>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
using namespace std;

#define DRAW_ANCHOR_CENTER 0
#define DRAW_ANCHOR_RIGHT 2
#define DRAW_ANCHOR_LEFT 1
#define DRAW_ANCHOR_DOWN 8
#define DRAW_ANCHOR_UP 4
#define DRAW_ANCHOR_DOWN_RIGHT 10
#define DRAW_ANCHOR_DOWN_LEFT 9
#define DRAW_ANCHOR_UP_RIGHT 6
#define DRAW_ANCHOR_UP_LEFT 5

//this allocates resources to maintaining drawn stuff.

class Session;

class shippingHandler
{
 public:
  shippingHandler ();
  ~shippingHandler ();

  bool Startup ();

  int64_t getObserverX ();
  int64_t getObserverY ();

  void setObserverX (int64_t);
  void setObserverY (int64_t);

  uint16_t getScreenResolutionX ();
  uint16_t getScreenResolutionY ();

  void setScreenResolution (uint16_t, uint16_t);

  void flipScreen ();
  void clearScreen ();
  void setBackgroundColor (uint8_t r, uint8_t g, uint8_t b);
  void clearBackgroundColor ();

  bool loadFont (string & keyName);
  bool loadBitmap (string & keyName);
  bool loadPrimitive (string & keyName);
  bool loadFrame (string & keyName);
  bool loadSound (string & keyName);
  bool loadMusic (string & keyName);
  bool loadToon (string & keyName);

  uint16_t getFontSize (const string & keyName);
  uint16_t getFontSpacing (const string & keyName);
  void getTextDimensions (const string & input, const string & fontName, uint16_t & width, uint16_t & height);
  void getPrimitiveDimensions (const string & name, uint16_t & width, uint16_t & height);
  void getFrameDimensions (const string & name, uint16_t & width, uint16_t & height);
  void calculateDimensions (const string & type, vector<int16_t> &, vector<int16_t> &, vector<int16_t> &, int & w, int & h);
  void calculateDimensions (const string & type, vector<int> &, vector<int> &, vector<int> &, int & w, int & h);
  void calculateDestination (bool respectCamera, int & destX, int & destY);

  void haltAllAudioBuffers();
  void fadeOutAllAudioBuffers(int tim);
  void fadeOutMusic(int tim);
  void pauseMusic ();
  void resumeMusic ();
  void stopMusic ();
  void rewindMusic ();

  void drawFont (const string & str, const string & keyName, int32_t xPos, int32_t yPos, uint8_t colorRed, uint8_t colorGreen, uint8_t colorBlue, bool respectCamera, uint8_t orientation = DRAW_ANCHOR_CENTER);
  void drawFont (Param & hash);
  void drawBitmap (Param & hash, AffineTransformationMatrix & atm);
  void drawPrimitive (Param & hash, AffineTransformationMatrix & atm);
  void drawFrame (Param & hash, AffineTransformationMatrix & atm);
  void animateToon (Param & hash, AffineTransformationMatrix & atmToUse, AnimatedState & as);
  void playSound (const string & keyName, AudioTransformation & at);
  void playMusic (const string & keyName, AudioTransformation & at);

  //draw directly to the buffer.
  void drawPrimitiveCircleDirect (Param & hash);
  void drawPrimitiveFilledPolygonDirect (Param & hash, vector<int>& points);
  void drawPrimitiveLineDirect (Param & hash);
  void drawPrimitiveRectangleDirect (Param & hash);

  void releaseFont (const string & keyName);
  void releaseBitmap (const string & keyName);
  void releasePrimitive (const string & keyName);
  void releaseFrame (const string & keyName);
  void releaseSound (const string & keyName);
  void releaseMusic (const string & keyName);
  void releaseToon (const string & keyName);

  //Dimensions are fixed. Text is added so it wraps within the given width. HeightFactor is out of 16ths.
  void addFormattedTextToFixedDimensions (Param & hash, TextContainer & tc);
  void addFormattedTextToFixedDimensions (Param & hash, vector<vector <FormattedText> > & fmt);
  void addFormattedTextToFixedDimensions (const string & stringToAdd,
                                          const string & fontName,
                                          uint16_t heightFactor,
                                          vector <vector<FormattedText> > & fmt,
                                          uint16_t containerWidth,
                                          bool forceNewLine=false,
                                          int colorIndex=0,
                                          int lineLimit=-1,
                                          const string & helpRef="NULL_INDEX");

  //Formatted text and its newlines are fixed. Calculate the minimum width and height needed to contain it.
  uint16_t getWidthOfLastLine(vector<vector<FormattedText> >&fmt);
  int getLargestStringToFitInWidth(string & stringToUse, string & stringLeftover, uint16_t leftoverWidth, const string & fontName);
  void getNextFormattedTextCoordinate(vector<vector<FormattedText> > & fmt, int & xPos, int & yPos);

  //session
  void setSession (Session *);
  Session * getSession ();

 private:
  bool loadResource (string & keyName, const string & dataType);
  bool loadFontHelper (const string & keyName, GraphicFont & newFont);
  bool loadBitmapHelper (const string & keyName, GraphicBitmap & newFrame);
  bool loadPrimitiveHelper (const string & keyName, GraphicPrimitive &);
  bool loadSoundHelper (const string & keyName, AudioBuffer & newAudio);
  bool loadMusicHelper (const string & keyName, AudioStream & newMusic);
  bool loadToonHelper (const string & keyName, AnimatedToon & newToon);

  bool loadAnimationHelper(xmlDocPtr &, xmlXPathContextPtr &, const string &, AnimatedToon &);
  bool loadAnimationFrameHelper(xmlDocPtr &, xmlXPathContextPtr &, const string &, AnimatedAnimation &);
  bool loadAudioTransformationHelper(xmlDocPtr &, xmlXPathContextPtr &, const string &, AudioTransformation &);
  bool loadGraphicEffectHelper(xmlDocPtr & doc, xmlXPathContextPtr & xpathCtx, const string & xpath, AffineTransformationMatrix & atmToLoad);

  bool loadFrameHelper (const string & keyName, GraphicFrame &);
  bool loadFrameHelper2 (xmlDocPtr doc, xmlXPathContextPtr xpathCtx, const string & xpath, GraphicFrame & gf);

  bool loadPrimitiveHelperRectangle (const string &, GraphicPrimitive &, xmlDocPtr &, xmlXPathContextPtr &);
  bool loadPrimitiveHelperLine (const string &, GraphicPrimitive &, xmlDocPtr &, xmlXPathContextPtr &);
  bool loadPrimitiveHelperCircle (const string &, GraphicPrimitive &, xmlDocPtr &, xmlXPathContextPtr &);
  bool loadPrimitiveHelperEllipse (const string &, GraphicPrimitive &, xmlDocPtr &, xmlXPathContextPtr &);
  bool loadPrimitiveHelperBezier (const string &, GraphicPrimitive &, xmlDocPtr & doc, xmlXPathContextPtr & xpathCtx);
  bool loadPrimitiveHelperTriangle (const string &, GraphicPrimitive &, xmlDocPtr & doc, xmlXPathContextPtr & xpathCtx);
  bool loadPrimitiveHelperFilledPolygon (const string &, GraphicPrimitive &, xmlDocPtr & doc, xmlXPathContextPtr & xpathCtx);

  void drawPrimitiveRectangle (int16_t, int16_t, int16_t, int16_t, GraphicPrimitive & sourceToUse, SDL_Surface * outputSurface, uint8_t colR, uint8_t colG, uint8_t colB, uint8_t alph);
  void drawPrimitiveLine (int16_t x1, int16_t y1, int16_t x2, int16_t y2, GraphicPrimitive & sourceToUse, SDL_Surface * outputSurface, uint8_t colR, uint8_t colG, uint8_t colB, uint8_t alph);
  void drawPrimitiveCircle (int16_t x1, int16_t y1, int16_t diameter, GraphicPrimitive & sourceToUse, SDL_Surface * outputSurface, uint8_t colR, uint8_t colG, uint8_t colB, uint8_t alph);
  void drawPrimitiveEllipse (int16_t x1, int16_t y1, int16_t diameterX, int16_t diameterY, GraphicPrimitive & sourceToUse, SDL_Surface * outputSurface, uint8_t colR, uint8_t colG, uint8_t colB, uint8_t alph);
  void drawPrimitiveBezier (int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, GraphicPrimitive & sourceToUse, SDL_Surface * outputSurface, uint8_t colR, uint8_t colG, uint8_t colB, uint8_t alph);
  void drawPrimitiveFilledPolygon (int16_t, int16_t *, int16_t *, GraphicPrimitive & sourceToUse, SDL_Surface * outputSurface, uint8_t colR, uint8_t colG, uint8_t colB, uint8_t alph);
  void drawPrimitiveTriangle (int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3, GraphicPrimitive & sourceToUse, SDL_Surface * outputSurface, uint8_t colR, uint8_t colG, uint8_t colB, uint8_t alph);

  uint16_t screenResolutionX;
  uint16_t screenResolutionY;

  bool windowedScreen;

  int64_t observerX;
  int64_t observerY;

  SDL_Surface *screen, *screenBuffer;
  uint8_t bkgColorR;
  uint8_t bkgColorG;
  uint8_t bkgColorB;

  int audioFreq;
  Uint16 audioFormat;
  int audioChannels;

  map <string, GraphicFont> fonts;
  map <string, GraphicBitmap> graphicBitmaps;
  map <string, GraphicPrimitive> graphicPrimitives;
  map <string, GraphicFrame> graphicFrames;
  map <string, AudioBuffer> soundBuffers;
  map <string, AudioStream> musicBuffers;
  map <string, AnimatedToon> toons;

  Session * session;
};

#endif
