#include "Renderer.h"

Renderer :: Renderer ()
{
  initialize ();
}

Renderer :: ~Renderer ()
{
  //You should empty your resources here.
}

bool Renderer :: initialize ()
{
  sge_CalibrateDelay();
  return true;
}

//33 ms since the last screenDelay call should have passed. If less time has passed, it waits here
void Renderer :: screenDelay ()
{
  int lastFrame = 0;
  session -> getInt ("Last Frame Tick", lastFrame);

  if (int(SDL_GetTicks ()) < 33 + lastFrame)
    sge_Delay(lastFrame + 33 - SDL_GetTicks ());

  session -> setInt ("Last Frame Tick", SDL_GetTicks());
}

//load the correct type of resource and store the results into this resource handler.
bool Renderer::loadToResourceHandler(const string & key, const string & resourceName, int resourceType, ResourceHandler & rh)
{
  string resourceToLoad=resourceName;
  //switch case based on type here
  switch(resourceType)
    {
    case(RESOURCE_TYPE_FONT):
      session->getShippingHandler()->loadFont(resourceToLoad);
      break;
    case(RESOURCE_TYPE_BITMAP):
      session->getShippingHandler()->loadBitmap(resourceToLoad);
      break;
    case(RESOURCE_TYPE_PRIMITIVE):
      session->getShippingHandler()->loadPrimitive(resourceToLoad);
      break;
    case(RESOURCE_TYPE_SOUND):
      session->getShippingHandler()->loadSound(resourceToLoad);
      break;
    case(RESOURCE_TYPE_MUSIC):
      session->getShippingHandler()->loadMusic(resourceToLoad);
      break;
    case(RESOURCE_TYPE_TOON):
      session->getShippingHandler()->loadToon(resourceToLoad);
      break;
    case(RESOURCE_TYPE_FRAME):
      session->getShippingHandler()->loadFrame(resourceToLoad);
      break;
    default:
      resourceToLoad="NULL_INDEX";
      break;
    };

  if (resourceToLoad=="NULL_INDEX")
    return false;

  rh.addResource(key,resourceToLoad,resourceType);
  return true;
}

//remove the resource from this resource handler. Unload it, too.
//returns true if rh contains a hash with a key equal to key.
//It will unload the refence from the shippingHandler.
//If the ResourceHandler does not have the resource, it is not removed and this returns false.
bool Renderer::removeFromResourceHandler(const string & key, ResourceHandler & rh)
{
  string resourceToRemove;
  int resourceType;

  resourceType=rh.getResourceType(key);
  rh.getResourceName(key,resourceToRemove);

  switch(resourceType)
    {
    case(RESOURCE_TYPE_FONT):
      session->getShippingHandler()->releaseFont(resourceToRemove);
      break;
    case(RESOURCE_TYPE_BITMAP):
      session->getShippingHandler()->releaseBitmap(resourceToRemove);
      break;
    case(RESOURCE_TYPE_PRIMITIVE):
      session->getShippingHandler()->releasePrimitive(resourceToRemove);
      break;
    case(RESOURCE_TYPE_SOUND):
      session->getShippingHandler()->releaseSound(resourceToRemove);
      break;
    case(RESOURCE_TYPE_MUSIC):
      session->getShippingHandler()->releaseMusic(resourceToRemove);
      break;
    case(RESOURCE_TYPE_TOON):
      session->getShippingHandler()->releaseToon(resourceToRemove);
      break;
    case(RESOURCE_TYPE_FRAME):
      session->getShippingHandler()->releaseFrame(resourceToRemove);
      break;
    default:
      resourceToRemove="NULL_INDEX";
      break;
    };

  //return false if it failed
  if (resourceToRemove=="NULL_INDEX")
    return false;

  //tell rh to remove the resource.
  rh.removeResource (key);
  return true;
}

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

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

//loading resources based on state
void Renderer::startStateLoadResources (int state)
{
  stateManageResources(state, RENDERER_LOAD_RESOURCES);
}

void Renderer::endStateReleaseResources (int state)
{
  stateManageResources(state, RENDERER_RELEASE_RESOURCES);
}

void Renderer::stateManageResources (int state, int operation)
{
  int i;

  bool startedBattle=false;
  session->getBool("Started Battle", startedBattle);

  //loading common battle resources
  switch (state)
    {
    case(STATE_ATTACK_PREVIEW):
    case(STATE_ATTACK_DRAWING):
    case(STATE_ATTACK_FINISHED):
    case(STATE_ATTACK_WAIT_FOR_USER):
    case(STATE_DEFEND_CLICKING):
      if (!startedBattle && operation == RENDERER_LOAD_RESOURCES)
        {
          //load all the rules required to start a battle.
          loadToResourceHandler("Battle Clickzone","debugBattleClickzone",RESOURCE_TYPE_FRAME,resources);
          loadToResourceHandler("Attack Path Circle","AttackCircle",RESOURCE_TYPE_FRAME,resources);
          loadToResourceHandler("Attack Path Zone","AttackZone",RESOURCE_TYPE_FRAME,resources);
        }
      break;
    };

  switch (state)
    {
      //initial state: fonts
    case(STATE_INITIALIZE):
      if (operation == RENDERER_LOAD_RESOURCES)
        {
          loadToResourceHandler("Font 16","DebugFont",RESOURCE_TYPE_FONT,resources);
          loadToResourceHandler("Font 30","DebugFontHuge",RESOURCE_TYPE_FONT,resources);

	  //stats display
	  loadToResourceHandler("Health Icon","Player Status Health Icon",RESOURCE_TYPE_FRAME,resources);
	  loadToResourceHandler("Accuracy Icon","Player Status Accuracy Icon",RESOURCE_TYPE_FRAME,resources);
	  loadToResourceHandler("Armor Icon","Player Status Armor Icon",RESOURCE_TYPE_FRAME,resources);
	  loadToResourceHandler("Damage Icon","Player Status Damage Icon",RESOURCE_TYPE_FRAME,resources);
	  loadToResourceHandler("Evade Icon","Player Status Evade Icon",RESOURCE_TYPE_FRAME,resources);
	  loadToResourceHandler("Luck Icon","Player Status Luck Icon",RESOURCE_TYPE_FRAME,resources);
	  loadToResourceHandler("Pierce Icon","Player Status Pierce Icon",RESOURCE_TYPE_FRAME,resources);
        }
      else if (operation == RENDERER_RELEASE_RESOURCES)
        {
          removeFromResourceHandler("Font 16",resources);
          removeFromResourceHandler("Font 30",resources);

	  removeFromResourceHandler("Player Status Health Icon",resources);
	  removeFromResourceHandler("Player Status Accuracy Icon",resources);
	  removeFromResourceHandler("Player Status Armor Icon",resources);
	  removeFromResourceHandler("Player Status Damage Icon",resources);
	  removeFromResourceHandler("Player Status Evade Icon",resources);
	  removeFromResourceHandler("Player Status Luck Icon",resources);
	  removeFromResourceHandler("Player Status Pierce Icon",resources);
        }
      break;
    case(STATE_TEST):
      if (operation == RENDERER_LOAD_RESOURCES)
        {
          loadToResourceHandler("Test resource","debugToon",RESOURCE_TYPE_TOON,resources);
          loadToResourceHandler("Test resource2","debugRect2",RESOURCE_TYPE_PRIMITIVE,resources);

          animatedS.setAnimation("default");
          animatedS.play();
        }
      else if (operation == RENDERER_RELEASE_RESOURCES)
        {
          removeFromResourceHandler("Test resource", resources);
          removeFromResourceHandler("Test resource2", resources);
        }
      break;
    case(STATE_ATTACK_PREVIEW):
      if (operation == RENDERER_LOAD_RESOURCES)
        {
          //load attack path button icons
          vector <string> buttonIconResources;
          session->getRules()->getButtonIcons(buttonIconResources);
          for (i=0;i<int(buttonIconResources.size());i++)
            session->getShippingHandler()->loadFrame(buttonIconResources[i]);
        }
      else if (operation == RENDERER_RELEASE_RESOURCES)
        {
          vector <string> buttonIconResources;
          session->getRules()->getButtonIcons(buttonIconResources);
          for (i=0;i<int(buttonIconResources.size());i++)
            session->getShippingHandler()->releaseFrame(buttonIconResources[i]);
        }
      break;
    case(STATE_ATTACK_DRAWING):
      break;
    default:
      break;
    };
}

//dispatcher to draw various states.
void Renderer::drawState(int state)
{
  string textToPrint, fontHeaderIndex;
  Param hash;

  switch (state)
    {
    case(STATE_PLAYER_ATTACKS):
      drawStatePlayerAttacks();
      break;
    case(STATE_BATTLE_SWITCH_ROUND):
      drawStateBattleSwitchRound();
      break;
    case(STATE_TEST):
      drawStateTest();
      break;
    case(STATE_ATTACK_PREVIEW):
      drawStateAttackPreview();
      break;
    case(STATE_ATTACK_DRAWING):
      drawStateAttackDrawing();
      break;
    case(STATE_ATTACK_WAIT_FOR_USER):
      drawStateAttackWaitForUser();
      break;
    case(STATE_DEFEND_CLICKING):
      drawStateDefendClicking();
      break;
    default:
      resources.getResourceName ("Font 30",fontHeaderIndex);
      convertIntToString (state, textToPrint);
      hash.setString("String", "Stub for state index "+textToPrint);
      hash.setString("Resource Name", fontHeaderIndex);
      hash.setInt("X", 0);
      hash.setInt("Y", -220);
      hash.setInt("Red", 176);
      hash.setInt("Green", 176);
      hash.setInt("Blue", 176);
      hash.setBool("Relative to Camera", true);
      session->getShippingHandler() -> drawFont (hash);
      break;
    };
}

/////////////////////////////////////////////////////////
///Macro/helper functions here


//Macro for drawing a Power Selector.
//Shading is a vector full of how much shading should exist in the powers.
//Symbols contain the resource names of which objects should be in there.
void Renderer::drawPowerSelector(vector<FixedInt> & shading, vector<string> & symbols)
{
  int selectedIndex = session->getPowerSelector()->getSelected();
  Param unselectedFore, unselectedBack, selectedFore, selectedBack, shade, symbol;
  AffineTransformationMatrix atm, selectedAtm;
  unselectedFore.setInt("Red", 32);
  unselectedFore.setInt("Green", 32);
  unselectedFore.setInt("Blue", 32);
  unselectedFore.setBool("Filled", true);

  unselectedBack.setInt("Red", 0);
  unselectedBack.setInt("Green", 0);
  unselectedBack.setInt("Blue", 0);
  unselectedBack.setBool("Filled", true);

  selectedFore.setInt("Red", 48);
  selectedFore.setInt("Green", 48);
  selectedFore.setInt("Blue", 48);
  selectedFore.setBool("Filled", true);

  selectedBack.setInt("Red", 255);
  selectedBack.setInt("Green", 255);
  selectedBack.setInt("Blue", 255);
  selectedBack.setBool("Filled", true);

  shade.setInt("Red", 0);
  shade.setInt("Green", 0);
  shade.setInt("Blue", 0);
  shade.setInt("Alpha", 128);
  shade.setBool("Filled", true);

  symbol.setBool("Relative to Camera", false);
  selectedAtm.scale(FixedInt(1.5), FixedInt(1.5));

  uint16_t boxWidth=session->getPowerSelector()->getIndividualBoxWidth(), boxHeight=session->getPowerSelector()->getIndividualBoxHeight();
  int posX=session->getPowerSelector()->getPositionX(), posY=session->getPowerSelector()->getPositionY();

  //coordinates refer to the center of the block.

  int leftSide=posX-(3*boxWidth/2), topSide=posY-boxHeight;
  int blockWidth=boxWidth, blockHeight=boxWidth;
  int selectedBlockWidth=blockWidth*3/2, selectedBlockHeight=blockHeight*3/2;

  //draw blocks, unselected first.
  for (int i=0; i < 9; i++)
    {
      if (i!=selectedIndex)
        {
          unselectedBack.setInt("X1", leftSide-(blockWidth/2)+(blockWidth*(i%3)));
          unselectedBack.setInt("Y1", topSide-(blockHeight/2)+(blockHeight*(i/3)));
          unselectedBack.setInt("X2", leftSide-(blockWidth/2)+(blockWidth*(i%3))+blockWidth);
          unselectedBack.setInt("Y2", topSide-(blockHeight/2)+(blockHeight*(i/3))+blockHeight);
          session->getShippingHandler()->drawPrimitiveRectangleDirect(unselectedBack);

          unselectedFore.setInt("X1", leftSide-(blockWidth/2)+(blockWidth*(i%3))+1);
          unselectedFore.setInt("Y1", topSide-(blockHeight/2)+(blockHeight*(i/3))+1);
          unselectedFore.setInt("X2", leftSide-(blockWidth/2)+(blockWidth*(i%3))+blockWidth-1);
          unselectedFore.setInt("Y2", topSide-(blockHeight/2)+(blockHeight*(i/3))+blockHeight-1);
          session->getShippingHandler()->drawPrimitiveRectangleDirect(unselectedFore);

          //draw the icon now
          if (i<int(symbols.size()))
            {
              symbol.setString("Resource Name", symbols[i]);
              symbol.setInt("X", leftSide+(blockWidth*(i%3)));
              symbol.setInt("Y", topSide+(blockHeight*(i/3)));
              session->getShippingHandler()->drawFrame(symbol, atm);
            }
          //draw the shade now
        }
    }
  //draw the wait button.
  if (selectedIndex!=9)
    {
      unselectedBack.setInt("X1", leftSide-(blockWidth/2)+(blockWidth*3));
      unselectedBack.setInt("Y1", topSide-(blockHeight/2));
      unselectedBack.setInt("X2", leftSide-(blockWidth/2)+(blockWidth*4));
      unselectedBack.setInt("Y2", topSide-(blockHeight/2)+(blockHeight*3));
      session->getShippingHandler()->drawPrimitiveRectangleDirect(unselectedBack);

      unselectedFore.setInt("X1", leftSide-(blockWidth/2)+(blockWidth*3)+1);
      unselectedFore.setInt("Y1", topSide-(blockHeight/2)+1);
      unselectedFore.setInt("X2", leftSide-(blockWidth/2)+(blockWidth*4)-1);
      unselectedFore.setInt("Y2", topSide-(blockHeight/2)+(blockHeight*3)-1);
      session->getShippingHandler()->drawPrimitiveRectangleDirect(unselectedFore);
      //draw wait's symbol here.
      if (symbols.size()>=10)
        {
          symbol.setString("Resource Name", symbols[9]);
          symbol.setInt("X", leftSide+(blockWidth*3));
          symbol.setInt("Y", topSide+(blockHeight*3/2));
          session->getShippingHandler()->drawFrame(symbol, atm);
        }
    }

  //draw the selected blocks
  if (selectedIndex>=0 && selectedIndex<9)
    {
      selectedBack.setInt("X1", leftSide-(selectedBlockWidth/2)+(blockWidth*(selectedIndex%3)));
      selectedBack.setInt("Y1", topSide-(selectedBlockHeight/2)+(blockHeight*(selectedIndex/3)));
      selectedBack.setInt("X2", leftSide-(selectedBlockWidth/2)+(blockWidth*(selectedIndex%3))+selectedBlockWidth);
      selectedBack.setInt("Y2", topSide-(selectedBlockHeight/2)+(blockHeight*(selectedIndex/3))+selectedBlockHeight);
      session->getShippingHandler()->drawPrimitiveRectangleDirect(selectedBack);

      selectedFore.setInt("X1", leftSide-(selectedBlockWidth/2)+(blockWidth*(selectedIndex%3))+1);
      selectedFore.setInt("Y1", topSide-(selectedBlockHeight/2)+(blockHeight*(selectedIndex/3))+1);
      selectedFore.setInt("X2", leftSide-(selectedBlockWidth/2)+(blockWidth*(selectedIndex%3))+selectedBlockWidth-1);
      selectedFore.setInt("Y2", topSide-(selectedBlockHeight/2)+(blockHeight*(selectedIndex/3))+selectedBlockHeight-1);
      session->getShippingHandler()->drawPrimitiveRectangleDirect(selectedFore);

      //draw the icon now
      if (selectedIndex<int(symbols.size()))
        {
          symbol.setString("Resource Name", symbols[selectedIndex]);
          symbol.setInt("X", leftSide+(blockWidth*(selectedIndex%3)));
          symbol.setInt("Y", topSide+(blockHeight*(selectedIndex/3)));
          session->getShippingHandler()->drawFrame(symbol, selectedAtm);
        }

      //draw the shade now
    }
  //finally draw the wait block.
  if (selectedIndex==9)
    {
      selectedBack.setInt("X1", leftSide-(selectedBlockWidth/2)+(blockWidth*3));
      selectedBack.setInt("Y1", topSide-(selectedBlockHeight/2));
      selectedBack.setInt("X2", leftSide-(selectedBlockWidth/2)+(blockWidth*3)+selectedBlockWidth);
      selectedBack.setInt("Y2", topSide-(selectedBlockHeight/2)+(blockHeight*2)+selectedBlockHeight);
      session->getShippingHandler()->drawPrimitiveRectangleDirect(selectedBack);

      selectedFore.setInt("X1", leftSide-(selectedBlockWidth/2)+(blockWidth*3)+1);
      selectedFore.setInt("Y1", topSide-(selectedBlockHeight/2)+1);
      selectedFore.setInt("X2", leftSide-(selectedBlockWidth/2)+(blockWidth*3)+selectedBlockWidth-1);
      selectedFore.setInt("Y2", topSide-(selectedBlockHeight/2)+(blockHeight*2)+selectedBlockHeight-1);
      session->getShippingHandler()->drawPrimitiveRectangleDirect(selectedFore);

      //draw wait's symbol here.
      if (symbols.size()>=10)
        {
          symbol.setString("Resource Name", symbols[9]);
          symbol.setInt("X", leftSide+(blockWidth*3));
          symbol.setInt("Y", topSide+(blockHeight*3/2));
          session->getShippingHandler()->drawFrame(symbol, selectedAtm);
        }
    }
}

//The text container holds a certain portion of text.
void Renderer::drawTextContainer(TextContainer & tc)
{
  //get the upper left corner and iterate through.
  int leftSide, topSide;
  int firstLineVerticalOffset;
  Param textPrintOption;
  string fontName=tc.getFontName();

  vector <vector<FormattedText> > :: iterator lineToDraw, endOfLinesToDraw;
  vector<FormattedText> :: iterator textToDraw, endOfTextToDraw;

  leftSide=tc.getPositionX()-(tc.getTextContainerWidth()/2)+tc.getMarginLeft();
  topSide=tc.getPositionY()-(tc.getTextContainerHeight()/2)+tc.getMarginTop();
  tc.getVisibleText (firstLineVerticalOffset, lineToDraw, endOfLinesToDraw);

  while (lineToDraw!=endOfLinesToDraw)
    {
      textToDraw=lineToDraw->begin();
      endOfTextToDraw=lineToDraw->end();
      while(textToDraw!=endOfTextToDraw)
        {
          textPrintOption.setString("String", textToDraw->getText());
          textPrintOption.setString("Resource Name", fontName);
          textPrintOption.setInt("X", leftSide+textToDraw->getX());
          textPrintOption.setInt("Y", topSide+textToDraw->getY()-firstLineVerticalOffset);
          textPrintOption.setInt("Red", tc.getFontColorR(textToDraw->getColorIndex()));
          textPrintOption.setInt("Green", tc.getFontColorG(textToDraw->getColorIndex()));
          textPrintOption.setInt("Blue", tc.getFontColorB(textToDraw->getColorIndex()));
          textPrintOption.setInt("Orientation", DRAW_ANCHOR_UP_LEFT);
          textPrintOption.setBool("Relative to Camera", false);
          session->getShippingHandler()->drawFont(textPrintOption);
          textToDraw++;
        }
      lineToDraw++;
    }
}

/////////////////////////////////////////////////////////
///Utilities and modular entities
void Renderer::drawPlayerStats(const string & detailLevel)
{
  Param options;
  AffineTransformationMatrix atm;
  string intConversion;
  string resourceName;

  //print the mouse's location
  int mouseX=-1, mouseY=-1;
  string mouseXConversion, mouseYConversion, mouseLocationString;
  session->getParamNew()->getInt("Test Mouse X", mouseX);
  session->getParamNew()->getInt("Test Mouse Y", mouseY);
  convertIntToString(mouseX,mouseXConversion);
  convertIntToString(mouseY,mouseYConversion);
  mouseLocationString="("+mouseXConversion+","+mouseYConversion+")";

  options.clear();
  resources.getResourceName("Font 16", resourceName);
  options.setString("String", mouseLocationString);
  options.setString("Resource Name", resourceName);
  options.setInt("X", 0);
  options.setInt("Y", 0);
  options.setInt("Red", 255);
  options.setInt("Green", 255);
  options.setInt("Blue", 255);
  options.setBool("Relative to Camera", false);
  options.setInt("Orientation", DRAW_ANCHOR_UP_LEFT);
  session->getShippingHandler()->drawFont(options);

  if (detailLevel=="Battle Basic")
    {
      convertIntToString(session->getRules()->getPlayer()->getCurrentHealth(),intConversion);
      intConversion+="/";
      convertIntToStringAppend(session->getRules()->getPlayer()->getHealth(),intConversion);
      drawStat(60,360,"Health",intConversion);
      convertIntToString(session->getRules()->getPlayer()->getPierce(),intConversion);
      drawStat(20,390,"Pierce",intConversion);
      convertIntToString(session->getRules()->getPlayer()->getDamage(),intConversion);
      drawStat(100,390,"Damage",intConversion);
      convertIntToString(session->getRules()->getPlayer()->getArmor(),intConversion);
      drawStat(20,430,"Armor",intConversion);
      convertIntToString(session->getRules()->getPlayer()->getEvade(),intConversion);
      drawStat(100,430,"Evade",intConversion);
      convertIntToString(session->getRules()->getPlayer()->getLuck(),intConversion);
      drawStat(60,460,"Luck",intConversion);

      //draw the player's name above the stats.
      options.clear();
      resources.getResourceName("Font 16", resourceName);
      options.setString("String", session->getRules()->getPlayer()->getName());
      options.setString("Resource Name", resourceName);
      options.setInt("X", 80);
      options.setInt("Y", 320);
      options.setInt("Red", 255);
      options.setInt("Green", 255);
      options.setInt("Blue", 255);
      options.setBool("Relative to Camera", false);
      options.setInt("Orientation", DRAW_ANCHOR_UP);
      session->getShippingHandler()->drawFont(options);
    }
}

//draws a particular stat.
void Renderer::drawStat (int x, int y, const string & stat, const string & intConversion)
{
  string resourceName="NULL_INDEX";
  Param options;
  AffineTransformationMatrix atm;

  options.clear(); atm.clear();

  if (stat=="Health")
    resources.getResourceName("Health Icon", resourceName);
  else if (stat=="Pierce")
    resources.getResourceName("Pierce Icon", resourceName);
  else if (stat=="Damage")
    resources.getResourceName("Damage Icon", resourceName);
  else if (stat=="Armor")
    resources.getResourceName("Armor Icon", resourceName);
  else if (stat=="Evade")
    resources.getResourceName("Evade Icon", resourceName);
  else if (stat=="Luck")
    resources.getResourceName("Luck Icon", resourceName);

  options.setString("Resource Name", resourceName);
  options.setInt("X", x);
  options.setInt("Y", y);
  options.setBool("Relative to Camera", false);
  session->getShippingHandler()->drawFrame(options, atm);

  options.clear();
  resources.getResourceName("Font 16", resourceName);
  options.setString("String", intConversion);
  options.setString("Resource Name", resourceName);
  options.setInt("X", x+20);
  options.setInt("Y", y);
  options.setInt("Red", 255);
  options.setInt("Green", 255);
  options.setInt("Blue", 255);
  options.setBool("Relative to Camera", false);
  options.setInt("Orientation", DRAW_ANCHOR_LEFT);
  session->getShippingHandler()->drawFont(options);
}

/////////////////////////////////////////////////////////
///Specific phases are below

void Renderer::drawStatePlayerAttacks()
{
  string battleClickzone;
  Param hash;
  AffineTransformationMatrix atm;

  resources.getResourceName ("Battle Clickzone",battleClickzone);

  hash.setString("Resource Name", battleClickzone);
  hash.setInt("X", 320);
  hash.setInt("Y", 70+125);
  hash.setBool("Relative to Camera", false);
  session->getShippingHandler()->drawFrame (hash, atm);

  //now draw the attack path
  hash.clearParamState();

  string attackPathCircle;
  int attackPathStartX, attackPathStartY, attackPathRadius;
  vector <HitBox> :: iterator firstPoint;
  map<string, AttackPath>::iterator attackPath;
  if (session->getRules()->getAttackPath(attackPath))
    {
      firstPoint=attackPath->second.getFirstPoint();

      attackPathRadius=attackPath->second.getInitialRadius();
      attackPathStartX=firstPoint->getPosX();
      attackPathStartY=firstPoint->getPosY();

      resources.getResourceName ("Attack Path Circle",attackPathCircle);
      hash.setString("Resource Name", attackPathCircle);
      hash.setInt("X", attackPathStartX);
      hash.setInt("Y", attackPathStartY);
      hash.setBool("Relative to Camera", false);
      atm.scale(attackPathRadius*2, attackPathRadius*2);

      session->getShippingHandler()->drawFrame (hash, atm);
    }
}

void Renderer::stateStartPlayerAttacks()
{
  string battleClickzone;
  uint16_t width, height;

  resources.getResourceName ("Battle Clickzone",battleClickzone);
  session->getShippingHandler()->getPrimitiveDimensions (battleClickzone, width, height);

  session->setInt("Battle Clickzone X", 320);
  session->setInt("Battle Clickzone Y", 70+125);
}

void Renderer::drawStateBattleSwitchRound()
{
  bool mouseWasClicked=false;
  session->getParamOld()->getBool("Mouse Hit", mouseWasClicked);
  string dumpString, textToPrint, fontHeaderIndex;
  Param hash;
  int mouseX, mouseY, mouseButt;

  if (mouseWasClicked)
    {
      resources.getResourceName ("Font 30",fontHeaderIndex);
      session->getParamOld()->getInt("X Pos", mouseX);
      session->getParamOld()->getInt("Y Pos", mouseY);
      session->getParamOld()->getInt("Button", mouseButt);
      convertIntToString (mouseX, dumpString);
      textToPrint = "Mouse clicked at ("+dumpString;
      convertIntToString (mouseY, dumpString);
      textToPrint += ","+dumpString;
      convertIntToString (mouseButt, dumpString);
      textToPrint += ") With button "+dumpString;
      hash.setString("String", textToPrint);
      hash.setString("Resource Name", fontHeaderIndex);
      hash.setInt("X", 320);
      hash.setInt("Y", 15);
      hash.setInt("Red", 255);
      hash.setInt("Green", 255);
      hash.setInt("Blue", 255);
      hash.setBool("Relative to Camera", false);
      session->getShippingHandler() -> drawFont (hash);
    }
}

//Test phase
void Renderer::stateStartTest()
{
}

void Renderer::drawStateTest()
{
  string primResource="NULL_INDEX", primResource2="NULL_INDEX";
  Param hash, hash2;
  int angle=0;

  AffineTransformationMatrix atm, atm2;

  resources.getResourceName("Test resource",primResource);
  resources.getResourceName("Test resource2",primResource2);

  session->getParamNew()->getInt("angle", angle);
  angle++;
  angle %= 256;
  session->getParamNew()->setInt("angle", angle);

  hash.setString("Resource Name", primResource);
  hash.setInt("X", 40);
  hash.setInt("Y", 0);

  hash2.setString("Resource Name", primResource);
  hash2.setInt("X", -40);
  hash2.setInt("Y", 0);

  int test = 0;

  switch (test)
    {
    case(1):
      //test 1: Rotate
      atm.rotate(angle);
      break;
    case(2):
      //test 2: Rotate around a different point.
      atm.shift(25, 40);
      atm.rotate(angle);
      atm.shift(-25, -40);
      break;
    case(3):
      //test 3: Scaling uniformly.
      atm.scale(2,2);
      break;
    case(4):
      //test 4: Scaling Width
      atm.scale(2,1);
      break;
    case(5):
      //test 5: Scaling Height
      atm.scale(1,2);
      break;
    case(6):
      //test 6: Rotation and Scaling with a different rotation anchor.
      atm.shift(0, -100);
      atm.rotate(angle);
      atm.rotate(0);
      atm.scale(2,2);
      atm.shift(0, 100);
      break;
    default:
      break;
    };

  session->getShippingHandler()->animateToon(hash2, atm, animatedS);
}

//Attack Preview phase!
void Renderer::stateStartAttackPreview(int part)
{
  string fontToUse;
  Param textContainerStartupInfo;
  if (part==0)
    {
      session->setInt("Battle Clickzone X", 320);
      session->setInt("Battle Clickzone Y", 70+125);

      session->getPowerSelector()->setIndividualBoxDimensions(32,32);
      session->getPowerSelector()->setPositionX(560);
      session->getPowerSelector()->setPositionY(390);

      resources.getResourceName ("Font 16",fontToUse);

      session->getTextContainer()->setPositionX(320);
      session->getTextContainer()->setPositionY(400);
      session->getTextContainer()->setTextContainerWidth(320);
      session->getTextContainer()->setTextContainerHeight(120);
      session->getTextContainer()->addFontColor(255,255,255);
      session->getTextContainer()->addFontColor(255,0,0);
      session->getTextContainer()->setNumberOfLinesPerPage(4);
      session->getTextContainer()->setFontName(fontToUse);
      session->getTextContainer()->setMarginLeft(10);

      textContainerStartupInfo.clear();
      stateStartAttackPreview(1);
    }

  map<string, AttackPath>::iterator attackPath;
  if (part==1)
    {
      if (session->getRules()->getAttackPath(attackPath))
        attackPath->second.drawPreview(session->getRules()->getAttackPatternPoints(), session->getRules()->getAttackPatternSegments(), session->getRules()->getAttackPatternPointer());

      //updates the text container when a new power is selected.
      vector <FormattedText> attackPreviewText;
      Param options;
      session->getRules()->updatePowerPreviewText(attackPreviewText);
      vector<FormattedText>::iterator iter=attackPreviewText.begin();
      session->getTextContainer()->destroyAllText();
      while (iter!=attackPreviewText.end())
        {
          options.clear();
          options.setString("String", iter->getText());
          options.setString("Help Link Reference", iter->getHelpIndex());
          options.setInt("Font Color Index", iter->getColorIndex());
          options.setInt("Max Number of Lines",-1);
          options.setBool("Force Newline?",iter->getNewline());

          //add to the power preview here.
          session->getShippingHandler()->addFormattedTextToFixedDimensions (options, *session->getTextContainer());
          iter++;
        }
    }
}

void Renderer::drawStateAttackPreview()
{
  string battleClickzone;
  Param hash;
  AffineTransformationMatrix atm;
  int battleClickZoneX=0, battleClickZoneY=0;

  session->getInt("Battle Clickzone X", battleClickZoneX);
  session->getInt("Battle Clickzone Y", battleClickZoneY);

  resources.getResourceName ("Battle Clickzone",battleClickzone);

  hash.setString("Resource Name", battleClickzone);
  hash.setInt("X", battleClickZoneX);
  hash.setInt("Y", battleClickZoneY);
  hash.setBool("Relative to Camera", false);
  session->getShippingHandler()->drawFrame (hash, atm);

  //draw the player's stats.
  drawPlayerStats("Battle Basic");

  //draw the text box
  hash.clear();
  hash.setInt("X1", 320-(320/2));
  hash.setInt("Y1", 400-(120/2));
  hash.setInt("X2", 320+(320/2));
  hash.setInt("Y2", 400+(120/2));
  hash.setInt("Red", 255); hash.setInt("Green", 255);
  hash.setInt("Blue", 255); hash.setInt("Alpha", 64);
  hash.setBool("Filled", true);
  session->getShippingHandler()->drawPrimitiveRectangleDirect (hash);

  drawTextContainer(*session->getTextContainer());

  int x=0, y=0, radius=10, colR=255, colG=255, colB=255, alph=255;
  bool antiAlias=false, filled=true;
  vector<HitBox*>::iterator attackPatternIter;

  vector <FixedInt> blah;
  vector<string> buttonIconNames;
  //populate the powerselector vectors with the names of the pictures.
  session->getRules()->getButtonIcons(buttonIconNames);
  drawPowerSelector(blah, buttonIconNames);

  map<string, AttackPath>::iterator attackPath;
  bool validPath = session->getRules()->getAttackPath(attackPath);
  if (validPath)
    {
      attackPatternIter=session->getRules()->getAttackPatternPoints().begin();

      //first layer print all the lines connecting the points.
      colR=32, colG=32, colB=32, alph=128;
      hash.clear();
      hash.setInt("Red", colR);
      hash.setInt("Green", colG);
      hash.setInt("Blue", colB);
      hash.setInt("Alpha", alph);
      hash.setBool("Anti Aliased", false);
      //skip the first pair of lines
      for (int i=2;i<int(session->getRules()->getAttackPatternSegments().size()/2);i++)
        {
          hash.setInt("X1", session->getRules()->getAttackPatternSegments()[2*i]);
          hash.setInt("Y1", session->getRules()->getAttackPatternSegments()[2*i+1]);
          hash.setInt("X2", session->getRules()->getAttackPatternSegments()[2*i-2]);
          hash.setInt("Y2", session->getRules()->getAttackPatternSegments()[2*i-1]);
          session->getShippingHandler()->drawPrimitiveLineDirect(hash);
        }

      //go through and directly print the endpoints.
      attackPatternIter=session->getRules()->getAttackPatternPoints().begin();
      if (attackPatternIter != session->getRules()->getAttackPatternPoints().end())
        attackPatternIter++;
      colR=32;colG=32;colB=32;alph=128;
      map<string, AttackPath>::iterator attackPath;
      if (session->getRules()->getAttackPath(attackPath))
        {
          while (attackPatternIter != session->getRules()->getAttackPatternPoints().end())
            {
              x=(*attackPatternIter)->getPosX();
              y=(*attackPatternIter)->getPosY();
              radius=attackPath->second.getCurrentRadius();

              hash.clearParamState();
              hash.setInt("X", x);
              hash.setInt("Y", y);
              hash.setInt("Radius", radius);
              hash.setInt("Red", colR);
              hash.setInt("Green", colG);
              hash.setInt("Blue", colB);
              hash.setInt("Alpha", alph);
              hash.setBool("Filled", filled);
              hash.setBool("Anti Aliased", antiAlias);
              session->getShippingHandler()->drawPrimitiveCircleDirect(hash);
              attackPatternIter++;
            }

          //print the initial point
          colR=255, colG=255, colB=255, alph=255;
          attackPatternIter=session->getRules()->getAttackPatternPoints().begin();
          if (attackPatternIter != session->getRules()->getAttackPatternPoints().end())
            {
              x=(*attackPatternIter)->getPosX();
              y=(*attackPatternIter)->getPosY();
              radius=attackPath->second.getCurrentRadius();

              hash.clearParamState();
              hash.setInt("X", x);
              hash.setInt("Y", y);
              hash.setInt("Radius", radius);
              hash.setInt("Red", colR);
              hash.setInt("Green", colG);
              hash.setInt("Blue", colB);
              hash.setInt("Alpha", alph);
              hash.setBool("Filled", filled);
              hash.setBool("Anti Aliased", antiAlias);
              session->getShippingHandler()->drawPrimitiveCircleDirect(hash);
            }

          //finally print the direction triangle connecting the first point to the second.
          colR=255, colG=255, colB=255, alph=255;
          antiAlias=false;
          if (session->getRules()->getAttackPatternPointer().size() > 5)
            {
              hash.clearParamState();
              hash.setInt("Red", colR);
              hash.setInt("Green", colG);
              hash.setInt("Blue", colB);
              hash.setInt("Alpha", alph);
              hash.setBool("Anti Aliased", antiAlias);
              session->getShippingHandler()->drawPrimitiveFilledPolygonDirect(hash,session->getRules()->getAttackPatternPointer());
            }
        }
    }
}

//Attack Drawing phase
void Renderer::stateStartAttackDrawing()
{
}

void Renderer::drawStateAttackDrawing()
{
  string battleClickzone;
  Param hash;
  AffineTransformationMatrix atm;
  int battleClickZoneX=0, battleClickZoneY=0, startTime;

  session->getInt("Attack Drawing Start Time", startTime);

  session->getInt("Battle Clickzone X", battleClickZoneX);
  session->getInt("Battle Clickzone Y", battleClickZoneY);

  resources.getResourceName ("Battle Clickzone",battleClickzone);

  hash.setString("Resource Name", battleClickzone);
  hash.setInt("X", battleClickZoneX);
  hash.setInt("Y", battleClickZoneY);
  hash.setBool("Relative to Camera", false);
  session->getShippingHandler()->drawFrame (hash, atm);

  int segmentPartToDraw=0;
  session->getParamOld()->getInt("Segment Part to Draw", segmentPartToDraw);

  map<string, AttackPath>::iterator attackPath;
  if (session->getRules()->getAttackPath(attackPath))
    {
      //load that part of the line segment and the part after it.
      attackPath->second.drawTwoPoints(segmentPartToDraw, session->getRules()->getAttackPatternPoints(), session->getRules()->getAttackPatternSegments(), startTime);

      //now draw.

      int x=0, y=0, radius=10, colR=255, colG=255, colB=255, alph=255;
      bool antiAlias=false, filled=true;

      //Draw the first two points.
      for (int i=0; i < int(session->getRules()->getAttackPatternPoints().size()) && i < 2; i++)
        {
          x=session->getRules()->getAttackPatternPoints()[i]->getPosX();
          y=session->getRules()->getAttackPatternPoints()[i]->getPosY();
          radius=attackPath->second.getCurrentRadius(SDL_GetTicks()-startTime);

          hash.clearParamState();
          hash.setInt("X", x); hash.setInt("Y", y);
          hash.setInt("Radius", radius); hash.setInt("Red", colR);
          hash.setInt("Green", colG); hash.setInt("Blue", colB);
          hash.setInt("Alpha", alph); hash.setBool("Filled", filled);
          hash.setBool("Anti Aliased", antiAlias);
          session->getShippingHandler()->drawPrimitiveCircleDirect(hash);
        }

      //there must be at least 2 points.
      if (session->getRules()->getAttackPatternPoints().size()<2)
        return;

      //draw the segment containing them.

      //finally print the direction triangle connecting the first point to the second.
      colR=255, colG=255, colB=255, alph=255;
      antiAlias=false;
      hash.clearParamState();
      hash.setInt("Red", colR); hash.setInt("Green", colG);
      hash.setInt("Blue", colB); hash.setInt("Alpha", alph);
      hash.setBool("Anti Aliased", antiAlias);
      session->getShippingHandler()->drawPrimitiveFilledPolygonDirect(hash,session->getRules()->getAttackPatternSegments());
    }
}

//Attack Wait for user state: Only draw a single point
void Renderer::stateStartAttackWaitForUser()
{
  int battleClickZoneX=0, battleClickZoneY=0;

  session->getInt("Battle Clickzone X", battleClickZoneX);
  session->getInt("Battle Clickzone Y", battleClickZoneY);

  session->setInt("Battle Clickzone X", battleClickZoneX);
  session->setInt("Battle Clickzone Y", battleClickZoneY);
}

void Renderer::drawStateAttackWaitForUser()
{
  string battleClickzone;
  Param hash;
  AffineTransformationMatrix atm;
  int battleClickZoneX=0, battleClickZoneY=0;

  session->getInt("Battle Clickzone X", battleClickZoneX);
  session->getInt("Battle Clickzone Y", battleClickZoneY);

  resources.getResourceName ("Battle Clickzone",battleClickzone);

  hash.setString("Resource Name", battleClickzone);
  hash.setInt("X", battleClickZoneX);
  hash.setInt("Y", battleClickZoneY);
  hash.setBool("Relative to Camera", false);
  session->getShippingHandler()->drawFrame (hash, atm);

  int segmentPartToDraw=0;
  session->getParamOld()->getInt("Segment Part to Draw", segmentPartToDraw);

  //load that part of the line segment and the part after it.
  map<string, AttackPath>::iterator attackPath;
  if (session->getRules()->getAttackPath(attackPath))
    {
      attackPath->second.drawOnlyFirstPoint(segmentPartToDraw, session->getRules()->getAttackPatternPoints());

      //don't try to draw if there are no points to draw.
      if (session->getRules()->getAttackPatternPoints().size()==0)
        return;

      int x=0, y=0, radius=10, colR=255, colG=255, colB=255, alph=255;
      bool antiAlias=false, filled=true;

      //Draw the first point.
      x=session->getRules()->getAttackPatternPoints()[0]->getPosX();
      y=session->getRules()->getAttackPatternPoints()[0]->getPosY();
      radius=attackPath->second.getCurrentRadius();

      hash.clearParamState();
      hash.setInt("X", x); hash.setInt("Y", y);
      hash.setInt("Radius", radius); hash.setInt("Red", colR);
      hash.setInt("Green", colG); hash.setInt("Blue", colB);
      hash.setInt("Alpha", alph); hash.setBool("Filled", filled);
      hash.setBool("Anti Aliased", antiAlias);
      session->getShippingHandler()->drawPrimitiveCircleDirect(hash);
    }
}

//Defend Clicking: Paths are drawn, user clicks on them to halt them.
void Renderer::stateStartDefendClicking ()
{
  session->setInt("Battle Clickzone X", 320);
  session->setInt("Battle Clickzone Y", 70+125);
}

void Renderer::drawStateDefendClicking ()
{
  //get the locations and sizes of the defense points.
  vector <int> xLoc, yLoc, rads, indx;
  int defenseTime;
  session->getInt("Defense Drawing Start Time", defenseTime);
  session->getRules()->getDefenseArray().getDefensePointLocations(xLoc, yLoc, rads, indx);
  int index;
  Param hash;
  AffineTransformationMatrix atm;
  int battleClickZoneX=0, battleClickZoneY=0;
  int battleClickZoneWidth=320, battleClickZoneHeight=250;

  battleClickZoneWidth=session->getRules()->getDefenseArray().getWindowWidth();
  battleClickZoneHeight=session->getRules()->getDefenseArray().getWindowHeight();
  session->getInt("Battle Clickzone X", battleClickZoneX);
  session->getInt("Battle Clickzone Y", battleClickZoneY);

  //get the left side
  int battleClickZoneLeftSide=battleClickZoneX-(battleClickZoneWidth/2);

  //draw the clickzone

  hash.setInt("X1", battleClickZoneX-(battleClickZoneWidth/2));
  hash.setInt("Y1", battleClickZoneY-(battleClickZoneHeight/2));
  hash.setInt("X2", battleClickZoneX-(battleClickZoneWidth/2)+
              session->getRules()->getDefenseArray().getParryWindowWidth());
  hash.setInt("Y2", battleClickZoneY+(battleClickZoneHeight/2));
  hash.setInt("Red", 255); hash.setInt("Green", 255);
  hash.setInt("Blue", 255); hash.setInt("Alpha", 128);
  hash.setBool("Filled", true);
  session->getShippingHandler()->drawPrimitiveRectangleDirect (hash);

  for (index=0; index<int(xLoc.size()) && index<int(yLoc.size()) && index<int(rads.size()); index++)
    {
      hash.clear();
      if (session->getRules()->getDefenseArray().getMovingLeft())
        hash.setInt("X", battleClickZoneX+(battleClickZoneWidth/2)-xLoc[index]);
      else
        hash.setInt("X", xLoc[index]+battleClickZoneLeftSide);
      hash.setInt("Y", yLoc[index]+battleClickZoneY-(battleClickZoneHeight/2));
      hash.setInt("Radius", rads[index]);
      hash.setInt("Red", 255);
      hash.setInt("Green", 255);
      hash.setInt("Blue", 255);
      hash.setInt("Alpha", 255);
      hash.setBool("Filled", true);
      hash.setBool("Anti Aliased", false);
      session->getShippingHandler()->drawPrimitiveCircleDirect(hash);
    }
}
