#include "../include/config.h"
#include "../include/GameStateDuel.h"
#include "../include/GameOptions.h"
#include "../include/utils.h"
#include "../include/AIPlayer.h"
#include "../include/AIMomirPlayer.h"
#include "../include/PlayerData.h"
#include "../include/DeckStats.h"
#include "../include/MTGRules.h"
#include "../include/Credits.h"
#include "../include/Translate.h"

#ifdef TESTSUITE
#include "../include/TestSuiteAI.h"
#endif

enum ENUM_DUEL_STATE
  {
    DUEL_STATE_START,
    DUEL_STATE_END,
    DUEL_STATE_CHOOSE_DECK1,
    DUEL_STATE_CHOOSE_DECK1_TO_2,
    DUEL_STATE_CHOOSE_DECK2,
    DUEL_STATE_CHOOSE_DECK2_TO_PLAY,
    DUEL_STATE_ERROR_NO_DECK,
    DUEL_STATE_CANCEL,
    DUEL_STATE_PLAY,
    DUEL_STATE_BACK_TO_MAIN_MENU,
    DUEL_STATE_MENU,
    DUEL_STATE_ERROR
  };

enum ENUM_DUEL_MENUS
  {
    DUEL_MENU_GAME_MENU,
    DUEL_MENU_CHOOSE_DECK,
    DUEL_MENU_CHOOSE_OPPONENT
  };


GameStateDuel::GameStateDuel(GameApp* parent): GameState(parent) {
  for (int i = 0; i<2; i ++){
    deck[i]=NULL;
    mPlayers[i]=NULL;
  }
  premadeDeck = false;
  game = NULL;
  deckmenu = NULL;
  opponentMenu = NULL;
  opponentMenuFont = NULL;
  menu = NULL;
#ifdef TESTSUITE
  testSuite = NULL;
#endif

  credits = NULL;
}

GameStateDuel::~GameStateDuel() {
  End();
}

void GameStateDuel::Start()
{
  JRenderer * renderer = JRenderer::GetInstance();
  renderer->EnableVSync(true);


#ifdef TESTSUITE
  SAFE_DELETE(testSuite);
  testSuite = NEW TestSuite(RESPATH"/test/_tests.txt",mParent->collection);
#endif

  mGamePhase = DUEL_STATE_CHOOSE_DECK1;
  credits = NEW Credits();
  mFont = resources.GetJLBFont(Constants::MENU_FONT);
  mFont->SetBase(0);
  opponentMenuFont = mFont;

  menu = NEW SimpleMenu(DUEL_MENU_GAME_MENU, this, mFont, SCREEN_WIDTH/2-100, 25);
  menu->Add(12,"Back to main menu");
  menu->Add(13, "Cancel");

  int decksneeded = 0;


  for (int i = 0; i<2; i ++){
    if (mParent->players[i] ==  PLAYER_TYPE_HUMAN){
      decksneeded = 1;
      deckmenu = NEW SimpleMenu(DUEL_MENU_CHOOSE_DECK, this, mFont, 35, 25, "Choose a Deck");
      int nbDecks = fillDeckMenu(deckmenu,options.profileFile());
      if (nbDecks) decksneeded = 0;
      break;
    }
  }

  if (decksneeded){
    deckmenu->Add(-1,"Create your Deck!","Highly recommended to get\nthe full Wagic experience!");
    premadeDeck = true;
    fillDeckMenu(deckmenu,RESPATH"/player/premade");
  }
    //mGamePhase = DUEL_STATE_ERROR_NO_DECK;
}

void GameStateDuel::loadPlayerRandom(int playerId, int isAI, int mode){
  int color1 = 1 + rand() % 5;
  int color2 = 1 + rand() % 5;
  int color0 = Constants::MTG_COLOR_ARTIFACT;
  if (mode == GAME_TYPE_RANDOM1) color2 = color1;
  int colors[]={color1,color2,color0};
  int nbcolors = 3;

  string lands[] = {"forest", "forest", "island", "mountain", "swamp", "plains", "forest"};


  MTGDeck * tempDeck = NEW MTGDeck(mParent->collection);
  tempDeck->addRandomCards(9,0,0,-1,lands[color1].c_str());
  tempDeck->addRandomCards(9,0,0,-1,lands[color2].c_str());
  tempDeck->addRandomCards(1,0,0,'U',"land",colors,nbcolors);
  tempDeck->addRandomCards(1,0,0,'R',"land",colors,nbcolors);
  tempDeck->addRandomCards(12,0,0,-1,"creature",colors,nbcolors);
  tempDeck->addRandomCards(2,0,0,-1,"sorcery",colors,nbcolors);
  tempDeck->addRandomCards(2,0,0,-1,"enchantment",colors,nbcolors);
  tempDeck->addRandomCards(2,0,0,-1,"instant",colors,nbcolors);
  tempDeck->addRandomCards(2,0,0,-1,"artifact",colors,nbcolors);

  string deckFile = "random";
  string deckFileSmall = "random";

  deck[playerId] = NEW MTGPlayerCards(mParent->collection, tempDeck);
  if (!isAI) // Human Player
    mPlayers[playerId] = NEW HumanPlayer(deck[playerId], deckFile, deckFileSmall);
  else
    mPlayers[playerId] = NEW AIPlayerBaka(deck[playerId],deckFile, deckFileSmall, "");
  delete tempDeck;
}


void GameStateDuel::loadPlayerMomir(int playerId, int isAI){
  string deckFileSmall = "momir";
  char empty[] = "";
  MTGDeck * tempDeck = NEW MTGDeck(options.profileFile("momir.txt","",true).c_str(), mParent->collection);
  deck[playerId] = NEW MTGPlayerCards(mParent->collection, tempDeck);
  if (!isAI) // Human Player
    mPlayers[playerId] = NEW HumanPlayer(deck[playerId], options.profileFile("momir.txt","",true).c_str(), deckFileSmall);
  else
    mPlayers[playerId] = NEW AIMomirPlayer(deck[playerId], options.profileFile("momir.txt","",true).c_str(), deckFileSmall, empty);
  delete tempDeck;
}

void GameStateDuel::loadPlayer(int playerId, int decknb, int isAI){
  if (decknb){
    if (!isAI){ //Human Player
      char deckFile[255];
      if(premadeDeck)
        sprintf(deckFile, RESPATH"/player/premade/deck%i.txt",decknb);
      else
        sprintf(deckFile, "%s/deck%i.txt",options.profileFile().c_str(), decknb);
      char deckFileSmall[255];
      sprintf(deckFileSmall, "player_deck%i",decknb);
      MTGDeck * tempDeck = NEW MTGDeck(deckFile, mParent->collection);
      deck[playerId] = NEW MTGPlayerCards(mParent->collection,tempDeck);
      delete tempDeck;
      mPlayers[playerId] = NEW HumanPlayer(deck[playerId],deckFile, deckFileSmall);
    }else{ //AI Player, chose deck
          AIPlayerFactory playerCreator;
          Player * opponent = NULL;
          if (playerId == 1) opponent = mPlayers[0];
          mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection,opponent,decknb);
          deck[playerId] = mPlayers[playerId]->game;
    }
  }else{ //Random AI deck
    AIPlayerFactory playerCreator;
    Player * opponent = NULL;
    if (playerId == 1) opponent = mPlayers[0];
    mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection,opponent);
    deck[playerId] = mPlayers[playerId]->game;
  }
}

#ifdef TESTSUITE
void GameStateDuel::loadTestSuitePlayers(){
  if (!testSuite) return;
  for (int i = 0; i < 2; i++){
    SAFE_DELETE(mPlayers[i]);
    SAFE_DELETE(deck[i]);
    mPlayers[i] = NEW TestSuiteAI(testSuite, i);
    deck[i] = mPlayers[i]->game;
  }
  mParent->gameType = testSuite->gameType;
  SAFE_DELETE(game);
  GameObserver::Init(mPlayers, 2);
  game = GameObserver::GetInstance();
  game->startGame(0,0);
  if (mParent->gameType == GAME_TYPE_MOMIR){
    game->addObserver(NEW MTGMomirRule(-1, mParent->collection));
    for (int i = 0; i < 2; i++){
      game->players[i]->life+=4;
    }
  }
}
#endif

void GameStateDuel::End()
{
#if defined (WIN32) || defined (LINUX)
  OutputDebugString("Ending GamestateDuel\n");
#endif
  SAFE_DELETE(deckmenu);
  JRenderer::GetInstance()->EnableVSync(false);
  if (mPlayers[0] && mPlayers[1]) mPlayers[0]->End();
  GameObserver::EndInstance();
  game = NULL;
  premadeDeck = false;

  for (int i = 0; i < 2; i++){
    SAFE_DELETE(mPlayers[i]);
    SAFE_DELETE(deck[i]);
  }

  SAFE_DELETE(credits);

  SAFE_DELETE(menu);
  SAFE_DELETE(opponentMenu);
#ifdef TESTSUITE
  SAFE_DELETE(testSuite);
#endif
}




void GameStateDuel::Update(float dt)
{
  switch (mGamePhase)
    {
    case DUEL_STATE_ERROR_NO_DECK:
      if (PSP_CTRL_CIRCLE == mEngine->ReadButton())
	mParent->SetNextState(GAME_STATE_DECK_VIEWER);
      break;
    case DUEL_STATE_CHOOSE_DECK1:
      if (mParent->gameType == GAME_TYPE_MOMIR){
        for (int i = 0; i < 2; i++){
          int isAI = 1;
          if (mParent->players[i] ==  PLAYER_TYPE_HUMAN) isAI = 0;
          loadPlayerMomir(i, isAI);
        }
        mGamePhase = DUEL_STATE_PLAY;
      } else if (mParent->gameType == GAME_TYPE_RANDOM1 || mParent->gameType == GAME_TYPE_RANDOM2){
        for (int i = 0; i < 2; i++){
          int isAI = 1;
          if (mParent->players[i] ==  PLAYER_TYPE_HUMAN) isAI = 0;
          loadPlayerRandom(i, isAI, mParent->gameType);
        }
        mGamePhase = DUEL_STATE_PLAY;
      }else if (mParent->players[0] ==  PLAYER_TYPE_HUMAN)
	      deckmenu->Update(dt);
#ifdef TESTSUITE
      else if (mParent->players[1] ==  PLAYER_TYPE_TESTSUITE){
	      if (testSuite && testSuite->loadNext()){

	        loadTestSuitePlayers();

	        mGamePhase = DUEL_STATE_PLAY;
	        testSuite->initGame();
	        char buf[4096];
	        sprintf(buf, "nb cards in player2's graveyard : %i\n",mPlayers[1]->game->graveyard->nb_cards);
	        LOG(buf);
	      }else{
          if (!game){
            mGamePhase = DUEL_STATE_ERROR;
          }else{
	          mGamePhase = DUEL_STATE_END;
          }
	      }
      }
#endif
      else{
	      loadPlayer(0);
	      mGamePhase = DUEL_STATE_CHOOSE_DECK2;
      }
      break;
    case DUEL_STATE_CHOOSE_DECK1_TO_2:
      if (deckmenu->closed) mGamePhase = DUEL_STATE_CHOOSE_DECK2;
      else deckmenu->Update(dt);
      break;
    case DUEL_STATE_CHOOSE_DECK2:
      if (mParent->players[1] ==  PLAYER_TYPE_HUMAN)
	deckmenu->Update(dt);
      else{
	if (mParent->players[0] ==  PLAYER_TYPE_HUMAN){
	  if (!opponentMenu){
	    opponentMenu = NEW SimpleMenu(DUEL_MENU_CHOOSE_OPPONENT, this, opponentMenuFont, 35, 25, "Choose Opponent");
	    opponentMenu->Add(0,"Random");
	    if (options[Options::EVILTWIN_MODE_UNLOCKED].number)
	      opponentMenu->Add(-1,"Evil Twin", "Can you play against yourself?");
	    fillDeckMenu(opponentMenu,RESPATH"/ai/baka", "ai_baka", mPlayers[0]);
	  }
	  opponentMenu->Update(dt);
	}else{
	  loadPlayer(1);
	  mGamePhase = DUEL_STATE_PLAY;
	}
      }
      break;
    case DUEL_STATE_CHOOSE_DECK2_TO_PLAY:
      if (mParent->players[1] ==  PLAYER_TYPE_HUMAN){
	if (deckmenu->closed) mGamePhase = DUEL_STATE_PLAY;
	else deckmenu->Update(dt);
      }
      else
	{
	  if (opponentMenu->closed) mGamePhase = DUEL_STATE_PLAY;
	  else opponentMenu->Update(dt);
	}
      break;
    case DUEL_STATE_PLAY:
    //Stop the music before starting the game
      if (GameApp::music){
	      JSoundSystem::GetInstance()->StopMusic(GameApp::music);
	      SAFE_DELETE(GameApp::music);
      }
      if (!game){
	      GameObserver::Init(mPlayers, 2);
	      game = GameObserver::GetInstance();
	      game->startGame();
        if (mParent->gameType == GAME_TYPE_MOMIR){
          game->addObserver(NEW MTGMomirRule(-1, mParent->collection));
          for (int i = 0; i < 2; i++){
            game->players[i]->life+=4;
          }
        }
      }
      //      mParent->effect->UpdateSmall(dt);
      game->Update(dt);
      if (game->gameOver){
        credits->compute(mPlayers[0],mPlayers[1], mParent);
	      mGamePhase = DUEL_STATE_END;
#ifdef TESTSUITE
	if (mParent->players[1] == PLAYER_TYPE_TESTSUITE){
	  if (testSuite->loadNext()){
	    loadTestSuitePlayers();
	    mGamePhase = DUEL_STATE_PLAY;
	    testSuite->initGame();
	  }else{
	    mGamePhase = DUEL_STATE_END;
	  }
	}else
#endif
	  if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU){
	    End();
	    Start();
	  }
	mFont->SetColor(ARGB(255,255,255,255));
      }
      if (mEngine->GetButtonClick(PSP_CTRL_START)){
	mGamePhase = DUEL_STATE_MENU;
      }
      break;
    case DUEL_STATE_MENU:
      //      mParent->effect->UpdateSmall(dt);
      menu->Update(dt);
      break;
    case DUEL_STATE_CANCEL:
      //      mParent->effect->UpdateSmall(dt);
      menu->Update(dt);
      if (menu->closed)
	mGamePhase = DUEL_STATE_PLAY;
      break;
    case DUEL_STATE_BACK_TO_MAIN_MENU:
      //       mParent->effect->UpdateSmall(dt);
     menu->Update(dt);
      if (menu->closed)
	mParent->SetNextState(GAME_STATE_MENU);
      break;
    default:
      if (PSP_CTRL_CIRCLE == mEngine->ReadButton()){
	mParent->SetNextState(GAME_STATE_MENU);
      }
    }
}


void GameStateDuel::Render()
{
  //Erase
  LOG("Start Render\n");
  JRenderer::GetInstance()->ClearScreen(ARGB(0,0,0,0));

  if (game)
    game->Render();
  switch (mGamePhase)
    {
    case DUEL_STATE_END:
      {
        JRenderer * r = JRenderer::GetInstance();
	      r->ClearScreen(ARGB(200,0,0,0));
	      credits->Render();
#ifdef TESTSUITE
	      if (mParent->players[1] == PLAYER_TYPE_TESTSUITE){
          r->ClearScreen(ARGB(255,0,0,0));
          char buf[4096];
          int nbFailed = testSuite->nbFailed;
          int nbTests = testSuite->nbTests;
          if (!nbFailed){
            sprintf(buf, "All %i tests successful!", nbTests);
          }else{
            sprintf(buf, "%i tests out of %i FAILED!", nbFailed, nbTests);
          }
          
          mFont->DrawString(buf,0,SCREEN_HEIGHT/2);
        }
#endif
	      break;
      }
    case DUEL_STATE_ERROR:
      {
        JRenderer * r = JRenderer::GetInstance();
	      r->ClearScreen(ARGB(200,0,0,0));
	      mFont->DrawString(_("AN ERROR OCCURED, CHECK FILE NAMES").c_str(),0,SCREEN_HEIGHT/2);
	      break;
      }
    case DUEL_STATE_CHOOSE_DECK1:
    case DUEL_STATE_CHOOSE_DECK1_TO_2:
    case DUEL_STATE_CHOOSE_DECK2:
    case DUEL_STATE_CHOOSE_DECK2_TO_PLAY:
      if (mParent->gameType != GAME_TYPE_CLASSIC){
        mFont->DrawString(_("LOADING DECKS").c_str(),0,SCREEN_HEIGHT/2);
      }else{
        if (opponentMenu){
	        opponentMenu->Render();
        }else if (deckmenu){
	        deckmenu->Render();
        }
      }
      break;
    case DUEL_STATE_ERROR_NO_DECK:
      mFont->DrawString(_("NO DECK AVAILABLE,").c_str(),0,SCREEN_HEIGHT/2);
      mFont->DrawString(_("PRESS CIRCLE TO GO TO THE DECK EDITOR!").c_str(),0,SCREEN_HEIGHT/2 + 20);
      break;
    case DUEL_STATE_MENU:
    case DUEL_STATE_CANCEL:
    case DUEL_STATE_BACK_TO_MAIN_MENU:
      menu->Render();
  }
  LOG("End Render\n");
}

void GameStateDuel::ButtonPressed(int controllerId, int controlId)
{
  switch (controllerId){
    case DUEL_MENU_CHOOSE_OPPONENT:
      {
        switch(controlId){
          case 0:
            loadPlayer(1);
	          opponentMenu->Close();
	          mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY;
            break;
          default:
            loadPlayer(1,controlId,1);
	          opponentMenu->Close();
	          mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY;
            break;

        }
        break;
      }
    case DUEL_MENU_CHOOSE_DECK:
      {
        if (controlId < 0){
          mParent->SetNextState(GAME_STATE_DECK_VIEWER);
          return;
        }
        if (mGamePhase == DUEL_STATE_CHOOSE_DECK1){
          loadPlayer(0,controlId);
          deckmenu->Close();
          mGamePhase = DUEL_STATE_CHOOSE_DECK1_TO_2;
        }else{
          loadPlayer(1,controlId);
          deckmenu->Close();
          mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY;
        }
        break;
      }
    default:
      {
      switch (controlId)
        {

          case 12:
	    menu->Close();
	    mGamePhase = DUEL_STATE_BACK_TO_MAIN_MENU;
            break;
          case 13:
	    menu->Close();
            mGamePhase = DUEL_STATE_CANCEL;
            break;
        }
      }
  }
}
