// Copyright (C) 2011 Ben Asselstine
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Library General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
//  02110-1301, USA.

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <stdlib.h>
#include "Configuration.h"
#include "xmlhelper.h"
#include "tarhelper.h"
#include "File.h"
#include "ucompose.hpp"
#include "game-parameters.h"
#include "GameScenario.h"
#include "CreateScenario.h"
#include "armysetlist.h"
#include "shieldsetlist.h"
#include "CreateScenarioRandomize.h"
#include "counter.h"
#include "stack.h"
#include "fight.h"
#include "armyproto.h"
#include "army.h"
#include "citylist.h"
#include "ruinlist.h"
#include "templelist.h"
#include "roadlist.h"
#include "city.h"
#include "heroproto.h"
#include "armyprodbase.h"
#include "bridge.h"

std::string create_and_dump_scenario(const std::string &file, const GameParameters &g)
{
  CreateScenario creator (g.map.width, g.map.height);

  // then fill the other players
  int army_id = Armysetlist::getInstance()->getArmyset(g.army_theme)->getId();
  Shieldsetlist *ssl = Shieldsetlist::getInstance();
  guint32 id = ssl->getShieldset(g.shield_theme)->getId();
  for (std::vector<GameParameters::Player>::const_iterator
       i = g.players.begin(), end = g.players.end();
       i != end; ++i) {

    if (i->type == GameParameters::Player::OFF)
      {
        fl_counter->getNextId();
        continue;
      }

    Player::Type type;
    if (i->type == GameParameters::Player::EASY)
      type = Player::AI_FAST;
    else if (i->type == GameParameters::Player::HARD)
      type = Player::AI_SMART;
    else
      type = Player::HUMAN;

    creator.addPlayer(i->name, army_id, ssl->getColor(id, i->id), type);
  }


  CreateScenarioRandomize random;
  // the neutral player must come last so it has the highest id among players
  creator.addNeutral(random.getPlayerName(Shield::NEUTRAL), army_id, 
                     ssl->getColor(id, MAX_PLAYERS), Player::AI_DUMMY);

  // now fill in some map information
  creator.setMapTiles(g.tile_theme);
  creator.setShieldset(g.shield_theme);
  creator.setCityset(g.city_theme);
  creator.setNoCities(g.map.cities);
  creator.setNoRuins(g.map.ruins);
  creator.setNoTemples(g.map.temples);
  int num_signposts = g.map.signposts;
  if (num_signposts == -1)
    num_signposts = CreateScenario::calculateNumberOfSignposts(g.map.width,
                                                               g.map.height,
                                                               g.map.grass);
  creator.setNoSignposts(num_signposts);

  // terrain: the scenario generator also accepts input with a sum of
  // more than 100%, so the thing is rather easy here
  creator.setPercentages(g.map.grass, g.map.water, g.map.forest, g.map.swamp,
                         g.map.hills, g.map.mountains);

  // and tell it the turn mode
  if (g.process_armies == GameParameters::PROCESS_ARMIES_AT_PLAYERS_TURN)
    creator.setTurnmode(true);
  else
    creator.setTurnmode(false);

  // now create the map and dump the created map
  std::string path = File::getSavePath();
  path += file;

  creator.create(g);
  creator.dump(path);
  return path;
}

GameScenario *create_new_scenario(GameParameters &g, GameScenario::PlayMode m)
{
  bool update_uuid = false;
  if (g.map_path.empty()) 
    {
      // construct new random scenario if we're not going to load the game
      std::string path = create_and_dump_scenario("random.map", g);
      g.map_path = path;
    }
  else
    update_uuid = true;

  bool broken = false;
						 
  GameScenario* game_scenario = new GameScenario(g.map_path, broken);
  if (broken)
    return NULL;

  GameScenarioOptions::s_see_opponents_stacks = g.see_opponents_stacks;
  GameScenarioOptions::s_see_opponents_production = g.see_opponents_production;
  GameScenarioOptions::s_play_with_quests = g.play_with_quests;
  GameScenarioOptions::s_hidden_map = g.hidden_map;
  GameScenarioOptions::s_diplomacy = g.diplomacy;
  GameScenarioOptions::s_cusp_of_war = g.cusp_of_war;
  GameScenarioOptions::s_neutral_cities = g.neutral_cities;
  GameScenarioOptions::s_razing_cities = g.razing_cities;
  GameScenarioOptions::s_intense_combat = g.intense_combat;
  GameScenarioOptions::s_military_advisor = g.military_advisor;
  GameScenarioOptions::s_random_turns = g.random_turns;

  game_scenario->setName(g.name);
  game_scenario->setPlayMode(m);

  if (game_scenario->getRound() == 0)
    {
      if (update_uuid)
	game_scenario->setNewRandomId();
      Playerlist::getInstance()->syncPlayers(g.players);
      game_scenario->initialize(g);
    }
  return game_scenario;
}

GameScenario* setup_scenario()
{
  // quick load a test scenario
  GameParameters g;
  GameParameters::Player p;
  p.type = GameParameters::Player::HUMAN;
  p.id = 0;
  p.name = "Mr. Test";
  g.players.push_back(p);
  p.type = GameParameters::Player::EASY;
  p.id = 1;
  p.name = "Evil";
  g.players.push_back(p);
  for (unsigned int i = 2; i < MAX_PLAYERS; i++)
    {
      p.type = GameParameters::Player::OFF;
      p.id = i;
      p.name = "";
      g.players.push_back(p);
    }
  g.map.width = 20;
  g.map.height = 20;
  g.map.grass = 100;
  g.map.water = 0;
  g.map.swamp = 0;
  g.map.forest = 0;
  g.map.hills = 0;
  g.map.mountains = 0;
  g.map.cities = 1;
  g.map.ruins = 0;
  g.map.temples = 0;
  g.map.signposts = 0;
  g.map_path = "";
  g.play_with_quests = GameParameters::NO_QUESTING;
  g.hidden_map = false;
  g.neutral_cities = GameParameters::STRONG;
  g.razing_cities = GameParameters::ALWAYS;
  g.diplomacy = false;
  g.random_turns = false;
  g.quick_start = GameParameters::NO_QUICK_START;
  g.intense_combat = false;
  g.military_advisor = false;
  g.army_theme = "default";
  g.tile_theme = "default";
  g.shield_theme = "default";
  g.city_theme = "default";
  g.process_armies = GameParameters::PROCESS_ARMIES_AT_PLAYERS_TURN;
  g.difficulty = GameScenario::calculate_difficulty_rating(g);
  g.cities_can_produce_allies = false;
  g.cusp_of_war = false;
  g.see_opponents_stacks = true;
  g.see_opponents_production = true;
    
  return create_new_scenario(g, GameScenario::HOTSEAT);
}

void make_stack(Player *p, guint32 num, ArmyProto *proto, Vector<int> tile)
{
  Stack *stack = new Stack(p, tile);
  if (proto->isHero())
    {
      HeroProto *hp = new HeroProto(*proto);
      for (unsigned int i = 0; i < num; i++)
        {
          Hero *h = new Hero(*hp);
          stack->add(h);
        }
      delete hp;
    }
  else
    {
      Army *a;
      for (unsigned int i = 0; i < num; i++)
        {
          a = new Army(*proto);
          stack->add(a);
        }
    }
  GameMap::getInstance()->putStack(stack);
  return;
}

void make_stacks(Player *p, guint32 num, guint32 type, Vector<int> tile)
{
  ArmyProto *proto = 
    Armysetlist::getInstance()->getArmy(p->getArmyset(), type);
  Playerlist::getInstance()->setActiveplayer(p);
  guint32 count = 0;
  for (unsigned int i = 0; i < num; i+= MAX_STACK_SIZE)
    {
      Vector<int> pos;
      switch (count)
        {
        case 0: pos = tile + Vector<int>(0,0); break;
        case 1: pos = tile + Vector<int>(0,1); break;
        case 2: pos = tile + Vector<int>(1,0); break;
        case 3: pos = tile + Vector<int>(1,1); break;
        default: pos = tile + Vector<int>(0,0); break;
        }
      if (i + MAX_STACK_SIZE > num)
        make_stack(p, num % MAX_STACK_SIZE, proto, pos);
      else
        make_stack(p, MAX_STACK_SIZE, proto, pos);
      count++;
    }
}

void _fight_it(unsigned int attacker_type, unsigned int num_attackers, unsigned int defender_type, unsigned int num_defenders, double *num)
{
  Player *p1 = Playerlist::getInstance()->getPlayer(0);
  Player *p2 = Playerlist::getInstance()->getPlayer(1);

  make_stacks(p1, num_attackers, attacker_type, Vector<int>(0,0));
  make_stacks(p2, num_defenders, defender_type, Vector<int>(0,0));

  Playerlist::getInstance()->setActiveplayer(p2);
  Stack* defender = GameMap::getFriendlyStack(Vector<int>(0,0));
  Playerlist::getInstance()->setActiveplayer(p1);
  Stack* attacker = GameMap::getFriendlyStack(Vector<int>(0,0));
  p1->setActivestack(attacker);

  GameMap::getInstance()->updateStackPositions();

  if (num == NULL)
    {
      Fight fight(attacker, defender, Fight::FOR_KICKS);
      guint32 str = fight.getModifiedStrengthBonus(attacker->front());
      printf("%s's modified strength is %d\n", attacker->front()->getName().c_str(), str);
      printf("army bonus is %08x\n", attacker->front()->getStat(Army::ARMY_BONUS));
      printf("strength is %d\n", attacker->front()->getStat(Army::STRENGTH, false));
      printf("ship: %d\n", attacker->front()->getStat(Army::SHIP));
      str = fight.getModifiedStrengthBonus(defender->front());
      printf("%s's modified strength is %d\n", defender->front()->getName().c_str(), str);
      printf("army bonus is %08x\n", defender->front()->getStat(Army::ARMY_BONUS));
      printf("ship: %d\n", defender->front()->getStat(Army::SHIP));
    }
  double p = 0;
  for (unsigned int i = 0; i < 10000; i++)
    {
      Fight fight(attacker, defender, Fight::FOR_KICKS);
      fight.battle(GameScenarioOptions::s_intense_combat);
      if (fight.getResult() == Fight::ATTACKER_WON)
        p += 0.01;
    }

  p1->clearStacklist();
  p2->clearStacklist();
  if (num)
    *num = p;
  else
    printf("%lf\n", p);
  return;
}

using namespace std;
int max_vector_width;
int main(int argc, char* argv[])
{
  srand(time(NULL));
  initialize_configuration();
  Vector<int>::setMaximumWidth(1000);

  #if ENABLE_NLS
  setlocale(LC_ALL, Configuration::s_lang.c_str());
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);
  #endif

  if (argc > 1)
    {
      for (int i = 2; i <= argc; i++)
	{
          string parameter(argv[i-1]); 
	  if (parameter == "--help" || parameter == "-?")
	    {
	      cout << File::get_basename(argv[0], true) << " [OPTION]... FILE" << endl << 
                endl;
	      cout << "LordsAWar! Battle Probability Generation Tool " << _("version") << 
                " " << VERSION << endl << endl;
	      cout << _("Options:") << endl << endl; 
	      cout << "  -?, --help                 " << _("Display this help and exit") <<endl;
	      cout << endl;
	      cout << _("Report bugs to") << " <" << PACKAGE_BUGREPORT ">." << endl;
	      exit(0);
	    }
	}
    }

  GameScenario *game_scenario = setup_scenario();
  GameMap::getInstance()->removeCity(Citylist::getInstance()->front()->getPos());

  /*
  Player *p2 = Playerlist::getInstance()->getPlayer(1);
  Playerlist::getInstance()->setActiveplayer(p2);
  GameMap::getInstance()->putNewCity(Vector<int>(0,0));
  City *c = GameMap::getCity(Vector<int>(0,0));
  (*c)[0]->setArmyProdBase(new ArmyProdBase(*Armysetlist::getInstance()->getArmy(p2->getArmyset(), 0)));
  */
  for (unsigned int i = 0; i < 8; i++)
    {
      double p;
      _fight_it(26, 1, 3, i + 1, &p);
      printf("%lf\n", p);
    }

  delete game_scenario;
}
