//  Group D

package risk.engine.ai;

import risk.engine.*;
import risk.engine.core.*;

import java.util.*;

/**
 * <p> Class for AIHardPlayer </p>
 * @author SE Group D
 */

public class AIHard extends AIEasy {

    public String getPlaceArmies() {

		String output;

		   if ( game.NoEmptyCountries()==false ) {

		       Continent[] cont = game.getContinents();

		       /* ai looks at all the continents and tries to see which one it should place on
			The formula for placement is :
			extraArmiesForContinent - numberOfBorders - (neighborTerritories - numberOfBorders)+(territorynum * 0.9)-(IIF(numberofEnemyUnits=0,-3,numberofEnemyUnits) * 1.2)
			 */
			
		       int extraArmiesForContinent = 0;
		       int numberOfBorders = 0;
		       int neighborTerritories = 0;
		       int numberofEnemyUnits = -3;
		       int territorynum = 0;
		       boolean isBorder = false;
		       double check = -20;
		       double ratio = -20;
		       String name="";
		       int val = -1;

		       for (int i=0; i<cont.length; i++) {
		     	  Vector ct = new Vector();
			  Continent co = cont[i];

			  extraArmiesForContinent = co.getArmyValue();

			  ct = co.getTerritoriesContained();

			  for (int j=0; j<ct.size(); j++) {
			     if ( ((Country)ct.elementAt(j)).getOwner() == player ) { 
				/* This territory belongs to the player */
			        territorynum++; 
				}
			     else {
				if (((Country)ct.elementAt(j)).getOwner() != null) {
				   /* This territory belongs to an enemy */
			           if (numberofEnemyUnits == -3) {
				      numberofEnemyUnits = 1;
				   }
			           else {
				      numberofEnemyUnits++;
			           }
				}
			     }
			     Vector w = ((Country)ct.elementAt(j)).getNeighbours();
                                for (int k=0; k<w.size(); k++) {
                                   if (((Country)w.elementAt(k)).getContinent() != co) {
				      /* This is a territory to protect from */
                                      neighborTerritories++;				      
				      isBorder = true;
                                   }
				}
				if (isBorder) {
				   numberOfBorders++;
				}
			  }

			  /* Calculate the value of that continent */ 

			  ratio = extraArmiesForContinent - numberOfBorders - (neighborTerritories - numberOfBorders)+(territorynum * 0.9) - (numberofEnemyUnits * 1.2);

			  if (check <= ratio && hasFreeTerritories(ct) == true) {
			      check = ratio;
			      val = i;
			  }

			  territorynum = 0;
		          numberofEnemyUnits = -3;
			  neighborTerritories = 0;
                          numberOfBorders = 0;
		       }
		       if (val==-1) { val=0; } // YURA: val is not being set

		       /* ..pick country from that continent */
                       boolean picked = false;
		       if (check > 0) {
			  Continent co = cont[val];
		          Vector ct = co.getTerritoriesContained();

			  for (int j=0; j<ct.size(); j++) {
			     if ( ((Country)ct.elementAt(j)).getOwner() == null )  {
				name=((Country)ct.elementAt(j)).getColor()+"";
				picked = true;
				break;
			     }
			  }
		       }

                       if (picked == false) {
                          Continent co = cont[val];
                          Vector ct = co.getTerritoriesContained();

                          for (int j=0; j<ct.size(); j++) {
                             if ( ((Country)ct.elementAt(j)).getOwner() == null )  {
                                name=((Country)ct.elementAt(j)).getColor()+"";

                                Vector v = ((Country)ct.elementAt(j)).getNeighbours();
                                for (int k=0; k<v.size(); k++) { // YURA: was ct.size()
                                   if (((Country)v.elementAt(k)).getOwner() != player) {
                                      name=((Country)ct.elementAt(j)).getColor()+"";
                                      break;
                                   }
                                }
                             }
                          }
                       }

                       String s = blockOpponent(player);
                       if( !s.equals("none") )
                          name = s;

		       if (name.equals(""))
			  output = "autoplace";

		       else
			output = "placearmies " + name +" 1";
		   }
		   else {


		       Vector t = player.getTerritoriesOwned();
		       Vector n;
		       String name="";

		       for (int a=0; a< t.size() ; a++) {

                          if ( ownsNeighbours( (Country)t.elementAt(a)) == false && ((Country)t.elementAt(a)).getArmies() <= 11 ) {

                              name=((Country)t.elementAt(a)).getColor()+"";
                              break;
                          }

		          if ( !(name.equals("")) ) { break; }

		       }

                       String s = keepBlocking(player);
                       if( !s.equals("none") )
                          name = s;

                       String f = freeContinent(player);
                       if( !f.equals("none") )
                          name = f;

		       if ( name.equals("") )
			   output = "placearmies " + ((Country)t.elementAt(0)).getColor() +" "+player.getExtraArmies();

		       else if (game.getSetup() )
			   output = "placearmies " + name +" "+player.getExtraArmies();

		       else
			   output = "placearmies " + name +" 1";
		   }

		return output;

    }

    public String getBattleWon() {

		String output;

		   /* Attempt to safeguard critical areas when moving armies to won country */

		   Country attacker = game.getAttacker();
		   Continent continent = attacker.getContinent();
		   if (continent.isOwned(player) == true || mostlyOwned(continent) == true) {

		       /* Set 50% security limit */
		       if (attacker.getArmies() > 6)
		   	   output = "move " + (attacker.getArmies()-1);

		       else if (attacker.getArmies() > 3 && attacker.getArmies() <= 6)
			   output = "move " + (attacker.getArmies()-1);

		       else
			   output = "move all";
                   }
		   else
		      output="move all";

		return output;

    }

    public String getTacMove() {

		String output="";

		    /* reinforces armies from less critical to more critical areas */

		    Vector t = player.getTerritoriesOwned();
		    Vector n;
		    boolean possible = false;
                    int difference = 0;
                    Country sender = null;
                    Country receiver = null;
                    Country temp = null;
                    int highest = 1;

		    for (int a=0; a<t.size(); a++) {

			Country country = ((Country)t.elementAt(a));
			difference  = country.getArmies();
			if (difference > highest)  {
			    highest = difference;
			    sender = country;
			}
		    }

		    if (sender != null)  {

			receiver = check1(sender);

			if (receiver == null) {
			    n = sender.getNeighbours();
			    for (int i=0; i<n.size(); i++) {
				temp = (Country) n.elementAt(i);
				if (temp.getOwner() == player) {
				    possible = check2(temp);
				}
				if (possible == true)  { receiver = temp; break; }
			    }
			}
		    }

		    if (receiver != null && receiver != sender) {
			output= "movearmies " + ((Country)sender).getColor() + " " + ((Country)receiver).getColor() + " " + (((Country)sender).getArmies()-1);
			//System.out.println(((Country)sender).getName()); TESTING
			//System.out.println(((Country)receiver).getName()); TESTING
		    }

		    if ( output.equals("") ) {
			output = "nomove";
		    }

		return output;

    }

    public String getAttack() {

		String output="";

		Vector t = player.getTerritoriesOwned();
		Vector n;

                    boolean chosen = false;
		    Continent[] cont = game.getContinents();


		    for (int a=0; a< t.size() ; a++) {
		        if ( ((Country)t.elementAt(a)).getArmies() > 1 ) {
		   	     n = ((Country)t.elementAt(a)).getNeighbours();

                             /* attack ratio set to 50% of attack force */

                             int ratio = ((Country)t.elementAt(a)).getArmies();
			     for (int b=0; b< n.size() ; b++) {
			         if ( ((Country)n.elementAt(b)).getOwner() != player && ((Country)n.elementAt(b)).getArmies() + (ratio / 2) < ratio  ) {
				     output= "attack " + ((Country)t.elementAt(a)).getColor() + " " + ((Country)n.elementAt(b)).getColor();
			         }
			     }
		         }
		    }


		   /* attempt to attack continent which is almost all owned, if scenario is there */

                   int count = 0;
                   Country attackfrom = null;
                   boolean complex = false;

                   for (int i=0; i<cont.length; i++) {

                       if ( mostlyOwned( cont[i] ) == true) {

			   n = cont[i].getTerritoriesContained();

			   for (int j=0; j<n.size(); j++) {

                               if ( ((Country)n.elementAt(j)).getArmies() > count && ((Country)n.elementAt(j)).getOwner() == player ) {
                                     count = ((Country)n.elementAt(j)).getArmies();
                                     attackfrom = (Country)n.elementAt(j);
                               }

			   }

			   for (int b=0; b< n.size() ; b++) {
			        if ( ((Country)n.elementAt(b)).getOwner() != player && (((Country)n.elementAt(b)).getArmies()+1) < count && ((Country)n.elementAt(b)).isNeighbours(attackfrom) == true ) {
                                      output= "attack " + attackfrom.getColor() + " " + ((Country)n.elementAt(b)).getColor();
                                      complex = true;
                                      break;
                                }
			   }
                       }
                   }

                   // else attempt to attack continent with the greatest territories owned, that has yet to be conquered.

                   if (complex == false) {
                      int value = 0;
                      Continent choice = null;

                      for (int i=0; i<cont.length; i++) {

                         if ( cont[i].isOwned(player) == false) {

                             n = cont[i].getTerritoriesContained();

                             int check = 0;
                             for (int j=0; j<n.size(); j++) {
                                if ( ((Country)n.elementAt(j)).getOwner() == player )
                                   check++;
                             }

                             if (check > value)
                                choice = cont[i];
                         }
                      }

                      if (choice !=null) {

                         //System.out.println(choice.getName()); TESTING
                         n = ((Continent)choice).getTerritoriesContained();

                         for (int j=0; j<n.size(); j++) {

                             if ( ((Country)n.elementAt(j)).getArmies() > count && ((Country)n.elementAt(j)).getOwner() == player ) {
                                   count = ((Country)n.elementAt(j)).getArmies();
                                   attackfrom = (Country)n.elementAt(j);
                             }
                         }

                         for (int b=0; b< n.size() ; b++) {
			     if ( ((Country)n.elementAt(b)).getOwner() != player && (((Country)n.elementAt(b)).getArmies()+1) < count && ((Country)n.elementAt(b)).isNeighbours(attackfrom) == true ) {
                                   output= "attack " + attackfrom.getColor() + " " + ((Country)n.elementAt(b)).getColor();
                                   break;
                             }
                         }
                      }
                   }

                   // check to see if there are any players to eliminate

                   Vector players = game.getPlayers();
                   Vector cankill = new Vector();

                   for (int i=0; i<players.size(); i++) {
                      if (( (Player) players.elementAt(i)).getNoTerritoriesOwned() < 3 && ( (Player) players.elementAt(i)) != player)
                         cankill.addElement((Player) players.elementAt(i));
                   }

                   if (cankill.size() > 0) {
                      for (int i=0; i<cankill.size(); i++) {
                         Vector territories = ((Player) cankill.elementAt(i)).getTerritoriesOwned();
                         for (int j=0; j<territories.size(); j++) {

                            Vector neighbours = ((Country)territories.elementAt(j)).getNeighbours();
                            for (int k=0; k<neighbours.size(); k++) {
                                  if (((Country) neighbours.elementAt(k)).getOwner() == player && (((Country)territories.elementAt(j)).getArmies() + 1 < ((Country) neighbours.elementAt(k)).getArmies())  ) {
                                      output= "attack " + ((Country) neighbours.elementAt(k)).getColor() + " " + ((Country)territories.elementAt(j)).getColor();
                                      //System.out.println("eliminate: " + output); TESTING
                                      break;
                                  }
                            }
                         }
                      }
                   }

	      	   if ( output.equals("") ) {
		  	output="endattack";
		   }

		return output;

    }

    public String getRoll() {

		String output;

		int n=((Country)game.getAttacker()).getArmies() - 1;


		/* Only roll for as long as while attacking player has more armies than defending player */
		int m=((Country)game.getDefender()).getArmies();

		if (n > 3 && n > m) {
		    output= "roll "+3;
		}
		else if (n <= 3 && n > m) {
		    output= "roll "+n;
		}
		else {
		    output= "retreat";
		}

		return output;

    }








    /**
     * Checks if the player owns most of the territories within a continent
     * @param p player object
     * @return boolean True if the player owns most of the territories within a continent,
     * otherwise false if the player does not own most of the territories
     */
    public boolean mostlyOwned(Continent w) {

	int ownedByPlayer=0;

	Vector territoriesContained = w.getTerritoriesContained();

	for (int c=0; c< territoriesContained.size() ; c++) {

	    if ( ((Country)territoriesContained.elementAt(c)).getOwner() == player ) {
		ownedByPlayer++;
	    }

	}

	if ( ownedByPlayer>=(territoriesContained.size()/2) ) {
	    return true;
	}
	else {
	   return false;
	}

    }

    /**
     * Checks if the player can make a valid tactical move
     * @param p player object, b Country object
     * @return Country if the tactical move is valid, else returns null.
     */
    public Country check1(Country b) {

      Vector neighbours = b.getNeighbours();
      Country c = null;

      for (int i=0; i<neighbours.size(); i++) {
         if ( ownsNeighbours( (Country)neighbours.elementAt(i)) == false && ((Country)neighbours.elementAt(i)).getOwner() == player)
              return (Country)neighbours.elementAt(i);
      }
     return c;
    }

    /**
     * Checks if the player can make a valid tactical move
     * @param p player object, b Country object
     * @return booelean True if the tactical move is valid, else returns false.
     */
    public boolean check2(Country b) {

      Vector neighbours = b.getNeighbours();
      Country c = null;

      for (int i=0; i<neighbours.size(); i++) {
         if ( ownsNeighbours( (Country)neighbours.elementAt(i)) == false && ((Country)neighbours.elementAt(i)).getOwner() == player)
              return true;
      }
     return false;
    }


    /**
     * Attempts to block an opposing player gaining a continent during the initial placement
     * @param p player object
     * @return String name if a move to block the opponent is required/possible, else returns "none"
     */
    public String blockOpponent(Player p) {
       Continent[] continents = game.getContinents();
       Vector players = game.getPlayers();

       for (int i=0; i<players.size(); i++) {
          for (int j=0; j<continents.length; j++) {
              if ( almostOwned((Player) players.elementAt(i), continents[j] ) == true
                   && continents[j].isOwned( (Player)players.elementAt(i) ) == false
                   && (Player) players.elementAt(i) != p ) {
                        Vector v = continents[j].getTerritoriesContained();
                        for (int k=0; k<v.size(); k++) {
                             if ( ((Country) v.elementAt(k)).getOwner() == null) {
                                 return ((Country) v.elementAt(k)).getColor()+"";
                             }
                        }
              }
          }
       }
    return "none";
    }

    /**
     * Attempts to block an opposing player gaining a continent during the actual game
     * @param p player object
     * @return String name if a move to block the opponent is required/possible, else returns "none"
     */
    public String keepBlocking(Player p) {
       Continent[] continents = game.getContinents();
       Vector players = game.getPlayers();

       for (int i=0; i<players.size(); i++) {
          for (int j=0; j<continents.length; j++) {
              if ( almostOwned((Player) players.elementAt(i), continents[j]) == true
                   && continents[j].isOwned((Player) players.elementAt(i)) == false
                   && (Player) players.elementAt(i) != p ) {
                        Vector v = continents[j].getTerritoriesContained();
                        for (int k=0; k<v.size(); k++) {
                             if ( ((Country) v.elementAt(k)).getOwner() == p && ((Country) v.elementAt(k)).getArmies() < 5) {
                                 return ((Country) v.elementAt(k)).getColor()+"";
                             }
                        }
              }
          }
       }
    return "none";
    }

    /**
     * Attempts to free a continent from an enemy player if it is possible to do so
     * @param p player object
     * @return Sring name is a move to free a continent is required/possible, else returns "none"
     */
    public String freeContinent(Player p) {
       Continent[] continents = game.getContinents();
       Vector players = game.getPlayers();

       for (int i=0; i<players.size(); i++) {
          for (int j=0; j<continents.length; j++) {
              if ( continents[j].isOwned((Player) players.elementAt(i)) == true
                   && (Player) players.elementAt(i) != p ) {

                        Vector v = continents[j].getTerritoriesContained();
                        for (int k=0; k<v.size(); k++) {
                            Vector neighbours = ((Country) v.elementAt(k)).getNeighbours();
                             for (int l=0; l<neighbours.size(); l++) {             // .equals(p.getName())
                                 if ( (((Country) neighbours.elementAt(l)).getOwner()) == p                && ((Country) neighbours.elementAt(l)).getArmies() < 5) {
                                        return ((Country) neighbours.elementAt(l)).getColor()+"";
                                 }
                             }
                        }
                }
            }
        }
        return "none";
    }

    /**
     * Checks if the player owns almost all of the territories within a continent
     * @param p player object
     * @return booelan True if the player owns almost all of the territories within a continent,
     * otherwise false if the player does not own most of the territories
     */
    public boolean almostOwned(Player p, Continent co) {

	int ownedByPlayer=0;
        Vector territoriesContained = co.getTerritoriesContained();

	for (int c=0; c< territoriesContained.size() ; c++) {

	    if ( ((Country)territoriesContained.elementAt(c)).getOwner() == p ) {
		ownedByPlayer++;
	    }

	}

	if ( ownedByPlayer>=(territoriesContained.size()-2) ) {
	    return true;
	}
	else {
	   return false;
	}

    }

    /**
     * Checks whether a country owns its neighbours
     * @param p player object, c Country object
     * @return boolean True if the country owns its neighbours, else returns false
     */
    public boolean ownsNeighbours(Country c) {
        Vector neighbours = c.getNeighbours();
        int count = 0;

        for (int i=0; i<neighbours.size(); i++) {
           if ( ((Country) neighbours.elementAt(i)).getOwner() == player)
               count++;
        }

        if (count == neighbours.size())
            return true;

    return false;
    }

    /**
     * Checks if a player is still playing the game
     * @param p player object
     * @return booelan True if player is present, else return false
     */
    public boolean playerKilled(Player p) {
       Vector play = game.getPlayers();

       for (int i=0; i<play.size(); i++) {
         if ( (Player) play.elementAt(i) == p)
             return true;
       }
       return false;
     }


    /**
     * Checks if a continent has a free territory
     * @param ct Vector of countries in the continent
     * @return boolean true if there is a free country, otherwise returns false
     */
    public boolean hasFreeTerritories(Vector ct) {
	for (int i=0; i<ct.size(); i++)
	    if (((Country) ct.elementAt(i)).getOwner() == null)
	    	return true;
	return false;
    }

}
