#include "shippingHandler.h"

shippingHandler::shippingHandler()
{
  screenResolutionX=640;
  screenResolutionY=480;
  windowedScreen=true;
  observerX=0;
  observerY=0;
  screen=NULL;
  screenBuffer=NULL;
  bkgColorR=0;
  bkgColorG=0;
  bkgColorB=0;
}

shippingHandler::~shippingHandler()
{
  map <string, GraphicFont> :: iterator fontsIter;
  fontsIter=fonts.begin();
  while (fontsIter != fonts.end ())
    {
      TTF_CloseFont(fontsIter->second.getFont());
      fontsIter->second.setFont(NULL);
      fonts.erase(fontsIter);
      fontsIter=fonts.begin();
    }

  //you need to release everything in Frames first.
  map <string, GraphicFrame> :: iterator frameIter;
  vector<string> :: iterator frameReferenceIter, frameReferenceEndPoint;
  frameIter=graphicFrames.begin();

  while (frameIter != graphicFrames.end())
    {
      frameReferenceIter=frameIter->second.getGraphicPrimitiveList().begin();
      frameReferenceEndPoint=frameIter->second.getGraphicPrimitiveList().end();
      while (frameReferenceIter != frameReferenceEndPoint)
        {
          releasePrimitive(*frameReferenceIter);
          frameReferenceIter++;
        }

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

      while (frameReferenceIter != frameReferenceEndPoint)
        {
          releaseBitmap(*frameReferenceIter);
          frameReferenceIter++;
        }

      graphicFrames.erase(frameIter);
      frameIter=graphicFrames.begin();
    }

  map <string, GraphicBitmap> :: iterator bitmapIter;
  bitmapIter=graphicBitmaps.begin();
  while (bitmapIter != graphicBitmaps.end())
    {
      SDL_FreeSurface(bitmapIter->second.getPic());
      bitmapIter->second.setPic(NULL);
      graphicBitmaps.erase(bitmapIter);
      bitmapIter=graphicBitmaps.begin();
    }

  map <string, AudioBuffer> :: iterator soundIter;
  soundIter=soundBuffers.begin();
  while (soundIter != soundBuffers.end())
    {
      Mix_FreeChunk(soundIter->second.getSample());
      soundIter->second.setSample(NULL);
      soundBuffers.erase(soundIter);
      soundIter=soundBuffers.begin();
    }

  map <string, AudioStream> :: iterator musicIter;
  musicIter=musicBuffers.begin();
  while (musicIter != musicBuffers.end())
    {
      Mix_FreeMusic(musicIter->second.getStream());
      musicIter->second.setStream(NULL);
      musicBuffers.erase(musicIter);
      musicIter=musicBuffers.begin();
    }

  TTF_Quit ();
  //SDL_Mixer
  Mix_CloseAudio();
  //shtus down SDL processes.
  if (screen != NULL)
    SDL_FreeSurface(screen);
  if (screenBuffer != NULL)
    SDL_FreeSurface(screenBuffer);
  //when quitting
  SDL_Quit ();
}

bool shippingHandler::Startup ()
{
  //this starts SDL.
  //returns true on success
  SDL_ClearError ();
  //first initalize SDL
  if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0){
    writeToErrorLog ("SDLStartup failed", 0);
    writeToErrorLog (SDL_GetError (), 1);
    return false;
  }

  SDL_Rect ** videoModes;

  //read resolution info from a file.
  screenResolutionX = 640;
  screenResolutionY = 480;

  SDL_ClearError ();

  if (windowedScreen)
    screen = SDL_SetVideoMode (screenResolutionX, screenResolutionY, 32, SDL_DOUBLEBUF|SDL_SWSURFACE);
  else
    screen = SDL_SetVideoMode (screenResolutionX, screenResolutionY, 32, SDL_DOUBLEBUF|SDL_FULLSCREEN|SDL_SWSURFACE);
  if (screen == NULL)
    {
      //get the next available resolution
      if (windowedScreen)
        videoModes=SDL_ListModes(NULL, SDL_DOUBLEBUF);
      else
        videoModes=SDL_ListModes(NULL, SDL_DOUBLEBUF|SDL_FULLSCREEN);

      if (videoModes == NULL)
        {
          writeToErrorLog ("Set video mode failed. No available resolutions with these properties: 32 bit, doublebuffered", 0);
          writeToErrorLog (SDL_GetError (), 1);
          return false;
        }
      else //if it videoModes == -1, then the resolution should have set before and shouldn't have been here.
        {
          //videoModes is in no particular order. It should be filtered for the next smallest size.
          //pick the smallest legal size that is above the minimum resolution.
        }
    }

  //make screen buffer
  screenBuffer = SDL_CreateRGBSurface(SDL_SRCALPHA|SDL_SWSURFACE, screen -> w, screen -> h,
                                      screen -> format -> BitsPerPixel,
                                      screen -> format -> Rmask,
                                      screen -> format -> Gmask,
                                      screen -> format -> Bmask,
                                      screen -> format -> Amask);

  SDL_ClearError ();
  if (Mix_OpenAudio (MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 2048) < 0)
    {
      writeToErrorLog ("Error in Mix_OpenAudio", 0);
      writeToErrorLog (Mix_GetError (), 1);
      return false;
    }

  //you need to open the sound system before you query its stats. This is important if this computer doesn't match default settings.
  if (Mix_QuerySpec (&audioFreq, &audioFormat, &audioChannels) == 0)
    {
      writeToErrorLog ("Error while querying sound system", 0);
      return false;
    }

  SDL_ClearError ();
  if(TTF_Init()==-1) {
    writeToErrorLog("Error in TTF", 0);
    writeToErrorLog(TTF_GetError(), 1);
    return false;
  }

  return true;
}

int64_t shippingHandler :: getObserverX ()
{
  return observerX;
}

int64_t shippingHandler :: getObserverY ()
{
  return observerY;
}

void shippingHandler :: setObserverX (int64_t obsx)
{
  observerX = obsx;
}

void shippingHandler :: setObserverY (int64_t obsy)
{
  observerY = obsy;
}

uint16_t shippingHandler :: getScreenResolutionX ()
{
  return screenResolutionX;
}

uint16_t shippingHandler :: getScreenResolutionY ()
{
  return screenResolutionY;
}

void shippingHandler :: setScreenResolution (uint16_t resX, uint16_t resY)
{
  screenResolutionX = resX;
  screenResolutionY = resY;
}

void shippingHandler :: flipScreen ()
{
  //flips the buffer.
  //SDL_Flip(screen);

  SDL_BlitSurface(screenBuffer, NULL, screen, NULL);
  SDL_UpdateRect(screen, 0,0,0,0);
}

void shippingHandler :: clearScreen ()
{
  //clears the buffer
  SDL_Rect dest;

  dest.x = 0;
  dest.y = 0;
  dest.w = screenResolutionX;
  dest.h = screenResolutionY;

  uint32_t bkgColor = SDL_MapRGBA (screenBuffer -> format, bkgColorR, bkgColorG, bkgColorB, 0);

  SDL_FillRect(screenBuffer, &dest, bkgColor);
}

void shippingHandler :: setBackgroundColor (uint8_t r, uint8_t g, uint8_t b)
{
  bkgColorR = r;
  bkgColorG = g;
  bkgColorB = b;
}

void shippingHandler :: clearBackgroundColor ()
{
  setBackgroundColor (0, 0, 0);
}

bool shippingHandler :: loadResource (string & keyName, const string & dataType)
{
  //Looks through the list of resources, seeing if the resource was loaded.
  //If the resource exists already, return true, don't modify keyName.
  //If the resource doesn't exist, try to create the file, access the data, and fill the object.
  //  If that fails, return false, modify keyName to "NULL_INDEX".

  //If the resource exists already, return true, don't modify keyName.
  if (dataType == "font")
    {
        map <string, GraphicFont> :: iterator iter2;
        iter2 = fonts.find (keyName);
        if (iter2 != fonts.end())
          {
            (*iter2).second.incRefCount();
            return true;
          }
    }
  else if (dataType == "bitmap")
    {
        map <string, GraphicBitmap> :: iterator iter2;
        iter2 = graphicBitmaps.find (keyName);
        if (iter2 != graphicBitmaps.end())
          {
            (*iter2).second.incRefCount();
            return true;
          }
    }
  else if (dataType == "primitive")
    {
        map <string, GraphicPrimitive> :: iterator iter2;
        iter2 = graphicPrimitives.find (keyName);
        if (iter2 != graphicPrimitives.end())
          {
            (*iter2).second.incRefCount();
            return true;
          }
    }
  else if (dataType == "frame")
    {
        map <string, GraphicFrame> :: iterator iter2;
        iter2 = graphicFrames.find (keyName);
        if (iter2 != graphicFrames.end())
          {
            (*iter2).second.incRefCount();
            return true;
          }
    }
  else if (dataType == "sound")
    {
        map <string, AudioBuffer> :: iterator iter2;
        iter2 = soundBuffers.find (keyName);
        if (iter2 != soundBuffers.end())
          {
            (*iter2).second.incRefCount();
            return true;
          }
    }
  else if (dataType == "music")
    {
      map <string, AudioStream> :: iterator iter2;
      iter2 = musicBuffers.find (keyName);
      if (iter2 != musicBuffers.end())
        {
          (*iter2).second.incRefCount();
          return true;
        }
    }
  else if (dataType == "toon")
    {
      map <string, AnimatedToon> :: iterator iter2;
      iter2 = toons.find (keyName);
      if (iter2 != toons.end())
        {
          (*iter2).second.incRefCount();
          return true;
        }
    }
  else
    {
      keyName = "NULL_INDEX";
      return false;
    }

  //If the resource doesn't exist, try to create the file, access the data, and fill the object.
  //  If that fails, return false, modify keyName to "NULL_INDEX".
  if (dataType == "font")
    {
      GraphicFont newFont;
      if (!loadFontHelper (keyName, newFont))
        {
          keyName="NULL_INDEX";
          return false;
        }
      newFont.incRefCount();
      fonts[keyName]=newFont;
    }
  else if (dataType == "bitmap")
    {
      GraphicBitmap newBitmap;
      if (!loadBitmapHelper (keyName, newBitmap))
        {
          keyName="NULL_INDEX";
          return false;
        }
      newBitmap.incRefCount();
      graphicBitmaps[keyName]=newBitmap;
    }
  else if (dataType == "primitive")
    {
      GraphicPrimitive newPrimitive;
      if (!loadPrimitiveHelper (keyName, newPrimitive))
        {
          keyName="NULL_INDEX";
          return false;
        }
      newPrimitive.incRefCount();
      graphicPrimitives[keyName]=newPrimitive;
    }
  else if (dataType == "frame")
    {
      GraphicFrame newFrame;
      if (!loadFrameHelper (keyName, newFrame))
        {
          keyName="NULL_INDEX";
          return false;
        }
      newFrame.incRefCount();
      graphicFrames[keyName]=newFrame;
    }
  else if (dataType == "sound")
    {
      AudioBuffer newSound;
      if (!loadSoundHelper (keyName, newSound))
        {
          keyName="NULL_INDEX";
          return false;
        }
      newSound.incRefCount();
      soundBuffers[keyName]=newSound;
    }
  else if (dataType == "music")
    {
      AudioStream newMusic;
      if (!loadMusicHelper (keyName, newMusic))
        {
          keyName="NULL_INDEX";
          return false;
        }
      newMusic.incRefCount();
      musicBuffers[keyName]=newMusic;
    }
  else if (dataType == "toon")
    {
      AnimatedToon newToon;
      if (!loadToonHelper (keyName, newToon))
        {
          keyName="NULL_INDEX";
          return false;
        }
      newToon.incRefCount();
      toons[keyName]=newToon;
    }
  else
    {
      keyName = "NULL_INDEX";
      return false;
    }
  return true;
}

bool shippingHandler::loadAudioTransformationHelper(xmlDocPtr & doc, xmlXPathContextPtr & xpathCtx, const string & xpath, AudioTransformation & atToLoad)
{
  xmlChar *element;
  int tempInt, tempInt2;
  double tempDouble;

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Volume", "");
  if (element != NULL)
    {
      tempInt=int(xmlXPathCastStringToNumber(element))%256;
      xmlFree(element);
      atToLoad.setVolume(tempInt);
    }

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/FadeIn", "");
  if (element != NULL)
    {
      tempInt=int(xmlXPathCastStringToNumber(element));
      xmlFree(element);
      atToLoad.setTransformFlag(atToLoad.getTransformFlag()|AUDIO_TRANSFORMATION_FADE_IN);
      atToLoad.setFadeInTime(tempInt);
    }

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/FadeOut", "");
  if (element != NULL)
    {
      tempInt=int(xmlXPathCastStringToNumber(element));
      xmlFree(element);
      atToLoad.setTransformFlag(atToLoad.getTransformFlag()|AUDIO_TRANSFORMATION_FADE_OUT);
      atToLoad.setFadeOutTime(tempInt);
    }

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/StartTime", "");
  if (element != NULL)
    {
      tempDouble=xmlXPathCastStringToNumber(element);
      xmlFree(element);
      atToLoad.setTransformFlag(atToLoad.getTransformFlag()|AUDIO_TRANSFORMATION_START_TIME);
      atToLoad.setStartTime(tempDouble);
    }

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Loops", "");
  if (element != NULL)
    {
      tempInt=int(xmlXPathCastStringToNumber(element));
      xmlFree(element);
      atToLoad.setNumberOfLoops(tempInt);
    }

  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Panning/Left", "");
  if (element != NULL)
    {
      tempInt=int16_t(xmlXPathCastStringToNumber(element));
      xmlFree(element);
      element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Panning/Right", "");
      if (element != NULL)
        {
          tempInt2=int16_t(xmlXPathCastStringToNumber(element));
          xmlFree(element);
          atToLoad.setTransformFlag(atToLoad.getTransformFlag()|AUDIO_TRANSFORMATION_PANNING);
          atToLoad.setPanning(tempInt,tempInt2);
        }
    }

  return true;
}

//sets and gets Session
void shippingHandler::setSession (Session * ses)
{
  session = ses;
}

Session * shippingHandler::getSession ()
{
  return session;
}
