package fr.cnam.grille;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import fr.cnam.tore.*;

/**
   Classe de définition d'une grille IHM avec laquelle il est possible :<br>
   - de colorer ou effacer une case de la grille<br>
   - de realiser une action sur chacun des 10 boutons qui se trouvent à cote de la grille<br>
   - de nommer les boutons<br>
   
*/
public class GrilleIHM
{
    private final static int    MAX_CONTROLES = 10;
    private final static int    NB_MAX_MARQUE = 10;

    private Panel              _panel;
    private Canvas             _canvas;
    private Button             _controles[];
    private GrilleControlesInt _anyActions;
    private int                _nbX;
    private int                _nbY;
    private int                _tailleCase;
    private int                _grille[][];
    private int                _width;
    private int                _height;
    private Color[]            _couleurs;

  
    // ======================================================================
    /** Constructeur de la grille.<br>
        L'objet créé doit ensuite être insérer dans une objet swing comme par exemple un Frame d'une fenêtre principale.<br>
        La méthode getPanel() retourne le Panel de la GrilleIHM.<br>
        @param nbX nombre colonne de la grille
        @param nbY nombre de ligne de la grille
        @param tailleCase la taille en pixel des cases de la grille
    */
    public GrilleIHM(int nbX,
                     int nbY,
                     int tailleCase) 
    {
        // Creation du panel principal
        _panel = new Panel();

        // Caractéristiques de la grille
        _tailleCase  = tailleCase;
        _nbX         = nbX;
        _nbY         = nbY;
        _width       = _nbX * _tailleCase;
        _height      = _nbY * _tailleCase;
        _couleurs    = new Color[NB_MAX_MARQUE];
        _couleurs[0] = Color.black;
        _couleurs[1] = Color.red;
        _couleurs[2] = Color.green;
        _couleurs[3] = Color.blue;
        _couleurs[4] = Color.gray;
        _couleurs[5] = Color.magenta;
        _couleurs[6] = Color.orange;
        _couleurs[7] = Color.yellow;
        _couleurs[8] = Color.cyan;
        _couleurs[9] = Color.pink;

        // Creation du canvas
        _canvas = new GrilleCanvas(this);
        _canvas.resize(_width+5,_height+5);

        // Initialisation du tableau de la grille
        _grille = new int[_nbX][_nbY];
        razGrille();

        // Initialisation des boutons d'actions
        _anyActions = null;
        _controles = new Button[MAX_CONTROLES];

        // Creation du panel des zones de saisie et des boutons
        Panel controle = new Panel(new GridLayout(MAX_CONTROLES,1));
        for(int i=0;i<MAX_CONTROLES;i++)
            {
                int num = i+1;
                _controles[i] = new Button("Action "+num);
                _controles[i].setSize(100,20);
                _controles[i].addActionListener( new ControleAction(num,this));
                controle.add(_controles[i]);
                _controles[i].setLabel("Bouton " + i);
            }

        // On ajoute les 2 éléments dans l'IHM
        // 
        _panel.add(controle);
        _panel.add(_canvas);
    }

    // ======================================================================
    /**
       Initialise l'acteur qui est un objet qui implémente l'interface  GrilleControlesInt
     */
    public void setActeur(GrilleControlesInt acteur)
    {
        _anyActions = acteur;
    }
  
    // ======================================================================
    /**
       Retourne le panel contenant la GrilleIHM
       @return le panel
     */
    public Panel getPanel()
    {
        return(_panel);
    }

    // ======================================================================
    /** Efface le contenu de la grille<br>
        (La valeur 0 est mise dans chaque case)
     */
    public void razGrille()
    {
        for(int i=0;i<_nbX;i++)
            {
                for(int j=0;j<_nbY;j++)
                    {
                        _grille[i][j]=0;
                    }
            }
    }

    // ======================================================================
    /** Affecte à une case de la grille la marque (couleur)
        @param marque une valeur de 1 à 10 (couleur) ou 0 (case vide)
        @param x coordonnée en x de la case
        @param y coordonnée en y de la case
     */
    public void setMarque(int marque,int x,int y)
    {
        _grille[x][y] = marque;
        marquer(marque,x,y);
    }
  
    // ======================================================================
    /** Retourne la marque de la case
       @param x coordonnée en x de la case
       @param y coordonnée en y de la case
       @return la valeur de la case (de 0 à 10)
     */
    public int getMarque(int x,int y)
    {
        return(_grille[x][y]);
    }
  
    // ======================================================================
    /** Teste si la case est libre (différente de 0)
        @param x coordonnée en x de la case
        @param y coordonnée en y de la case
        @return true si la case est libre sinon false
    */
    public boolean siCaseLibre(int x,int y)
    {
        return( getMarque(x,y)==0 );
    }
  
    // ======================================================================
    /** Retourne le nombre de colonne de la grille
        @return le nombre de colonne
    */
    public int getNbX()
    {
        return(_nbX);
    }
  
    // ======================================================================
    /** Retourne le nombre de ligne de la grille
        @return le nombre de ligne
    */
    public int getNbY()
    {
        return(_nbY);
    }

    // ======================================================================
    /** Retourne le nombre max de couleur géré par GrilleIHM
        @return nombre max
    */
    public int getNbMaxMarqueur()
    {
        return(NB_MAX_MARQUE);
    }  
    // ======================================================================
    /** Permet de changer le nom d'un bouton de l'IHM.
        @param num numéro du bouton (de 1 à 10)
        @param nom du bouton
    */
    public void setNomBouton(int num,String nom)
    {
        _controles[num-1].setLabel(nom);
    }

    // ======================================================================
    // Affichage de la grille
    //
    private void afficherGrille()
    {
        Graphics g = _canvas.getGraphics();

        // On efface toute la grille
        g.clearRect(0,0,_width,_height);

        // Tracer des lignes verticales
        for(int i=0;i<_nbX+1;i++)
            {
                Point p1= new Point( (_width/_nbX)*i,0);
                Point p2= new Point( (_width/_nbX)*i,_height);
                g.drawLine(p1.x,p1.y,p2.x,p2.y);
            }

        // Tracer des lignes horizontales
        for(int i=0;i<_nbY+1;i++)
            {
                Point p1= new Point( 0,      (_height/_nbY)*i);
                Point p2= new Point( _width, (_height/_nbY)*i);
                g.drawLine(p1.x,p1.y,p2.x,p2.y);
            }

        // Tracer des éléments
        for(int i=0;i<_nbX;i++)
            {
                for(int j=0;j<_nbY;j++)
                    {
                        marquer(_grille[i][j],i,j);
                    }
            }
    }

    // ======================================================================
    // Tracer d'un élément dans la grille
    //
    private void marquer(int marque,int x,int y)
    {
        Graphics g = _canvas.getGraphics();
        int niX1 = x*(_width/_nbX);
        int niX2 = (x+1)*(_width/_nbX);
        int niY1 = y*(_height/_nbY);
        int niY2 = (y+1)*(_height/_nbY);

        g.clearRect(niX1+1,niY1+1,niX2-niX1-2,niY2-niY1-2);
        if (marque >0)
            {
                g.setColor(_couleurs[marque-1]);
                g.fillRect(niX1+2,niY1+2,niX2-niX1-4,niY2-niY1-4);
            }
    }

    // ======================================================================
    /** Méthode de test de la classe.
        Ce programme crée une grille et crée un thread qui déplace une case.
        Les boutons permettent de tester le comportement du déplacement
    */
    public static void main(String... args)
    {
        int nbX=20;
        int nbY=30;

        // On crée la fenêtre
        Frame fen = new Frame();
        

        // On y ajoute la grille
        GrilleIHM grilleihm = new GrilleIHM(nbX,nbY,15);

        // Exemple qui teste la grille
        Test t = new Test(grilleihm);
        grilleihm.setActeur(t);
        
        // Panel in Frame
        fen.add(grilleihm.getPanel());

        // Pour fermer la fenetre
        GrilleWindowAdapter a = new GrilleWindowAdapter();
        fen.addWindowListener((WindowListener)a);
        
        // On affiche la fenetre
        fen.setLocation(100,100);
        fen.setSize(300+nbX*15,250+nbY*15);
        fen.show();
        
        // Démarrage du test
        t.start();
    }



    // ===============================================================
    // Inner classe interne de definition du callback sur les boutons
    // ===============================================================
    // Pour récupérer les actions de click sur les boutons
    class ControleAction implements ActionListener
    {
        int _type; // numero bouton
        GrilleIHM _grille; // La grille IHM

        // Constructeur afin de designer le type d'action
        public ControleAction(int type, GrilleIHM grille)
        {
            _type=type;
            _grille=grille;
        }

        // Traitement des actions
        public void actionPerformed(ActionEvent e)
        {
            if (_anyActions!=null)
                {
                    _anyActions.action(_type,_grille);
                }
        }
    }



    // ===============================================================
    // Classe interne de definition de la surcharge de paint du canvas
    // ===============================================================
    class GrilleCanvas extends Canvas
    {
        GrilleIHM _g;
        
        public GrilleCanvas(GrilleIHM g)
        {
            _g = g;
        }

        public void paint(Graphics g)
        {
            _g.afficherGrille();
        }
    }

} // Fin de GrilleIHM


// ===============================================================
// Classe interne de fermeture de la fenetre
// ===============================================================
// L'adaptateur d'une window
//
class GrilleWindowAdapter extends WindowAdapter
{
    // On ne s'interesse que a l'action de fermeture de
    // la fenetre
    public void windowClosing(WindowEvent e) 
    {
        System.exit(0);
    }
}

// ===============================================================
/** Classe utilisée pour tester la classe Tore et la grille
 */
class Test extends Thread implements GrilleControlesInt
{
    private GrilleIHM grille;
    private int mode;

    public Test(GrilleIHM g)
    {
        grille = g;
        mode=1;
    }

    public void run()
    {
        Random  rdm = new Random();
        Tore espace = new Tore(grille.getNbX(),grille.getNbY());

        // 
        grille.setNomBouton(1,"Dep aleat");
        grille.setNomBouton(2,"Pos aleat");
        grille.setNomBouton(3,"Vers le coin\n (0,0)");
        
        //
        int x=grille.getNbX()/2;
        int y=grille.getNbY()/2;
        grille.setMarque(1,x,y);
        while(true)
            {
                if (mode==1)
                    {
                        int sensX = rdm.nextInt(3)-1;
                        int sensY = rdm.nextInt(3)-1;
                        Point p = espace.deplacer(x,y,sensX,sensY);
                        grille.setMarque(0,x,y);
                        x = (int)p.x;
                        y = (int)p.y;
                        grille.setMarque(1,x,y);
                    }

                if (mode==2)
                    {
                        grille.setMarque(0,x,y);
                        x = rdm.nextInt(grille.getNbX());
                        y = rdm.nextInt(grille.getNbY());
                        grille.setMarque(1,x,y);
                        try{Thread.sleep(1000);}catch(Exception ex){};
                    }

                if (mode==3)
                    {
                        Point sens = espace.sensTore(new Point(x,y),new Point(0,0));
                        Point p = espace.deplacer(x,y,sens.x,sens.y);
                        grille.setMarque(0,x,y);
                        x = (int)p.x;
                        y = (int)p.y;
                        grille.setMarque(1,x,y);
                    }
                
                try{Thread.sleep(200);}catch(Exception ex){};
            }
    }

    public void action(int num,GrilleIHM grille)
    {
        mode = num;
    }

}

    