#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <cstdio>

#include "Player.h"
#include "Scout.h"
#include "Soldier.h"
#include "Pyro.h"

using std::cout;
using std::endl;
using std::vector;

int Random(int low, int high)
{
  int r1 = static_cast<int>( std::rand() / 2 - 1 );
  return r1 % (high - low + 1) + low;
}

 //********************************************************************
void TestSimple1()
{
    // No polymorphism
  Scout scout("Moe", 100, 1, 5);
  Soldier soldier("Larry", 150, 2, 10);
  Pyro pyro("Curly", 200, 3, 15);

  cout << scout.WhoAmI() << endl;
  cout << soldier.WhoAmI() << endl;
  cout << pyro.WhoAmI() << endl;
}

//********************************************************************
void TestSimple2()
{
    // Take the default values
  Player *p[] = {new Scout("Moe"), new Soldier("Larry"), new Pyro("Curly")};

  // Polymorphism
  for (unsigned i = 0; i < sizeof(p) / sizeof(*p); i++)
  {
    cout << p[i]->WhoAmI() << endl;
    delete p[i];
  }
}

bool isAlive(const vector<Player *>& team)
{
  vector<Player *>::const_iterator it;
  for (it = team.begin(); it != team.end(); ++it)
    if ((*it)->isAlive())
      return true;

  return false;
}

void print_results(const vector<Player *>& team1, const vector<Player *>& team2)
{
  vector<Player *>::const_iterator it;

    // team1 won
  if (isAlive(team1))
  {
    cout << "Team 1 wins!" << endl;
    cout << "Team 1: ";
    for (it = team1.begin(); it != team1.end(); ++it)
      cout << (*it)->getName() << "[" << (*it)->getHealth() << "]  ";

    cout << endl;
    cout << "Team 2: ";
    for (it = team2.begin(); it != team2.end(); ++it)
      cout << (*it)->getName() << "[" << (*it)->getHealth() << "]  ";
    cout << endl;
  }
  else
  {
    cout << "Team 2 wins!" << endl;
    cout << "Team 1: ";
    for (it = team1.begin(); it != team1.end(); ++it)
      cout << (*it)->getName() << "[" << (*it)->getHealth() << "]  ";

    cout << endl;
    cout << "Team 2: ";
    for (it = team2.begin(); it != team2.end(); ++it)
      cout << (*it)->getName() << "[" << (*it)->getHealth() << "]  ";
    cout << endl;
  }
}

#define VERBOSEx

void fight(const vector<Player *>& team1, const vector<Player *>& team2)
{
  vector<Player *>::const_iterator it;
  cout << "Team 1:" << endl;
  for (it = team1.begin(); it != team1.end(); ++it)
    cout << (*it)->WhoAmI() << endl;

  cout << "Team 2:" << endl;
  for (it = team2.begin(); it != team2.end(); ++it)
    cout << (*it)->WhoAmI() << endl;

  cout << endl;

    // While at least one team member is still alive
  while (isAlive(team1) && isAlive(team2))
  {
    int attacker, attackee;
    Player *player1, *player2;

      // If 1, team1 attacks team2
    if (Random(0, 1))
    {
        // Choose a player from Team 1 that is still alive
      do
      {
        attacker = Random(0, team1.size() - 1);
        player1 = team1[attacker];
      }
      while (!player1->isAlive());

        // Choose a player from Team 2 that is still alive
      do
      {
        attackee = Random(0, team2.size() - 1);
        player2 = team2[attackee];
      }
      while (!player2->isAlive());

        // 0=attack, 1=attack2
      if (Random(0, 1)) 
        player1->Attack2(*player2);
      else
        player1->Attack(*player2);

      #ifdef VERBOSE
        cout << player1->getName() << " is attacking "
             << player2->getName() << " (health=" << player2->getHealth() << ")" << endl;
      #endif

      if (!player2->isAlive())
        cout << player2->getName() << " was killed by " << player1->getName() << endl;

    }
    else // team2 attacks team1
    {
        // Choose a player from Team 2 that is still alive
      do
      {
        attacker = Random(0, team2.size() - 1);
        player2 = team2[attacker];
      }
      while (!player2->isAlive());

        // Choose a player from Team 1 that is still alive
      do
      {
        attackee = Random(0, team1.size() - 1);
        player1 = team1[attackee];
      }
      while (!player1->isAlive());

        // 0=attack, 1=attack2
      if (Random(0, 1)) 
        player2->Attack2(*player1);
      else
        player2->Attack(*player1);

      #ifdef VERBOSE
        cout << player2->getName() << " is attacking "
             << player1->getName() << " (health=" << player1->getHealth() << ")" << endl;
      #endif

      if (!player1->isAlive())
        cout << player1->getName() << " was killed by " << player2->getName() << endl;
    }
  }
}

void delete_team(const vector<Player *>& team)
{
  vector<Player *>::const_iterator it;
  for (it = team.begin(); it != team.end(); ++it)
    delete *it;
}

void TestFight()
{
    // Red team
  vector<Player *> red_team;
  red_team.push_back(new Scout("Moe", 20, 1, 5));
  red_team.push_back(new Soldier("Larry", 30, 2, 3));
  red_team.push_back(new Pyro("Curly", 40, 3, 2));

    // Blue team
  vector<Player *> blue_team;
  blue_team.push_back(new Scout("Fred", 20, 1, 5));
  blue_team.push_back(new Soldier("Barney", 30, 2, 3));
  blue_team.push_back(new Pyro("Wilma", 40, 3, 2));

  fight(red_team, blue_team);
  print_results(red_team, blue_team);

  delete_team(red_team);
  delete_team(blue_team);
}

std::vector<Player *> make_team(int count, int team)
{
  const int MAXNAME = 20;
  std::vector<Player *> players;

  for (int i = 0; i < count; i++)
  {
    char name[MAXNAME];
    int type = Random(0, 2); // Scout, Soldier, or Pyro
    Player *player;
    int health, damage1, damage2;

    if (type == 0) // Scout
    {
      health = Random(20, 30);
      damage1 = Random(1, 5);
      damage2 = Random(3, 7);
      std::sprintf(name, "Scout%i-%02i", team, i);
      player = new Scout(name, health, damage1, damage2);
    }
    else if (type == 1) // Soldier
    {
      health = Random(30, 50);
      damage1 = Random(3, 7);
      damage2 = Random(5, 10);
      std::sprintf(name, "Soldier%i-%02i", team, i);
      player = new Soldier(name, health, damage1, damage2);
    }
    else // Pyro
    {
      health = Random(50, 90);
      damage1 = Random(5, 9);
      damage2 = Random(10, 12);
      std::sprintf(name, "Pyro%i-%02i", team, i);
      player = new Pyro(name, health, damage1, damage2);
    }

    players.push_back(player);
  }

  return players;
}

void stress(int count)
{
  std::vector<Player *> team1 = make_team(count, 1);
  std::vector<Player *> team2 = make_team(count, 2);

  fight(team1, team2);
  print_results(team1, team2);

  delete_team(team1);
  delete_team(team2);
}


int main(int argc, char **argv)
{
  std::srand(std::time(0));
  int count = 10;
  //TestSimple1();
  //TestSimple2();
  //TestFight();

  if (argc > 1)
    count = std::atoi(argv[1]);

  stress(count);

  return 0;
}