#include "AnimatedAnimation.h"

AnimatedAnimation::AnimatedAnimation ()
{
  clear();
}

AnimatedAnimation::~AnimatedAnimation ()
{
}

void AnimatedAnimation::clear ()
{
  frames.clear();
  sounds.clear();
  ats.clear();
  timeFrameShouldEnd.clear();
  atms.clear();
  numLoops=0;
}

//returns duration of the animation.
uint32_t AnimatedAnimation::getDuration ()
{
  if (timeFrameShouldEnd.size()==0)
    return 0;
  return timeFrameShouldEnd.back();
}

//Returns the graphical frame index the time elapsed falls between.
int32_t AnimatedAnimation::getFrameHelper(uint32_t timeElapsed)
{
  if (getDuration ()==0)
    return -1;

  uint32_t timeElapsedMod = getElapsedTimeInThisLoop(timeElapsed);
  uint32_t loopItsIn = getLoopElapsedTimeIsIn(timeElapsed);

  //If it's past the number of allowed loops, return the last frame.
  //unless numLoops is infinite.
  if (int(loopItsIn)>numLoops && numLoops >= 0)
    return frames.size()-1;

  int frameToReturn = 0, i=0;
  bool done=false;

  while (!done)
    {
      if (timeElapsedMod >= timeFrameShouldEnd[i])
        {
          i++;
        }
      else
        {
          frameToReturn=i;
          done=true;
        }
    }
  return frameToReturn;
}

//Function to mod the duration.
uint32_t AnimatedAnimation::getElapsedTimeInThisLoop(uint32_t timeElapsed)
{
  return timeElapsed % getDuration ();
}

//To get the loop this elapsed time is in.
uint32_t AnimatedAnimation::getLoopElapsedTimeIsIn(uint32_t timeElapsed)
{
  return timeElapsed / getDuration ();
}

int AnimatedAnimation::getNumLoops ()
{
  return numLoops;
}

void AnimatedAnimation::setNumLoops (int l)
{
  numLoops=l;
}

void AnimatedAnimation::getAllGraphicFrames (vector <string> & ans)
{
  vector<string> :: iterator stringIterator;
  stringIterator=frames.begin();
  while (stringIterator!=frames.end())
    {
      ans.push_back(*stringIterator);
      stringIterator++;
    }
}

void AnimatedAnimation::getAllAudioBuffers (vector <string> & ans)
{
  vector<string> :: iterator stringIterator;
  stringIterator=sounds.begin();
  while (stringIterator!=sounds.end())
    {
      ans.push_back(*stringIterator);
      stringIterator++;
    }
}

//adds a frame to the animation.
//frameIndex and soundIndex are the names of the index
//at and atm are transformations.
//time is the duration of this frame.
void AnimatedAnimation::add (Param & hash, AffineTransformationMatrix & atm,
                             AudioTransformation & at)
{
  int tim = 0;
  string frameIndex="NULL_INDEX", soundIndex="NULL_INDEX";

  hash.getInt("Frame Duration", tim);
  hash.getString("Frame", frameIndex);
  hash.getString("Sound", soundIndex);

  //time = 0? reject.
  if (tim == 0)
    return;

  //OK, it's as legal as I can figure.
  if (timeFrameShouldEnd.size()==0)
    timeFrameShouldEnd.push_back(tim);
  else
    timeFrameShouldEnd.push_back(timeFrameShouldEnd.back()+tim);

  frames.push_back(frameIndex);
  sounds.push_back(soundIndex);
  ats.push_back(at);
  atms.push_back(atm);
}


//gets the data to draw and play at the specified time.
//The audio clip to play only works once per frame change.
void AnimatedAnimation::get (Param & hash, AffineTransformationMatrix & atm,
                             AnimatedState & as, AudioTransformation & at)
{
  int tim = 0;
  string frameIndex="NULL_INDEX", soundIndex="NULL_INDEX";
  bool dontGetSound=false;

  hash.getInt("Time Right Now", tim);
  hash.getBool("Do not play sound", dontGetSound);

  uint32_t loopNum = getLoopElapsedTimeIsIn(tim);
  uint32_t indexToGet;

  if (int(loopNum) > numLoops)
    indexToGet=frames.size()-1;
  else
    indexToGet=getFrameHelper(tim);

  frameIndex=frames[indexToGet];
  atm=atms[indexToGet];

  //set variable for sound
  if (!dontGetSound)
    {
      at=ats[indexToGet];
      if (timeFrameShouldEnd[indexToGet]>getElapsedTimeInThisLoop(as.getDoNotPlaySoundUntilThisTime()))
        {
          as.setDoNotPlaySoundUntilThisTime(timeFrameShouldEnd[indexToGet]);
          soundIndex=sounds[indexToGet];
        }
      else
        soundIndex="NULL_INDEX";
    }

  hash.setString("Frame", frameIndex);
  hash.setString("Sound", soundIndex);
}
