import javax.swing.*;



import java.awt.*;
import java.awt.event.*;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
/**
 *
 * Projet :PaintRevolution
 * <p>Title:DessinFigures.java </p>
 * <p>Description:
 * Classe héritant de JPanel qui permet de visualiser et contenir toutes les figures
 * que l'utilisateur souhaitera créer et manipuler. Elle dispose d'une classe interne
 * permettant de réaliser les actions prévues à cet effet.
 *  </p>
 * <p>Copyright: Copyright (c) 2005</p>
 * <p>Societe:IUT NANCY CHARLEMAGNE II </p>
 * @author VIGNERON GEOFFROY && GANGANELLI DORIAN
 * @version 3.0
 */
public class DessinFigures extends JPanel{
    
    /**
     * Tableau qui contient les figures créées par l'utilisateur et manipulable à l'écran
     */
    protected FigureColoree[] figures;
    
    /**
     * Nombre de figures effectivement créées par l'utilisateur.
     */
    protected int nbf;
    
    /**
     * Indice qui permet de savoir quelle figure est sélectionnée par l'utilisateur
     * Vaut -1 si aucune figure n'est sélectionnée.
     */
    protected int sel;
    
    /**
     * Curseur de la souris
     */
    private Cursor cur ;
    
    
    
    /**
     * Constructeur principal de la classe DessinFigures qui instancie un Panel
     * et un tableau vide pouvant contenir des figures
     */
    public DessinFigures(){
        this.figures = new FigureColoree[1000];
        this.nbf = 0;
        this.sel = -1;
    }
    
    
    /**
     * Méthode qui permet de rajouter une figure et de la visualiser à l'écran
     * @param f figure créée par l'utilisateur
     */
    public void ajoute(FigureColoree f){
        for (int i=0;i<nbf;i++)
            this.figures[i].deselectionne();
        
        if (f != null ){
            this.figures[this.nbf] = f;
            if (sel != -1) this.figures[this.sel].deselectionne();
            this.sel = this.nbf;
            f.selectionne();
            this.nbf++;
        }
        repaint();
    }
    
    /**
     * Méthode permettant de changer de curseur entre la barre de menu
     * et le panel dessinable
     * @param img l'image du curseur
     * @param p les coordonnées d'un point
     * @param s une chaine
     */
    public void  setCursorFeuilles(Image img, Point p,  String s) {
        Toolkit toolkit = getToolkit();
        int colors = toolkit.getMaximumCursorColors();
        Dimension d = toolkit.getBestCursorSize(10, 10);
        cur = toolkit.createCustomCursor(img, p, s);
        this.setCursor(cur);
        
    }
    
    /**
     * Permet de changer le curseur
     * (souvent pour remettre le curseur à défault)
     * @param c le curseur choisie
     */
    public void changeCursor(Cursor c){
        this.setCursor(c);
    }
    
    /**
     * Méthode qui retourne le nombre de figures créées
     * @return un entier
     */
    public int nbFigures() {
        return this.nbf ;
    }
    
    
    /**
     * Méthode qui permet de récupérer la figure, si celle-ci est sélectionnée,
     * parmis celles disponibles dans le tableau
     * @return la figure effectivement sélectionnée, sinon null
     */
    public FigureColoree figureSelection(){
        if (this.sel != -1)
            return this.figures[sel] ;
        else
            return null;
    }
    
    /**
     * Méthode qui permet de sélectionner à tour de rôle chaque figure visualisable à l'écran
     */
    public void selectionProchaineFigure(){
        if (this.sel!=-1){
            this.figures[this.sel].deselectionne();
            this.sel++;
            if (this.sel==this.nbf) this.sel = 0;
            this.figures[this.sel].selectionne();
            this.repaint();
        }
        else{
            this.figures[0].selectionne();
            this.sel = 0;
        }
    }
    
    
    /**
     * Redéfinition de la méthode appelée par le systeme lorsqu'un élément graphique
     * doit être redessiné ou quand la figure ou la fenetre principale est rafraichie
     * @param g environnement graphique associé
     */
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        for (int i=0; i<this.nbf; i++)
            figures[i].affiche(g);
    }
    
    
    /**
     * Méthode utilisé lorsque l'utilisateur souhaite dessiner à main levée avec la souris.
     * @param c couleur sélectionnée pour effectuer le tracé.
     */
    public void trace (Color c){
        Graphics g=this.getGraphics();
        TraceurForme tr = new TraceurForme(g);
        g.setColor(c);
        this.addMouseListener(tr);
        this.addMouseMotionListener(tr);
    }
    
    
    /**
     * Méthode mettant en oeuvre un auditeur lorsque l'utilisateur souhaite faire des
     * manipulations sur la figure
     */
    public void activeManupulationSouris(int manipulation) {
        ManipulateurForme manip=new ManipulateurForme(manipulation);
        this.addMouseListener(manip);
        this.addMouseMotionListener(manip);
    }
    
    /**
     * Méthode qui permet de supprimer tous les auditeurs associés aux autres objets
     */
    public void removeListeners() {
        MouseListener[] mlist = (MouseListener[])(this.getListeners(MouseListener.class));
        for(int i=0;i<mlist.length;i++) {
            this.removeMouseListener(mlist[i]);
        }
        MouseMotionListener[] mmlist = (MouseMotionListener[])(this.getListeners(MouseMotionListener.class));
        for(int i=0;i<mmlist.length;i++) {
            this.removeMouseMotionListener(mmlist[i]);
        }
    }
    
    
    /**
     * Méthode qui permet de charger dans un tableau des figures préalablement sauvegardées
     * dans un fichier. Les éventuelles figures courantes seront supprimées et remplacées.
     * @param fig tableau de figures à charger
     */
    public void chargerFigureSauvegardee ( FigureColoree[] fig ) {
        this.nbf = fig.length;
        int total = 0;
        for (int i=0;i<this.nbf;i++){
            if (fig[i] != null){
                total++;
                this.figures[i] = fig[i];
            }else break;
        }
        this.nbf = total;
        this.repaint();
    }
    
    /**
     * Methode qui permet à l'utilisateur de supprimer une figure si celle-ci est selectionnée.
     */
    public void supprime(){
        for (int i= this.sel ; i < this.nbf; i++){
            this.figures[i] = this.figures[i + 1];
        }
        this.nbf--;
        this.sel= -1;
    }
    
    
    /**
     * Projet: PaintRevolution
     * <p>Title:Manipulateur forme</p>
     * <p>Description: 
     * Classe interne qui permet de traduire les actions de l'utilisateur sur une figure
     * Auditeur qui implément des auditeurs associés à la souris</p>
     * <p>Copyright: Copyright (c) 2004</p>
     * <p>Societe: IUT NANCY CHARLEMAGNE II</p>
     * @author VIGNERON GEOFFROY && GANGANELLI DORIAN
     * @version 3.0
     */
    public class ManipulateurForme implements MouseListener,MouseMotionListener {
        
        /**
         * Réprésente la dernière abscisse du point mémorisé par un clic de souris
         */
        private int lastX;
        
        /**
         * Réprésente la dernière ordonnée du point mémorisé par un clic de souris
         */
        private int lastY;
        
        /**
         * Reperesnte le choix d'une manipulation
         */
        private int manip;
        
        /**
         * Constructeur de la classe permettant les manipulations
         * @param choixManipulation un entier représentant: 
         *        1-translation 2-redimensionnement 3-selection
         */
        public ManipulateurForme(int choixManipulation){
            manip=choixManipulation;
        }
        public void mouseEntered(MouseEvent e) { }
        public void mouseExited(MouseEvent e)  { }
        public void mouseReleased(MouseEvent e){ }
        public void mouseMoved(MouseEvent e)   { }
        public void mouseClicked(MouseEvent e) { }
        
        /**
         * Méthode qui traduit l'action de la souris lorsqu'un bouton est pressé et mémorise
         * les coordonnées du click de la souris s'il s'agit d'un click gauche
         * @param e Evènement détecté par l'auditeur
         */
        public void mousePressed(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                lastX = e.getX();
                lastY = e.getY();
                if (sel != -1) {
                    FigureColoree f = figures[sel];
                    f.deselectionne();
                    sel = -1;
                }
                for (int i = 0; i < nbf; i++) {
                    FigureColoree fc =  figures[i];
                    if (fc.contient(e.getX(), e.getY())) {
                        fc.selectionne();
                        sel = i;
                        break;
                    }
                }
                repaint();
            }
        }
        
        /**
         * Méthode qui traduit l'action de la souris lorsque celle-ci se déplace avec un bouton enfoncé
         * @param e Evènement détecté par l'auditeur
         */
        public void mouseDragged(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                if (sel != -1 && (manip>0||manip<3) ){
                    FigureColoree f =figures[sel];
                    int indicePoint=0;
                    UnRectangle r = null;
                    for (int i = 0; i < f.tab_mem.length; i++) {
                        indicePoint = i;
                        r = new UnRectangle(f.tab_mem[i]);
                        if (!r.contient(e.getX(), e.getY())) r = null;
                        else break;
                    }
                    if (manip==1){//translation
                        f.translation(e.getX() - lastX, e.getY() - lastY);
                        f.selectionne();
                        repaint();
                        lastX = e.getX();
                        lastY = e.getY();
                    }
                    if (manip==2){//redimensionnement
                        if ((r != null && r.contient(e.getX(), e.getY() ))){
                            if (f instanceof UnRectangle){
                                // pour le rectangle : 2 déplacement à gérer suivant le point de mémorisation sélectionné
                                if ((indicePoint==0 )){
                                    f.tab_mem[indicePoint].translation(e.getX() - lastX, e.getY() - lastY);
                                    f.tab_mem[3].translation(e.getX() - lastX , 0);
                                    f.tab_mem[1].translation(0 , e.getY() - lastY);
                                }else if ((indicePoint==2 )){
                                    f.tab_mem[indicePoint].translation(e.getX() - lastX, e.getY() - lastY);
                                    f.tab_mem[3].translation( 0 , e.getY() - lastY);
                                    f.tab_mem[1].translation( e.getX() - lastX , 0);
                                }
                                lastX = e.getX();
                                lastY = e.getY();
                                repaint();
                            }else{
                                f.tab_mem[indicePoint].translation(e.getX() - lastX, e.getY() - lastY);
                                lastX = e.getX();
                                lastY = e.getY();
                                repaint();
                            }
                            
                        }
                    }
                }
            }
            
        }// fin void mouseDragged(...);
    }//*************** fin classe interne ManipulateurForme ************************
}
