#include "GameState.h"

GameState :: GameState ()
{
  stringVect.resize (0);
  listBoxVect.clear ();
  helpBoxVect.clear ();
  buttonVect.clear ();
  textFeeders.clear ();
}

GameState :: ~GameState ()
{
  gamestateQuit();

  inputBuffer.clear ();

  vector <Command *> :: iterator iter2;
  iter2 = commandBuffer -> begin ();
  while(iter2 < commandBuffer -> end ()) {
    delete (*iter2);
    iter2 ++;
  }
  commandBuffer -> clear ();

  vector <string *> :: iterator iter4;
  iter4 = stringVect.begin ();
  while(iter4 < stringVect.end ()) {
    delete (*iter4);
    iter4 ++;
  }
  stringVect.clear ();
  listBoxVect.clear ();
  helpBoxVect.clear();
  textFeeders.clear();

  delete player1Input;
  delete commandBuffer;
  delete sdlRE;
}

bool GameState :: initialize ()
{
  initializeAngles();
  seedRandomization();

  currentGamestate = GAMESTATE_INITIAL;
  previousGamestate = GAMESTATE_INITIAL;

  SDL_ClearError ();
  sdlRE = new shippingHandler ();
  if (sdlRE -> Startup () == false)
    {
      writeToErrorLog ("SDL Startup Failed: ", 0);
      writeToErrorLog (SDL_GetError (), 1);
      return false;
    }
  rander.initialize ();
  rander.setResourceEngine (sdlRE);

  inputBuffer.clear();
  commandBuffer = new vector <Command *> (0);
  player1Input = new LocalInput ();

  startTime = 0;
  firstTimeInNewState = true;

  helpReference = "NULL_INDEX";

  buttonVect.resize(6);

  stringVect.push_back (new string);
  stringVect.push_back (new string);
  stringVect.push_back (new string);
  stringVect.push_back (new string);
  stringVect.push_back (new string);
  stringVect.push_back (new string);

  listBoxVect.resize(3);

  numButtons = 0;
  numListBoxes = 0;

  playerPowerSelector.clear();

  tempStr.push_back("Hola");
  tempStr.push_back("TEST!");
  tempStr.push_back("TEST!1");
  tempStr.push_back("TEST!2");
  tempStr.push_back("TEST!3");
  tempStr.push_back("TEST!4");
  tempStr.push_back("TEST!5");
  tempStr.push_back("TEST!6");
  tempStr.push_back("TEST!7");

  //vector <bool> tempBool;
  tempBool.resize(tempStr.size(), false);
  //tempBool[0]=true;
  //tempBool[8]=true;
  //lBV[0].setScrollPosition(0);

  tempHelpStr.resize(tempStr.size(), "NULL_INDEX");

  textFeeders.resize(1);
  return true;
}

void GameState :: go ()
{
  //output ();
  //gatherInput ();
  //applyInputToInterface ();
  // ^^ may call applyRuleToRuleset (); if it makes a command
  // ^^ may call applyCommandToProgram (); if it's quit/expand window etc.
  //if no preparations needed, screenDelay ();

  vector <Command *> :: iterator iter2;

  stateStartup();

  bool drawToScreen = true;
  //set up the next draw
  sdlRE -> clearScreen ();

  stateBeforeDrawing(drawToScreen);

  //draw if you have to
  helpStackBeforeDraw ();

  if (drawToScreen)
    {
      sdlRE -> flipScreen ();
      gatherInput ();
    }

  stateAfterDrawing();

  if (drawToScreen)
    screenDelay ();

  //clear input buffer
  inputBuffer.clear ();

  //clear command buffer
  iter2 = commandBuffer -> begin ();
  while(iter2 < commandBuffer -> end ()) {
    delete (*iter2);
    iter2 ++;
  }
  commandBuffer -> clear ();
}

/*
  These functions are callled based on the gamestate.

  0) check firstTimeInNewState. If true, load all resources and play stuff that should happen only on transition.
  1) draw, in layer order. Later I may allow a layer call to draw based on the layer.
  2) grab the input so you can figure out what's going on.

  If you need to change states, set firstTimeInNewState to true, then write the new state in.
 */

void GameState :: gatherInput ()
{
  //poll devices for input

  //I might have to call pump events

  SDL_Event mainEvent;

  if (getGameState () == GAMESTATE_INITIAL)
    return;

  inputBuffer.clear();

  while (SDL_PollEvent (&mainEvent)){
    switch (mainEvent.type)
      {
      case (SDL_KEYUP):
      case (SDL_KEYDOWN):
      case (SDL_MOUSEMOTION):
      case (SDL_MOUSEBUTTONUP):
      case (SDL_MOUSEBUTTONDOWN):
        player1Input -> pollInput (mainEvent, inputBuffer);
        break;
      default:
        break;
      };
  }
}

void GameState :: applyRuleToRuleset ()
{
  //if it makes a command that applies to the ruleset, apply it here

  //go through the command buffer, apply them to ruleset

  vector <Command *> :: iterator iter;

  iter = commandBuffer -> begin ();
  while(iter < commandBuffer -> end ()) {
    iter ++;
  }
}

void GameState :: applyCommandToProgram ()
{
  //if it's quit/expand window etc.

  //go through the command buffer.

  //if the command is a quit command
  vector <Command *> :: iterator iter;

  iter = commandBuffer -> begin ();
  while(iter < commandBuffer -> end ()) {
    if ((*iter) -> getCommand () == COMMAND_QUIT_GAME)
      {
        setNewGameState (GAMESTATE_QUIT);
      }
    iter ++;
  }
}

void GameState :: setNewGameState (uint8_t ngs)
{
  stateShutdown();

  firstTimeInNewState=true;
  previousGamestate=currentGamestate;
  currentGamestate=ngs;
}

uint8_t GameState :: getGameState ()
{
  return currentGamestate;
}

void GameState :: screenDelay ()
{
  //program waits for 33 milliseconds.
  if (SDL_GetTicks () < 33 + lastFrame)
    SDL_Delay(lastFrame + 33 - SDL_GetTicks ());
  lastFrame = SDL_GetTicks ();
}

void GameState :: clearButtons (uint8_t num)
{
  if (num == 0)
    num = numButtons;

  uint8_t index = 0;
  for (index = 0; index < num; index ++)
    {
      buttonVect[index].setIsHit (false);
    }
}

void GameState :: buttonUpdateClickStatus (Input & inp, uint8_t num)
{
  if (num == 0)
    num = numButtons;

  uint8_t index = 0;
  for (index = 0; index < num; index ++)
    {
      if (isMouseOnHotSpot (inp, buttonVect[index], false))
        buttonVect[index].setIsHit (true);
      else
        buttonVect[index].setIsHit (false);
    }
}

void GameState :: addQuitCommand ()
{
  Command * comm = NULL;
  //generate a "quit game" command
  comm = new Command ();
  comm -> setCommand (COMMAND_QUIT_GAME);
  commandBuffer -> push_back (comm);
  applyCommandToProgram ();
}

void GameState :: helpStackBeforeDraw ()
{
  HelpBox hb;

  //first see if you need to generate a new help box.
  if (!helpReference.empty() && helpReference != "NULL_INDEX")
    {
      //Add a new HelpBox, add it to the stack.
      //Creating a new help box
      //1) Renderer loads the graphics and font for the helpbox.
      rander.loadResourcesHelp();

      //2) Gamestate loads the text for the helpbox
      if (loadHelpText(hb, helpReference)&&sdlRE->loadHelpBoxColors(hb,helpReference))
        {
          //3) Renderer positions the text & determines the dimensions of the object (centered on the mouse)
          rander.positionHelpBoxText(hb);
          rander.positionHelpBox(helpBoxVect, hb);
          if (helpBoxVect.empty())
            newHelpReference = true;
          helpBoxVect.push_back(hb);
        }
      helpReference = "NULL_INDEX";
    }
  rander.outputHelpBoxStack (helpBoxVect);
}

void GameState :: helpStackHandleInput ()
{
  /*
  pseduocode:

  For each mouseUp Input or not Done
    If newRef is true
       clear newRef and return
    For each HelpBox, starting at the deepest (substitute in last and go backward)
        If the input hit a box
           Send input to the box
           You're Done
   If out of mouseUps and Not Done
      Remove the topmost helpbox
  */

  vector <HelpBox> :: reverse_iterator helpBoxIter;
  bool exitLoop = false, hadAMouseUp=false;
  inputBufferIterator = inputBuffer.begin ();

  while (inputBufferIterator != inputBuffer.end () && !exitLoop)
    {
      //  For each mouseUp Input or not Done
      if (inputBufferIterator -> getInput () == INPUT_MOUSEUP)
        {
          hadAMouseUp=true;
          //    For each HelpBox, starting at the deepest (substitute in last and go backward)
          helpBoxIter = helpBoxVect.rbegin ();
          while (helpBoxIter != helpBoxVect.rend () && !exitLoop)
            {
              //If the input hit a box
              if (pointRectangleCollision(inputBufferIterator->getData()[0],
                                          inputBufferIterator->getData()[1],
                                          helpBoxIter->getPositionX()-helpBoxIter->getWidth()/2,
                                          helpBoxIter->getPositionX()+helpBoxIter->getWidth()/2,
                                          helpBoxIter->getPositionY()-helpBoxIter->getHeight()/2,
                                          helpBoxIter->getPositionY()+helpBoxIter->getHeight()/2
                                          ))
                {
                  //send input to the box
                  checkInputOnHelpBox(*helpBoxIter, inputBufferIterator->getData()[0], inputBufferIterator->getData()[1], inputBufferIterator->getData()[2]);
                  exitLoop=true; //you're done
                }
              helpBoxIter ++;
            }
        }
      if (inputBufferIterator -> getInput () == INPUT_QUITGAME)
        {
          //close all helpWindows.
          helpBoxIter = helpBoxVect.rbegin ();
          while (helpBoxIter != helpBoxVect.rend () && !exitLoop)
            {
              helpBoxIter ++;
              rander.clearResourcesHelp();
            }
          helpBoxVect.clear();
        }
      inputBufferIterator++;
    }

  //If you had a mouseUp, and you are out of mouseUps, and Not Done
  if (!exitLoop && hadAMouseUp && !newHelpReference)
    {
      //Remove the topmost helpbox
      helpBoxVect.pop_back();
      rander.clearResourcesHelp();
    }

  //    If newRef is true
  if (hadAMouseUp && newHelpReference)
    {
      //       clear newRef and return
      newHelpReference = false; //so releasing the mouse doesn't clear the box you just made.
    }

}

void GameState::checkInputOnHelpBox(HelpBox & hb, int mouseX, int mouseY, int mouseButt)
{
  if (mouseButt != MOUSE_BUTTON_HELP)
    return;

  vector <FormattedText> :: iterator formattedTextIterator;
  bool done = false;

  formattedTextIterator=hb.getFormattedText().begin();

  while (formattedTextIterator!=hb.getFormattedText().end() && !done)
    {
      if (pointRectangleCollision(mouseX, mouseY,
                                  hb.getPositionX()-hb.getWidth()/2+formattedTextIterator->getX(),
                                  hb.getPositionX()-hb.getWidth()/2+formattedTextIterator->getX()+formattedTextIterator->getWidth(),
                                  hb.getPositionY()-hb.getHeight()/2+formattedTextIterator->getY(),
                                  hb.getPositionY()-hb.getHeight()/2+formattedTextIterator->getY()+formattedTextIterator->getHeight()))
        {
          helpReference=formattedTextIterator->getHelpIndex();
          done=true;
        }
      formattedTextIterator++;
    }
}

void GameState :: listBoxUpdateClickStatus (Input & inp, uint8_t numListsToUse)
{
  if (numListsToUse == 0)
    numListsToUse = numListBoxes;

  uint8_t index = 0;
  for (index = 0; index < numListsToUse; index ++)
    {
      //checkInputOnListBox (ListBox & lb, vector<string>& stringList, vector<string>& helpRefList, int mouseX, int mouseY, int mouseButt)
      //listBoxVect.at (index) -> checkElement (inp, sdlRE, helpReference);
    }
}

bool GameState::isMouseOnHotSpot(Input & comm, Button & b, bool respectCamera)
{
  int32_t mouseX, mouseY, boxX, boxY, butt;

  mouseX = comm.getData()[0];
  mouseY = comm.getData()[1];
  butt = comm.getData()[2];

  if (respectCamera)
    {
      boxX = sdlRE -> getScreenResolutionX() / 2 + b.getX () - sdlRE -> getObserverX ();
      boxY = sdlRE -> getScreenResolutionY() / 2 + b.getY () - sdlRE -> getObserverY ();
    }
  else
    {
      boxX = b.getX ();
      boxY = b.getY ();
    }

  if (pointRectangleCollision (mouseX, mouseY,
                               boxX-b.getWidth()/2, boxX+b.getWidth()/2,
                               boxY-b.getHeight()/2, boxY+b.getHeight()/2))
    {
      if (butt == MOUSE_BUTTON_ACTION)
       return true;
      if (butt == MOUSE_BUTTON_HELP)
       helpReference = "1"; //STUB
    }
  return false;
}

bool GameState :: loadHelpText(HelpBox & hb, const string & ref)
{
  //load the text based on the index.
  xmlDocPtr doc;
  xmlXPathContextPtr xpathCtx;

  string xpathStart="/HelpManifest/HelpText[@ID='";
  xpathStart+=ref;
  xpathStart+="']/FormattedText";

  if (!prepareXMLFile (doc, xpathCtx, "resources/HelpManifest.xml", xpathStart))
    {
      return false;
    }

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

  if (xpathObj==NULL)
    {
      //Couldn't find any help text.
      xmlXPathFreeContext(xpathCtx);
      xmlFreeDoc (doc);
      writeToErrorLog ("Failed to find help text reference "+ref+"in resources/HelpManifest.xml", 0);
      return false;
    }

  string idString;
  char searchString [255];

  //set the head of xpathCtx to match the node.
  for (int i=0; i<xpathObj->nodesetval->nodeNr; i++)
    {
      sprintf (searchString, "[%u]", i+1);
      idString=xpathStart+searchString;
      loadSingleFormattedText (doc, xpathCtx, idString, hb);
    }

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

  if (hb.getHelpReference().size () == 0)
    {
      //Failed to load shape. Cleanup and exit.
      writeToErrorLog ("Loading Help Text: No Formatted Text, not loading Help Text", 0);
      writeToErrorLog (ref.c_str(), 1);
      return false;
    }
  return true;
}

bool GameState :: loadSingleFormattedText (xmlDocPtr doc, xmlXPathContextPtr xpathCtx, const string & xpath, HelpBox & hb)
{
  FormattedText fmtx;

  xmlChar * element;
  int temp;

  //get text. If there is no text, then there is no Formatted Text.
  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Text", "");
  if (element == NULL)
    {
      xmlFree (element);
      return false;
    }

  string gab;
  gab.assign ((const char *)element);
  fmtx.setText (gab);
  xmlFree (element);

  //Newline. If it equals "true" then it's true. False otherwise.
  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Newline", "");
  if (element == NULL)
    {
      fmtx.setNewline (false);
    }
  else
    {
      if (xmlStrcasecmp (element, (const xmlChar *)"true") == 0)
        {
          fmtx.setNewline (true);
        }
      else
        fmtx.setNewline (false);

      xmlFree (element);
    }

  //Now, see if clicking on the text brings another help hint.
  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/HelpReferralIndex", "");
  if (element == NULL)
    {
      fmtx.setHelpIndex ("NULL_INDEX");
      fmtx.setColorIndex (0);
    }
  else
    {
      gab.assign ((const char *)element);
      fmtx.setHelpIndex (gab);
      xmlFree (element);
      fmtx.setColorIndex (1);
    }

  //finally, get the colorIndex.
  element = getFirstElementUsingXPath (doc, xpathCtx, xpath, "/Color", "");
  if (element != NULL)
    {
      temp = int(xmlXPathCastStringToNumber(element));
      if (temp < 0)
        temp = 0;
      fmtx.setColorIndex (temp);
      xmlFree (element);
    }

  hb.pushFormattedText(fmtx);
  return true;
}

uint8_t GameState::checkInputOnListBox (ListBox & lb, vector<string>& stringList, vector<string>& helpRefList, int mouseX, int mouseY, int mouseButt)
{
  //applies the mouse button to a ListBox.
  //possible actions:
  //0: Nothing.
  //1: Clicked on a valid element. Set valid element.
  //2: Clicked on a valid element with the help button. Set valid element, return help string.
  //4: Clicked Up Arrow
  //8: Clicked Down Arrow

  //Implement later
  //16: Clicked on scroll window

  //Did I click outside the ListBox?
  if (!pointRectangleCollision(mouseX, mouseY,
                               lb.getX()-lb.getWidth()/2,
                               lb.getX()+lb.getWidth()/2,
                               lb.getY()-lb.getHeight()/2,
                               lb.getY()+lb.getHeight()/2))
    return 0;

  int verticalDist = mouseY-(lb.getY()-lb.getHeight()/2+lb.getVerticalPadding());
  int textHeight = lb.getFontSize()+lb.getVerticalPadding();

  int maxTextEntriesInListBox=(lb.getHeight()-lb.getVerticalPadding())/textHeight;

  //so I clicked inside the box. Decide if you clicked on the scroll bar.
  bool needScrollBar=(maxTextEntriesInListBox <= stringList.size());

  bool clickedOnScrollBar=false;

  uint16_t widthScrollWindow, heightScrollWindow;
  sdlRE->getFrameDimensions (lb.getGraphicFrameScrollWindow(), widthScrollWindow, heightScrollWindow);

  uint16_t widthScrollUp=1, heightScrollUp=1, widthScrollDown=1, heightScrollDown=1;
  sdlRE->getFrameDimensions (lb.getGraphicFrameUpArrow(), widthScrollUp, heightScrollUp);
  sdlRE->getFrameDimensions (lb.getGraphicFrameDownArrow(), widthScrollDown, heightScrollDown);

  clickedOnScrollBar=needScrollBar && mouseX>=lb.getX()+(lb.getWidth()/2)-widthScrollWindow;

  if (needScrollBar && clickedOnScrollBar)
    {
      if (mouseY <= lb.getY()-(lb.getHeight()/2)+heightScrollUp)
        {
          lb.scrollUp(stringList.size());
          return 4;
        }
      else if (mouseY >= lb.getY()+(lb.getHeight()/2)-heightScrollDown)
        {
          lb.scrollDown(stringList.size());
          return 8;
        }
      else
        return 16; //Can do something more complicated, but I don't care right now.
    }

  if (textHeight==0) //invalid height.
    return 0;

  int elementClickedOn = lb.getScrollPosition()+(verticalDist/textHeight);

  if (mouseButt!=MOUSE_BUTTON_NONE)
    {
      lb.setElementHit(elementClickedOn);
      if (mouseButt==MOUSE_BUTTON_HELP)
        {
          helpReference=helpRefList[elementClickedOn];
          return 2; //hit the help button, set the help reference.
        }
      if (mouseButt==MOUSE_BUTTON_ACTION)
        return 1; //hit the action button.
    }
  return 0;
}

void GameState::gamestateQuit()
{
  rander.clearResourceDebug ("all");
}

//checks if it's time to change state. If it is, it tells the state it plans to enter to load variables, etc.
void GameState::stateStartup()
{
  if (!firstTimeInNewState)
    return;

  switch (getGameState ())
    {
    case (GAMESTATE_INITIAL):
      gamestateInitialStartup ();
      break;
    case (GAMESTATE_MAIN_MENU):
      gamestateMainMenuStartup();
      break;
    case (GAMESTATE_BATTLE_SWOOSH):
      gamestateBattleSwooshStartup ();
      break;
    case (GAMESTATE_BATTLE_SHOW_REWARDS):
      gamestateBattleShowRewardsStartup ();
      break;
    case (GAMESTATE_CHOOSE_YOUR_INTRO_POWERS):
      gamestateChooseYourIntroPowersStartup();
      break;
    case (GAMESTATE_QUIT):
      gamestateQuit();
      break;
    case (GAMESTATE_MAP):
      gamestateMapStartup(rulez.getEnemyMapUnits(), rulez.getPlayerMapUnit());
      break;
    default:
      break;
    };

  firstTimeInNewState=false;
  lastFrame = SDL_GetTicks ();
  startTime = SDL_GetTicks ();
}

//This extracts the state and tells it to prepare to draw stuff.
//set drawToScreen to true if the state should be drawn to screen.
void GameState::stateBeforeDrawing(bool & drawToScreen)
{
  drawToScreen=true;

  switch (getGameState ())
    {
    case (GAMESTATE_INITIAL):
      gamestateInitial ();
      drawToScreen = false;
      break;
    case (GAMESTATE_QUIT):
      drawToScreen = false;
      break;
    case (GAMESTATE_MAIN_MENU):
      rander.outputMainMenu (stringVect2, buttonVect, startTime);
      break;
    case (GAMESTATE_MAP):
      rander.outputMapScreen (stringVect2, buttonVect, rulez.getMap(), rulez.getPlayerMapUnit(), rulez.getEnemyMapUnits());
      break;
    case (GAMESTATE_BATTLE_SWOOSH):
      gamestateBattleSwooshBeforeDraw ();
      break;
    case (GAMESTATE_BATTLE_CHECK_FOR_RESULT):
      rander.outputCheckForResult ();
      break;
    case (GAMESTATE_BATTLE_PLAYER_PHASE):
      rander.outputPlayerPhase (stringVect2, buttonVect, rulez.getPlayer(), playerPowerSelector, rulez.getPlayerBattleAbilities(), textFeeders);
      break;
    case (GAMESTATE_BATTLE_ENEMY_PHASE):
      rander.outputEnemyPhase (stringVect2, buttonVect, rulez.getPlayer());
      break;
    case (GAMESTATE_BATTLE_SHOW_REWARDS):
      rander.outputRewards(stringVect2, buttonVect, rulez.getPlayer(), levelUps, startTime);
      break;
    case (GAMESTATE_BATTLE_GAME_OVER):
      rander.outputGameOver (stringVect2, buttonVect, startTime);
      break;
    case (GAMESTATE_CREDITS):
      rander.outputCredits (stringVect2, buttonVect);
      break;
    case (GAMESTATE_INVENTORY):
      rander.outputInventory(stringVect2, buttonVect, listBoxVect, rulez.getPlayer(), rulez.getStore(), rulez.getBetweenLevels (), rulez.getIntroBattle ());
      break;
    case (GAMESTATE_GAME_MENU):
      rander.outputGameMenu (stringVect2, buttonVect);
      break;
    case (GAMESTATE_NEW_GAME):
      rander.outputNewGame (stringVect2, buttonVect);
      break;
    case (GAMESTATE_CHOOSE_YOUR_CHARACTER):
      rander.outputChooseYourCharacter (stringVect2, buttonVect);
      break;
    case (GAMESTATE_CHOOSE_YOUR_INTRO_POWERS):
      rander.outputChooseYourPowers (stringVect2, buttonVect, rulez.getPlayer ());
      break;
    case (GAMESTATE_CONTINUE_GAME):
      rander.outputContinue(stringVect2, buttonVect);
      break;
    case (GAMESTATE_SAVE):
      rander.outputSave (stringVect2, buttonVect);
      break;
    case (GAMESTATE_ABILITY):
      rander.outputAbility(stringVect2, buttonVect, listBoxVect, rulez.getPlayer(), rulez.getStore(), rulez.getBetweenLevels (), rulez.getIntroBattle ());
      break;
    case (GAMESTATE_LEVEL_COMPLETE):
      rander.outputLevelComplete ();
      break;
    case (GAMESTATE_LEVEL_NEW):
      rander.outputNewLevelAnnouncement ();
      break;
    default:
      break;
    };
}

//After drawing, this looks at the results from input and other circumstances.
void GameState::stateAfterDrawing()
{
  //do stuff after you have to draw
  if (helpBoxVect.size () <= 0)
    {
      switch (getGameState ())
        {
        case (GAMESTATE_MAIN_MENU):
          gamestateMainMenuAfterDraw(4);
          break;
        case (GAMESTATE_MAP):
          gamestateMapAfterDraw(2);
          break;
        case (GAMESTATE_BATTLE_SWOOSH):
          gamestateBattleSwooshAfterDraw ();
          break;
        case (GAMESTATE_BATTLE_CHECK_FOR_RESULT):
          gamestateBattleCheckForResultAfterDraw ();
          break;
        case (GAMESTATE_BATTLE_PLAYER_PHASE):
          gamestateBattlePlayerPhaseAfterDraw (3);
          break;
        case (GAMESTATE_BATTLE_ENEMY_PHASE):
          gamestateBattleEnemyPhaseAfterDraw (3);
          break;
        case (GAMESTATE_BATTLE_SHOW_REWARDS):
          gamestateBattleShowRewardsAfterDraw (1);
          break;
        case (GAMESTATE_BATTLE_GAME_OVER):
          gamestateBattleGameOverAfterDraw (1);
          break;
        case (GAMESTATE_CREDITS):
          gamestateCreditsAfterDraw(1);
          break;
        case (GAMESTATE_INVENTORY):
          if (rulez.getBetweenLevels())
            gamestateInventoryAfterDraw(6);
          else
            gamestateInventoryAfterDraw(5);
          break;
        case (GAMESTATE_GAME_MENU):
          gamestateGameMenuAfterDraw(2);
          break;
        case (GAMESTATE_NEW_GAME):
          gamestateNewGameAfterDraw(2);
          break;
        case (GAMESTATE_CHOOSE_YOUR_CHARACTER):
          gamestateChooseYourCharacterAfterDraw(4);
          break;
        case (GAMESTATE_CHOOSE_YOUR_INTRO_POWERS):
          gamestateChooseYourIntroPowersAfterDraw(2);
          break;
        case (GAMESTATE_CONTINUE_GAME):
          gamestateContinueGameAfterDraw(3);
          break;
        case (GAMESTATE_SAVE):
          gamestateSaveAfterDraw();
          break;
        case (GAMESTATE_ABILITY):
          if (rulez.getBetweenLevels())
            gamestateAbilityAfterDraw(6,3);
          else
            gamestateAbilityAfterDraw(4,2);
          break;
        case (GAMESTATE_LEVEL_COMPLETE):
          gamestateLevelCompleteAfterDraw ();
          break;
        case (GAMESTATE_LEVEL_NEW):
          gamestateLevelNewAfterDraw ();
          break;
        default:
          break;
        };
    }
  else
    {
      helpStackHandleInput ();
    }
}

//This gives the state a chance to clean resources before it shuts down.
void GameState::stateShutdown()
{
  switch (getGameState ())
    {
    case(GAMESTATE_BATTLE_SHOW_REWARDS):
      rander.clearResourceBattle(playerPowerSelector);
      break;
    default:
      break;
    };
}

//Hit detection that gets the selected index.
//return -1 if it is not in range
int GameState::checkInputOnPowerSelector(PowerSelector & ps, int mouseX, int mouseY)
{
  string box, boxSelected, wait, waitSelected, rechargingShade;

  string resourceToUse;
  GraphicTransformation gt;

  int x=ps.getX(), y=ps.getY(), selectedIndex=-1, leftSide, topSide, numBoxesX, numBoxesY;

  uint16_t boxWidth, boxHeight;
  boxWidth=ps.getIndividualBoxWidth();
  boxHeight=ps.getIndividualBoxHeight();

  leftSide=x-(boxWidth*3/2); topSide=y-(boxHeight*3/2);

  //if the mouse isn't range, return -1.
  if (!pointRectangleCollision (mouseX, mouseY,
                                leftSide, leftSide+(boxWidth*4),
                                topSide, topSide+(boxHeight*3)))
    {
      return -1;
    }

  //get the coordinates of the mouse relative to the sides.
  numBoxesX=(mouseX-leftSide)/boxWidth;
  numBoxesY=(mouseY-topSide)/boxHeight;

  //ok, final range check.
  if (numBoxesX < 0 || numBoxesX > 3 || numBoxesY < 0 || numBoxesY > 2)
    return -1;

  //0 = upper left box, 2 = upper right box, 6 = lower left box, 8 = lower right box
  selectedIndex=numBoxesY*3+numBoxesX;

  //Exception: The right most box is button 9, and takes up all 3 rows.
  if (numBoxesX > 2)
    selectedIndex=9;
  return selectedIndex;
}
