import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;

// Canvas HardWare avec doublebuffering et antialiasing, herite de Canvas
class HWCanvas extends Canvas implements MouseMotionListener, MouseListener, KeyListener {
	// Serializable
	private static final long serialVersionUID = 1L;

	// Graphique de dessin
	protected Graphics2D g;

	// BufferStrategy pour afficher le doublebuffering
	protected BufferStrategy strategy; 
	 
	// Constructeur
	public HWCanvas(){
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		this.addKeyListener(this);
	}
	
	// Initialisation avec largeur et hauteur
	public void Initialize(int w, int h){
		if(isDisposed) return;
		setSize(w, h);
		setVisible( true );
		createBufferStrategy( 2 ); // Nombre de buffer (DoubleBuffering donc 2)
		// Recuperation du buffer strategy du Canvas
		strategy = getBufferStrategy();
		// Recuperation du graphique pour dessiner
		g = (Graphics2D) strategy.getDrawGraphics();
		// Activation de l'anti-aliasing
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	}
	public void paint(Graphics g){
		redraw();
	}
	   
	public void redraw(){ redraw(true); }
	public void redraw(boolean refresh){
		if(isDisposed) return;
		if(g==null) return;
		// On efface la zone de dessin
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, this.getWidth(), this.getHeight());
		try{
			// On demande a tous les clips de se redessiner
			for(Clip draw : clips)
				draw.repaint(g);
		}catch(Exception e){}
		// On remet la couleur a white
		g.setColor(Color.WHITE);
		// Si voulu, on reaffiche le buffer a l'ecran
		if(refresh) refresh();
	}
	
	// Affichage du buffer a l'ecran
	public void refresh(){
	   if(isDisposed) return;
	   try{strategy.show();}catch(Exception e){}
	}
	
	// Gestion de la destruction
	protected boolean isDisposed = false;
	public boolean isDisposed(){ return isDisposed; }
	public void finalize(){ Dispose(); }
	public void Dispose(){
		if(isDisposed) return;
		isDisposed = true;
		this.removeMouseMotionListener(this);
		this.removeMouseMotionListener(this);
		this.removeKeyListener(this);
		clips.clear();
		g = null;
	}
	
	
	// Liste des clips du canvas
    protected final ArrayList<Clip> clips = new ArrayList<Clip>();
    
    // Ajout d'un clip
    public void addClip(Clip draw) {
    	if(isDisposed) return;
		clips.add(draw);
		redraw(); // On redessine
	}

    // Suppression d'un clip
	public void removeClip(Clip draw) {
		if(isDisposed) return;
		clips.remove(draw);
		redraw();
	}

	// Evenements de clavier/souris (pour eviter de les remettre tous dans les classes heritees)
	public void keyPressed(KeyEvent ke) {}
	public void keyReleased(KeyEvent ke) {}
	public void keyTyped(KeyEvent ke) {}
	public void mouseClicked(MouseEvent me) {}
	public void mouseEntered(MouseEvent me) {}
	public void mouseExited(MouseEvent me) {}
	public void mousePressed(MouseEvent me) {}
	public void mouseReleased(MouseEvent me) {}
	public void mouseDragged(MouseEvent me) {}
	public void mouseMoved(MouseEvent me) {}	
	
	
	// Mettre un certain clip au premier plan
	public void bringMeToFront(Clip sender){
		if(isDisposed) return;
		if(!clips.contains(sender)) return;
		clips.remove(sender);
		clips.add(sender);
	}
	  
}
