package fr.cnam.joueur;

import java.util.*;
import java.awt.Point;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;

import fr.cnam.espacetore.*;
import fr.cnam.tore.*;

public abstract class Agent extends UnicastRemoteObject implements AgentInt, Runnable
{
    private static int count = 0;
    protected int numero;
    protected FactoryAgentInt factory;
    protected int x;
    protected int y;
    protected int couleur;
    protected boolean stopThread;
    protected int tempo;
    protected Thread thread;
    protected Random rdm;
    protected EspaceToreODInt espace;
    protected int nbX;
    protected int nbY;
    protected Tore tore;
    protected int nbVie;
    

    public Agent(int couleur,
                 FactoryAgentInt factory,
                 int portRMI
                 ) throws RemoteException
    {
        super(portRMI);
        try{
            this.factory = factory;
            this.espace = factory.getEspaceTore();
            this.stopThread = false;
            this.tempo = espace.getTempo();
            this.nbX = espace.getNbX();
            this.nbY = espace.getNbY();
            this.nbVie = 10;
            AgentInt stub = (AgentInt)(UnicastRemoteObject.toStub(this));
            Point p = espace.arriver(stub,couleur);
            this.x=(int)p.x;
            this.y=(int)p.y;

            this.couleur = couleur;
            this.numero=count++;
            this.rdm = new Random();
            this.tore = new Tore(this.nbX,this.nbY);
            
            this.thread = new Thread(this);
            this.thread.start(); 
        }catch(Exception ex){System.out.println("Erreur init agent");}
    }

    public void run()
    {
        while(! stopThread)
          deplacer();
        System.out.println("Arret du thred");
    }

    // Deplacement aleatoire
    //
    public void deplacer()
    {
        try{
            int sensX = Math.abs(rdm.nextInt())%3 - 1;
            int sensY = Math.abs(rdm.nextInt())%3 - 1;
            //System.out.println("x,y = "+x+","+y+" sens: "+sensX+" "+sensY);
            // Deplacement dans la grille
            Point p = espace.deplacer(x,y,sensX,sensY,couleur);
            if (p != null)
                {
                    // Le deplacement est possible
                    x = (int)p.x;
                    y = (int)p.y;
                    //System.out.println("Agent "+numero+"> deplacer en "+x+" "+y);
                }
        }
        catch(Exception ex){System.out.println("Erreur deplacer");}
    }

    // Methode permettant de deplacer l'agent de telle maniere qu'il se
    // dirige vers un agent de meme marque que lui.
    // Cette methode retourne false si le deplacement n'est pas possible
    // Le principe : 
    //    on determine le plus proche superieur à un certain seuil
    //    
    public boolean deplacerEnsemble(int seuil)
    {
        try{
        int sensX;
        int sensY;
        Point p;
        Vector points;
        
        // Determination des positions de tous les agents de meme marque
        //  qui evoluent dans la grille
        //
        points = null;

        points = this.espace.getPopulation(this.couleur);
        
        // Si il n'y en a pas alors retourne false
        if (points != null)
            {
                // On determine le plus proche superieur a un seuil 
                Point pointProche = this.tore.lePlusProche(new Point(x,y),points,seuil);
                
                // Si il n'y en a pas alors retourne false
                if (pointProche != null)
                    {
                        // Determination du sens de deplacement
                        //
                        Point sens = this.tore.sens(new Point(x,y),pointProche);
                        sensX = (int)(sens.x);
                        sensY = (int)(sens.y);
                        //System.out.println("sens "+numero+": "+sensX+" "+sensY);
                        // Realisation du deplacement
                        //
                        p = espace.deplacer(x,y,sensX,sensY,couleur);
                        if (p!=null) 
                            {
                                x = (int)p.getX();
                                y = (int)p.getY();
                                //System.out.println("Agent "+numero+"> deplacer ensemble en "+x+" "+y);
                                return(true);
                            }
                    }
            }
        return(false);
        }
        catch(Exception ex){return false;}
    }
    
    // Methode permettant de deplacer l'agent de telle maniere qu'il se
    // dirige vers un agent de meme marque que lui.
    // Cette methode retourne true si le deplacement a ete possible
    // Le principe : 
    //    on determine le plus proche inferieur à un certain seuil et 
    //    si le nombre d'agent troube est inferieur a un certain seuil
    //    
    // Methode permettant de deplacer l'agent de telle maniere qu'il se
    // dirige vers un agent de marque differente de lui.
    // Cette methode retourne false si le deplacement n'est pas possible
    // Le principe : 
    //    on determine le plus proche
    //    
    // Ce deplacement est agressif car l'agent attaque tout le temps
    //  tout ennemi proche
    //
    public boolean deplacerEnnemie()
    {
        try{
        int sensX;
        int sensY;
        Point p;
        Vector points;
        
        // Determination des positions de tous les agents pas de meme marque
        //  qui evoluent dans la grille
        //
        points = null;

        points = this.espace.getAutrePopulation(this.couleur);
        
        // Si il n'y en a pas alors retourne false
        if (points != null)
            {
                // On determine le plus proche (seuil = 0)
                Point pointProche = this.tore.lePlusProche(new Point(x,y),points,0);
                
                // Si il n'y en a pas alors retourne false
                if (pointProche != null)
                    {
                        // Determination du sens de deplacement
                        //
                        Point sens = this.tore.sens(new Point(x,y),pointProche);
                        sensX = (int)(sens.x);
                        sensY = (int)(sens.y);
                        
                        // Realisation du deplacement
                        //
                        p = espace.deplacer(x,y,sensX,sensY,couleur);
                        if (p!=null) 
                            {
                                x = (int)p.getX();
                                y = (int)p.getY();
                                //System.out.println("Agent> deplacer en "+x+" "+y);
                                return(true);
                            }
                    }
            }
        return(false);
        }catch(Exception ex){return false;}
    }
    
    // Les agents partent a l'oppose des agents ennemies
    //
    public boolean fuireEnnemie()
    {
        try{
        int sensX;
        int sensY;
        Point p;
        Vector points;
        
        // Determination des positions de tous les agents pas de meme marque
        //  qui evoluent dans la grille
        //
        points = null;

        points = this.espace.getAutrePopulation(this.couleur);
        
        // Si il n'y en a pas alors retourne false
        if (points != null)
            {
                // On determine le plus proche (seuil = 0)
                Point pointProche = this.tore.lePlusProche(new Point(x,y),points,0);
                
                // Si il n'y en a pas alors retourne false
                if (pointProche != null)
                    {
                        // Determination du sens de deplacement
                        //
                        Point sens = this.tore.sens(new Point(x,y),pointProche);
                        sensX = -(int)(sens.x);
                        sensY = -(int)(sens.y);
                        
                        // Realisation du deplacement
                        //
                        p = espace.deplacer(x,y,sensX,sensY,couleur);
                        if (p!=null) 
                            {
                                x = (int)p.getX();
                                y = (int)p.getY();
                                //System.out.println("Agent> deplacer en "+x+" "+y);
                                return(true);
                            }
                    }
            }
        return(false);
        }catch(Exception ex){return false;}
    }

    // Les agents partent a l'oppose de ses propres agents
    //
    public boolean fuireAmis()
    {
        try{
        int sensX;
        int sensY;
        Point p;
        Vector points;
        
        // Determination des positions de tous les agents de meme marque
        //  qui evoluent dans la grille
        //
        points = null;

        points = this.espace.getPopulation(this.couleur);
        
        // Si il n'y en a pas alors retourne false
        if (points != null)
            {
                // On determine le plus proche (seuil = 0)
                Point pointProche = this.tore.lePlusProche(new Point(x,y),points,0);
                
                // Si il n'y en a pas alors retourne false
                if (pointProche != null)
                    {
                        // Determination du sens de deplacement
                        //
                        Point sens = this.tore.sens(new Point(x,y),pointProche);
                        sensX = -(int)(sens.x);
                        sensY = -(int)(sens.y);
                        
                        // Realisation du deplacement
                        //
                        p = espace.deplacer(x,y,sensX,sensY,couleur);
                        if (p!=null) 
                            {
                                x = (int)p.getX();
                                y = (int)p.getY();
                                //System.out.println("Agent> deplacer en "+x+" "+y);
                                return(true);
                            }
                    }
            }
        return(false);
        }catch(Exception ex){return false;}
    }

   
    public int getNbVie() throws RemoteException
    {
        return nbVie;
    }
    
    public void setNbVie(int nbVie) throws RemoteException
    {
        this.nbVie = nbVie;
        if (nbVie<=0)
            {
                stopThread=true;
            }
    }
    
}