/**
   * @param attacks - a set of MoveAttack
   * @return the list of my neighbor that haven't attack me, since I can't attack someone who
   *     already attack me
   * @throws BadAcquaintancesException
   */
  private MoveAttackReturn manageIncomingMoveAttack(Set<EcoAttack> attacks)
      throws BadAcquaintancesException {
    if (attacks.size() > 1) { // si j'ai plus d'un voisin qui m'attaque j'en choisi au hasard
      System.err.println("I'm attack by various move attack, choose randomly"); // $NON-NLS-1$
    }
    EcoAttack attack = attacks.iterator().next();
    EcoIdentity target = attack.getAssailant();
    EcoIdentity[] neighboors = getNeighboors();
    EcoIdentity me = this.getEcoIdentity();
    EcoRelation defenderUp;
    EcoRelation defenderDown;
    EcoRelation defenderRight;
    EcoRelation defenderLeft;
    EcoRelation defenderHosted;

    if (target.equals(neighboors[0])) { // move to up
      defenderUp = new Down(me, target);
      defenderDown = new Up(target, me);
      defenderRight = new Left(target, neighboors[1]);
      defenderLeft = new Right(target, neighboors[3]);
    } else if (target.equals(neighboors[1])) { // move to right
      defenderUp = new Down(target, neighboors[0]);
      defenderDown = new Up(target, neighboors[2]);
      defenderRight = new Left(me, target);
      defenderLeft = new Right(target, neighboors[3]);
    } else if (target.equals(neighboors[2])) { // move to down
      defenderUp = new Down(me, target);
      defenderDown = new Up(target, neighboors[2]);
      defenderRight = new Left(target, neighboors[1]);
      defenderLeft = new Right(target, neighboors[3]);
    } else if (target.equals(neighboors[3])) { // move to left
      defenderUp = new Down(target, neighboors[0]);
      defenderDown = new Up(target, neighboors[2]);
      defenderRight = new Left(me, target);
      defenderLeft = new Right(target, neighboors[3]);
    } else {
      throw new BadAcquaintancesException();
    }
    defenderHosted = new Hosted(target, getPlace());

    Collection<EcoRelation> newTargetAcquaintances = new LinkedList<EcoRelation>();
    newTargetAcquaintances.add(defenderUp);
    newTargetAcquaintances.add(defenderDown);
    newTargetAcquaintances.add(defenderRight);
    newTargetAcquaintances.add(defenderLeft);
    newTargetAcquaintances.add(defenderHosted);

    MoveAttackReturn ack = new MoveAttackReturn(me, target, newTargetAcquaintances);

    this.setAcquaintances(attack.getConstraints());
    return ack;
  }
  /**
   * Forward manhattan attacks and manage the ones having as origin the blank tiles or my goals
   *
   * @param attacks a set of ManhattanDistanceAttack
   * @return
   * @throws BadAcquaintancesException
   */
  private final Set<ManhattanDistanceAttack> manageManhattanAttack(Set<EcoAttack> attacks)
      throws BadAcquaintancesException {

    Set<ManhattanDistanceAttack> manhattanAttacks = new HashSet<ManhattanDistanceAttack>();

    // Source of attack, distance from source, list of neighbor having the same distance
    this.sourceDistAndNeighbors = new TreeMap<EcoIdentity, TreeMap<Integer, List<EcoIdentity>>>();

    // Manage the list of my neighbors that haven't sent the attack from the corresponding source,
    // map<attack source, where to forward it>
    Map<EcoIdentity, List<EcoIdentity>> sourcePlaceAndAttackForwarders =
        new HashMap<EcoIdentity, List<EcoIdentity>>();

    List<EcoIdentity> neighboors = getNeighboorsAsList();

    // Find the minimal Manhattan distance of the various attacks having the same origin;
    // also register which of my neighbors send me this attack to forward it only to this other ones
    {
      EcoIdentity currentOrigin;
      Integer attackDist;
      List<EcoIdentity> attackForwarders;
      EcoIdentity neighboor;

      TreeMap<Integer, List<EcoIdentity>> distAndNeighbors;
      List<EcoIdentity> currentListOfNeighborHavingTheSameDist;

      for (EcoAttack attack : attacks) {
        currentOrigin = ((ManhattanDistanceAttack) attack).getAttackOrigin();
        neighboor = attack.getAssailant();
        attackDist = ((ManhattanDistanceAttack) attack).getManhattanDistance();

        distAndNeighbors = this.sourceDistAndNeighbors.get(currentOrigin);
        if (distAndNeighbors == null) {
          distAndNeighbors = new TreeMap<Integer, List<EcoIdentity>>();
          currentListOfNeighborHavingTheSameDist = new LinkedList<EcoIdentity>();
        } else {
          currentListOfNeighborHavingTheSameDist = distAndNeighbors.get(attackDist);
        }
        currentListOfNeighborHavingTheSameDist.add(neighboor);
        distAndNeighbors.put(attackDist, currentListOfNeighborHavingTheSameDist);
        this.sourceDistAndNeighbors.put(currentOrigin, distAndNeighbors);

        // who send me an attack ? which neighbors ?
        attackForwarders = sourcePlaceAndAttackForwarders.get(currentOrigin);
        if (attackForwarders != null) {
          attackForwarders.remove(neighboor);
          sourcePlaceAndAttackForwarders.put(currentOrigin, attackForwarders);
        } else {
          attackForwarders = new LinkedList<EcoIdentity>(neighboors);
          attackForwarders.remove(neighboor);
          sourcePlaceAndAttackForwarders.put(currentOrigin, attackForwarders);
        }
      }
    }

    // Determine the various attack I have to forward to those of my neighbor whose haven't received
    // it
    // also determine the nearest neighbors from my goal and the blank tile
    {
      List<EcoIdentity> toFowards;
      EcoIdentity attackOrigin;
      Integer currentMinMahanttanDistance;
      Object[] params;

      for (Map.Entry<EcoIdentity, TreeMap<Integer, List<EcoIdentity>>> e :
          this.sourceDistAndNeighbors.entrySet()) {
        attackOrigin = e.getKey();
        currentMinMahanttanDistance = e.getValue().firstKey();

        // THE ONLY DIFFERENCE WITH ITS PARENT METHOD
        // if (!this.isSatisfied()) { // if I'm satisfied I do not forward the attack
        toFowards = sourcePlaceAndAttackForwarders.get(attackOrigin);
        for (EcoIdentity to : toFowards) {
          params = new Object[2];
          params[0] = currentMinMahanttanDistance;
          params[1] = e.getKey();
          manhattanAttacks.add(new ManhattanDistanceAttack(this.getEcoIdentity(), to, params));
        }
        // }

        // I'm under attack and I forward it to all of my neighbors
        if (attackOrigin.equals(this.getEcoIdentity())) {
          params = new Object[2];
          params[0] = 0;
          params[1] = attackOrigin;
          if (neighboors.get(0) != null)
            manhattanAttacks.add(
                new ManhattanDistanceAttack(this.getEcoIdentity(), neighboors.get(0), params));
          if (neighboors.get(1) != null)
            manhattanAttacks.add(
                new ManhattanDistanceAttack(this.getEcoIdentity(), neighboors.get(1), params));
          if (neighboors.get(2) != null)
            manhattanAttacks.add(
                new ManhattanDistanceAttack(this.getEcoIdentity(), neighboors.get(2), params));
          if (neighboors.get(3) != null)
            manhattanAttacks.add(
                new ManhattanDistanceAttack(this.getEcoIdentity(), neighboors.get(3), params));
        }
      }
    }

    return manhattanAttacks;
  }