import java.util.*;
import java.awt.Point;

import fr.cnam.ihm.*;
import fr.cnam.tore.*;

// Classe de definition d'un agent
//
public class Agent extends Thread
{
  int           num;      // Numero unique de l'agent
  int           couleur;  // Couleur de l'agent
  Point         pos;      // Position courante de l'agent
  ExempleAgent  exemple;  // Reference vers l'exemple utilise par chaque agent

  // Constructeur
  //
  public Agent(int num,int couleur,Point pos,ExempleAgent exemple)
  {
    this.num=num;
    this.couleur=couleur;
    this.pos=pos;
    this.exemple = exemple;
    exemple.grille.setMarque(couleur,pos.x,pos.y);
    start();
  }

  // Le thread de l'agent qui realise le deplacement
  //
  public void run()
  {
    try{
      while(true)
        {
          // Deplacement aleatoire 
          if (exemple.mode==1) 
            deplacerAleat();

          // Deplacement vers le point designe si l'agent est noir et num=1
          if (exemple.mode==2) {
            if (couleur==1){
              if (!deplacerVersPointDesigne())
                if (! deplacerEnsemble())
                  deplacerAleat();
            }
            else {
              if (! deplacerEnsemble())
                deplacerAleat();
            }
          }

          // Deplacement ensemble de tous les agents d'une meme couleur
          if (exemple.mode==3) 
            {
              if (! deplacerEnsemble())
                deplacerAleat();
            }

          // Deplacement de fuite
          if (exemple.mode==4) 
            {
              if (!fuirLePointDesigne())
                if (! deplacerEnsemble())
                  deplacerAleat();
            }

          // Pour ralentir les deplacements pour les suivre a l'ecran
          try{Thread.sleep(200);}catch(Exception ex){};
        }

    }catch(Exception ex){ex.printStackTrace();}
  }

  // Deplacement aleatoire de l'agent
  //
  private boolean deplacerAleat()
  {
    // Sens de deplacement aleatoire
    int sensX = exemple.rdm.nextInt(3)-1;
    int sensY = exemple.rdm.nextInt(3)-1;
    
    // Calcul du nouveau point en fonction du sens dans un espace de tore
    Point p = exemple.espace.deplacer(pos.x,pos.y,sensX,sensY);
    
    // Si le point de destination est occupe alors pas de deplacement
    if (exemple.grille.getMarque(p.x,p.y)!=0) return false;

    // Deplacement
    exemple.grille.setMarque(0,pos.x,pos.y);
    exemple.grille.setMarque(couleur,p.x,p.y);
    pos=p;

    return true;
  }
  
  // Deplacement de l'agent vers un point designe dans la grille
  //
  private boolean deplacerVersPointDesigne()
  {
    // Seul l'agent de numero 0 se deplace vers le point designe
    if (num!=0) return false;

    // Si le point designe n'existe pas alors pas de deplacement
    if (exemple.pointCourant==null) return false;;

    // Calcul du sens de deplacement dans l'espace de tore
    Point sens = exemple.espace.sensTore(new Point(pos.x,pos.y),exemple.pointCourant);
     
    // Calcul du nouveau point en fonction du sens dans un espace de tore
    Point p = exemple.espace.deplacer(pos.x,pos.y,sens.x,sens.y);
    if (exemple.grille.getMarque(p.x,p.y)!=0) return false;

    // Deplacement
    exemple.grille.setMarque(0,pos.x,pos.y);
    exemple.grille.setMarque(couleur,p.x,p.y);
    pos=p;

    return true;
  }
  
  // L'agent se deplace dans le sens oppose du point designe
  //
  private boolean fuirLePointDesigne()
  {
    // Si le point designe n'existe pas alors pas de deplacement
    if (exemple.pointCourant==null) return false;;
    
    // Si la distance entre l'agent et le point designe est > 10 alors
    //   l'agent ne fuit pas donc pas de deplacement
    double d = exemple.espace.distance(pos,exemple.pointCourant);
    if (d>10.0) return false;

    // Calcul du sens oppose au point designe
    Point sens = exemple.espace.sensTore(new Point(pos.x,pos.y),exemple.pointCourant);
    sens.x=-sens.x;
    sens.y=-sens.y;

    // Calcul du nouveau point en fonction du sens dans un espace de tore
    Point p = exemple.espace.deplacer(pos.x,pos.y,sens.x,sens.y);
    if (exemple.grille.getMarque(p.x,p.y)!=0) return false;

    // Deplacement
    exemple.grille.setMarque(0,pos.x,pos.y);
    exemple.grille.setMarque(couleur,p.x,p.y);
    pos=p;

    return true;
  }
  
  // L'agent se deplace ensemble c'est a dire qu'il se rapproche de l'agent
  //  le plus proche de lui et qui est a une distance de seuil de lui superieure au 1/3
  //  du nombre d'agent de son genre.
  //  Si ce 1/3 du nombre d'agent est superieur au 1/3 de la taille de la grille
  //  alors la distance de seuil est le 1/3 de la taille de la grille
  //
  private boolean deplacerEnsemble()
  {
    // On construit la liste des agents de meme couleur que l'agent
    Vector points = new Vector();
    for(Agent a:exemple.population)
      if (a.couleur==couleur) points.add(a.pos);

    // Calcul du point le plus proche
    Point pointProche = exemple.espace.lePlusProche(pos,points,
                                                 points.size()>exemple.grille.getNbX()/3?exemple.grille.getNbX()/3:points.size()/3);

    // S'il n'existe pas d'agent le plus proche alors pas de deplacement
    if (pointProche==null) return false;

    //Deplacement vers l'agent le plus proche

    Point sens = exemple.espace.sensTore(pos,pointProche);
    Point p = exemple.espace.deplacer(pos.x,pos.y,sens.x,sens.y);
    if (exemple.grille.getMarque(p.x,p.y)!=0) return false;

    exemple.grille.setMarque(0,pos.x,pos.y);
    exemple.grille.setMarque(couleur,p.x,p.y);
    pos=p;
    
    return true;
  }

  
}