package fr.cnam.espacetore;

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

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

// Classe qui crÃ©er un espace de tore qui contient une grille
//  dans laquelle les agents se deplacent
//
public class EspaceTore implements EspaceToreInt
{
  private ControleurJeu           controleurJeu;
  private ObservableEspace        observable;
  private CelluleGrille[][]       grille;
  private Tore                    tore;
  private Random                  rdm;

  // Constructeur
  public EspaceTore(ControleurJeu controleurJeu)
  {
    this.controleurJeu = controleurJeu;
    this.observable = new ObservableEspace();
    this.rdm = new Random();
  }

  public void init()
  {
    this.grille     = new CelluleGrille[controleurJeu.getNbX()][controleurJeu.getNbY()];
    this.tore       = new Tore(controleurJeu.getNbX(),controleurJeu.getNbY());
  }

  // Determine une case libre pour positionner l'agent quand il arrive
  //  dans la grille
  synchronized public Point arriver(AgentInt agent,int couleur)
  {
    if (agent==null)
      System.out.println("arriver> STUB NULL STUB NULL STUB NULL ");

    CelluleGrille c=null;
    while (c==null)
      {
        int i = Math.abs(rdm.nextInt())%controleurJeu.getNbX();
        int j = Math.abs(rdm.nextInt())%controleurJeu.getNbY();
        
        c = grille[i][j];
        if (c==null)
          {
            grille[i][j] = new CelluleGrille(couleur,agent);
            try{agent.setNbVie(10);}
            catch(Exception ex){System.out.println("Impossible acceder agent");}
            if (observable.countObservers()!=0)
              {
                try{
                  observable.setChanged();
                  observable.notifyObservers(""+i+" "+j+" "+couleur);
                }catch(Exception ex){System.out.println("** EspaceTore.arriver> Pb de notification "+ex);}
              }
            return( new Point(i,j));
            }
      }
    return(null);
  }

  // Supprime tous les agents
  synchronized public void supprimerTousAgents()
  {
    for(int i=0;i<controleurJeu.getNbX();i++)
      for(int j=0;j<controleurJeu.getNbY();j++)
        {
          CelluleGrille c = grille[i][j];
          if (c!=null)
            {
              grille[i][j]=null;
              try{c.agent.setNbVie(0);}
              catch(Exception ex){System.out.println("Impossible acceder agent");}
              if (observable.countObservers()!=0)
                {
                  try{
                    observable.setChanged();
                    observable.notifyObservers(""+i+" "+j+" "+"0");
                  }catch(Exception ex){System.out.println("** EspaceTore.arriver> Pb de notification "+ex);}
                }
            }
        }
  }

  // Methode utilisee par un agent pour se deplacer
  //
  public Point deplacer(int x,int y,int sensX,int sensY,int couleur)
  {
    try{
      Point p = deplacerSynchro(x,y,sensX,sensY,couleur);
      Thread.sleep(getTempo());
      return p;
    }catch(Exception ex)
      {
        System.out.println("Erreur>deplacer: "+ex);
        return null;
      }
  }
  // Methode pour realiser un deplacement synchronise
  //
  synchronized public Point deplacerSynchro(int x,int y,int sensX,int sensY,int couleur)
  {
    // Cellule de la grille
    CelluleGrille cell = grille[x][y];
        
    if (cell.agent == null) 
      {
        System.out.println("deplacer> case null. Pas normal");
        return null;
      }

    // Si l'agent n'a plus de vie alors il ne peut pas se déplacer (il est mort)
    try{
      if (cell.agent.getNbVie()<=0) return null;
    }catch(Exception ex){System.out.println("deplacer>Pb communication agent");}

    // Calcul de la case de destination en fonction du sens de deplacement
    Point p = tore.deplacer(x,y,sensX,sensY);

    // Si la case de destination est libre
    if (grille[(int)p.x][(int)p.y]==null)
      {
        // La case est libre : l'agent s'y dÃ©place
        CelluleGrille c = grille[x][y];
        grille[x][y] = null;
        grille[(int)p.x][(int)p.y] = c;

        // Notification du deplacement
        if (observable.countObservers()!=0)
          {
            try{
              System.out.println(String.format("Notification : %3d %3d %3d",x,y,0));
              observable.setChanged();
              observable.notifyObservers(""+x+" "+y+" "+"0");
              observable.setChanged();
              observable.notifyObservers(""+p.x+" "+p.y+" "+couleur);
            }catch(Exception ex){System.out.println("** EspaceTore.deplacer> Pb de notification "+ex);}
          }
      }
    else
      {
        if (controleurJeu.getModeCombat()) // Mode combat
          {
            // La case de deplacement est occupee
            try{
              CelluleGrille c = grille[(int)p.x][(int)p.y];
              if (c.couleur!=couleur)
                {
                  // par un ennemi
                                    
                  // On decremente le nbre de vie de l'ennemi
                  //  La methode setNbVie arrete le thread si 0
                  //
                  c.agent.setNbVie(c.agent.getNbVie()-1);
                                    
                  // Si son nbre de vie est 0 alors on notifie
                  //   que le case est vide car l'agent est mort
                  if (c.agent.getNbVie()==0)
                    {
                      grille[(int)p.x][(int)p.y]=null;
                      if (observable.countObservers()!=0)
                        {
                          observable.setChanged();
                          observable.notifyObservers(""+p.x+" "+p.y+" "+"0");
                        }
                    }
                }
            }catch(Exception ex){System.out.println("Impossible acceder agent"+ex);
              ex.printStackTrace();}
          }
        p=null;
      }

    return p;
  }

  public boolean getModeCombat(){return controleurJeu.getModeCombat();}

  public int getTempo(){return controleurJeu.getTempo();}

  public ObservableEspace getObservable()
  {
    return observable;
  }

  public int getNbX()
  {
    return controleurJeu.getNbX();
  }
  public int getNbY()
  {
    return controleurJeu.getNbY();
  }
  public int getTailleCellule()
  {
    return controleurJeu.getTailleCase();
  }

  synchronized public Vector getPopulation(int couleur)
  {
    Vector elements = new Vector();
        
    for(int i=0;i<controleurJeu.getNbX();i++)
      {
        for(int j=0;j<controleurJeu.getNbY();j++)
          {
            CelluleGrille c = grille[i][j];
            if (c!=null)
              {
                if( c.couleur == couleur)
                  {
                    elements.addElement((Object)(new Point(i,j)));
                  }
              }
          }
      }
    return (elements);
  }

  synchronized public CelluleGrille[][] getGrille()
  {
    return grille;
  }

  public Vector getAutrePopulation(int couleur)
  {
    Vector elements = new Vector();
        
    for(int i=0;i<controleurJeu.getNbX();i++)
      {
        for(int j=0;j<controleurJeu.getNbY();j++)
          {
            CelluleGrille c = grille[i][j];
            if (c!=null)
              {
                if( c.couleur != couleur)
                  {
                    elements.addElement((Object)(new Point(i,j)));
                  }
              }
          }
      }
    return (elements);
  }

  public void submit(Formulaire form, String nomSubmit)
  {
    try{
      if (nomSubmit.equals("VALIDER"))
        {
          //inutile car fenetre synchrone.
        }
    }catch(Exception ex){}
  }

}

