/*
 * Applet : Pavages d'ordre 5
 */

/*
 * Remarque : il faudrait optimiser la partie Magnet qui fait des
 * calculs en trop
 */

// Bibilothèques utilisées 

/*
 * Gestion de l'interface utlisateur : Swing ou AWT ?
 * 1. Je déconseille Swing pour l'instant.
 * 2. Du coup, comme les boutons, menus et autres dépendent de l'OS
 *    je préfère faire mes propres composants : en fait je ne dérive
 *    rien de la classe Component, je fais tout à la main.
 */

import java.util.*;
import java.awt.*;
import java.awt.event.*;

/*
 * Classe principale (tout est dedans)
 */

public class Puzzle 
    extends Base
       // J'ai écrit la classe Base qui regroupe des fonctionnalités
       // communes à mes applets, voir description.txt
    implements 
	// ActionListener,
	MouseListener,
	MouseMotionListener,
	KeyListener
       // signifie qu'il réagit aux actions suivantes 
       // ActionListener   : actionPerformed(...)      -> bouton
       // MouseListener    : ... -> souris
       // MouseMotionListener : ... -> souris aussi
       // KeyListener      : clavier
{
    /*
     *                             Champs
     */

    /*
     * Je mets ici les constantes utilisées dans le placement des 
     * zones de l'applet
     */
    public static int
	XOFFSET=20, // position de l'aire de jeu (Upper Left corner)
	YOFFSET=20, // idem
	PIECES_AREA_WIDTH=100,
	BUTTON_SIZE=40;

    public static double 
	PIECES_AREA_SCALE=50;

    public Rectangle bounds; // mémorise la taille de la zone d'affichage

    public int x1,x2,y1,y2;  // mémorise les coords de la zone de pose
                             // des pièces

    /*
     * Magnet
     */

    // Dit si le mode magnet est en route
    public boolean magnet;
    public boolean stuck;

    // Seuil pour la magnet
    public static double
	SIDE_DIST_TRESH=0.2;

    public double memX,memY;

    /*
     * Zone de pose
     */

    // Données quand on fait glisser la zone de pose
    public boolean draggingDropZone;
    public int clickedX,clickedY;
    public double savedoffx,savedoffy;

    // Décalage et échelle mathématiques de la zone de pose
    public double
	offx,
	offy,
	scale;
    public int scaleIndex;
    public static int
	SCALE_INDEX_MIN=-8,
	SCALE_INDEX_MAX=8;
    public static double
	SCALE_LOG_STEP=0.4;

    // Sert à corriger un problème : quand on clique avec un léger
    // déplacement, le systeme considère qu'on fait un "glissé".
    // On pêut peut-être mieux faire ?
    public boolean dragging;

    /*
     * les deux figures de base
     */
    /*
    OLD :
    public static double[][][]
	POLS={{{0,0},{1,0},{1.309016994374947,.9510565162951535}
                       ,{0.309016994374947,.9510565162951535}}
	     ,{{0,0},{1,0},{1.809016994374947,.4370160244488210}
	               ,{0.809016994374947,.4370160244488210}}
	     };
    */
    public static double[][][]
	POLS={{{-.6545084971874738,-.4755282581475768}
	      ,{0.3454915028125262,-.4755282581475768}
              ,{0.6545084971874738,.4755282581475768}
              ,{-.3454915028125262,.4755282581475768}
              }
	     ,{{-.9045084971874738,-.2938926261462365}
	      ,{0.0954915028125262,-.2938926261462365}
              ,{0.9045084971874738,.2938926261462365}
              ,{-.0954915028125262,.2938926261462365}
              }
	     };
    //.9045084971874738, .2938926261462365

    // Angles orientés des cotés, en 1/10 de tours
    public static int[][] ANGLES={{0,2,5,7},{0,1,5,6}};

    /*
     * Pièce tenue
     */
    public int holdedX;
    public int holdedY;
    public int holdedType;
    public int holdedAngle;

    /*
     * Les deux polygônes du panier (coordonnées écran)
     */
    public Polygon P0, P1;

    /*
     * Table des cos et sin des multiples de 2*Pi/10
     */
    public double[] COS;
    public double[] SIN;

    /*
     * Géométrie des boutons
     */
    Rectangle but1,but2;

    // ...

    public boolean holdingPiece;

    public Vector droppedPieces;

    /*
     *                          Sous-classes
     */

    /*
     * Pièces posées
     */
    class Tile 
    {
	double x,y;
	int angle;
	int type;
    }

    /* 
     * Côté (orienté)
     */
    class Side
    {
	double x1,x2,y1,y2;
    }

    /*
     *                           Méthodes
     */

    /*
     * Crée un polygône à coords entière pour affichage à l'écran
     * on donne l'offset, l'échelle, la rotation en tour/10 et le
     * numéro du polygone dans la liste POLS
     */
    public Polygon rotateAndScale(double xoff_, double yoff_, double scale_,
				  int angle, int index)
    {
	Polygon p=new Polygon();
	double u,v;
	for(int i=0;i<4;i++) {
	    u=COS[angle]*POLS[index][i][0] - SIN[angle]*POLS[index][i][1];
	    v=SIN[angle]*POLS[index][i][0] + COS[angle]*POLS[index][i][1];
	    // Remarquer le signe '-' dans la formule suivante
	    p.addPoint((int)(xoff_+scale_*u),
		       (int)(yoff_-scale_*v));
	}
	return p;
    }

    /*
     * Version où les transfo sont faites dans un autre ordre et on
     * ajoute l'offset de la zone de pose
     */
    public Polygon scaleAndPlace(double xoff_, double yoff_, double scale_,
				 int angle, int index)
    {
	Polygon p=new Polygon();
	double u,v;
	for(int i=0;i<4;i++) {
	    u=COS[angle]*POLS[index][i][0] - SIN[angle]*POLS[index][i][1];
	    v=SIN[angle]*POLS[index][i][0] + COS[angle]*POLS[index][i][1];
	    // Remarquer le signe '-' dans la formule suivante
	    p.addPoint(XOFFSET+(int)(scale_*(xoff_+u)),
		       YOFFSET-(int)(scale_*(yoff_+v)));
	}
	return p;
    }

    /*
     * Création des deux polygônes du panier
     * Appelé à chaque Paint()
     */
    public void createBasketPolygons() {
	storeBounds();
	P0=rotateAndScale(x2+(XOFFSET+PIECES_AREA_WIDTH)/2,80,PIECES_AREA_SCALE,0,0);
	P1=rotateAndScale(x2+(XOFFSET+PIECES_AREA_WIDTH)/2,150,PIECES_AREA_SCALE,0,1);
    }

    /*
     * Mémorise la taille de la zone d'affichage et calcule quelques constantes
     */
    public void storeBounds() {
	bounds=getBounds(); // prendre la taille de la zone
	                              // d'affichage de la fenêtre

	// Zone de pose
	x1=XOFFSET;
	x2=bounds.width-XOFFSET-PIECES_AREA_WIDTH;
	y1=YOFFSET;
	y2=bounds.height-YOFFSET;

	// Boutons
	int w=(bounds.width-x2-2*BUTTON_SIZE)/3;
	but1=new Rectangle(x2+w,y2-BUTTON_SIZE,BUTTON_SIZE,BUTTON_SIZE);
	but2=new Rectangle(x2+2*w+BUTTON_SIZE,y2-BUTTON_SIZE,BUTTON_SIZE,BUTTON_SIZE);
    }

    /*
     *
     */
    public void setScale() {
	scale=((double)PIECES_AREA_SCALE)
	    *Math.exp(((double)scaleIndex)*SCALE_LOG_STEP);
    }

    /*
     * Utilisés pout le mode Magnet
     */

    public int getSideAngle(Tile tile, int n) {
	return (tile.angle+ANGLES[tile.type][n]) % 10;
    }

    public int getSideAngle2(int n) {
	return (holdedAngle+ANGLES[holdedType][n]) % 10;
    }

    /*
     * Distance entre les centres de deux côtés 
     */
    public double sideDistance(Side s1, Side s2) {
	double dx=(s1.x1+s1.x2)-(s2.x1+s2.x2);
	double dy=(s1.y1+s1.y2)-(s2.y1+s2.y2);
	return Math.max(Math.abs(dx),Math.abs(dy))/2.0;
    }

    /*
     * Distance entre deux côtés ORIENTES
     */
    /*
    public double sideDistance(Side s1, Side s2) {
	return Math.max(
		   Math.max(Math.abs(s1.x1-s2.x2),Math.abs(s1.y1-s2.y2)),
		   Math.max(Math.abs(s1.x2-s2.x1),Math.abs(s1.y2-s2.y1))
	        );
    }
    */
/*
    public double sideDistance(Side s1, Side s2, Integer shift)
    {
	double d1=Math.max(
		   Math.max(Math.abs(s1.x1-s2.x1),Math.abs(s1.y1-s2.y1)),
		   Math.max(Math.abs(s1.x2-s2.x2),Math.abs(s1.y2-s2.y2)));
	double d2=Math.max(
		   Math.max(Math.abs(s1.x1-s2.x2),Math.abs(s1.y1-s2.y2)),
		   Math.max(Math.abs(s1.x2-s2.x1),Math.abs(s1.y2-s2.y1)));
	if(d1<d2) {
	    shift=new Integer(0);
	    return d1;
	}
	else {
	    shift=new Integer(1);
	    return d2;
	}
    }
*/

    /*
     * Parties posées
     */
    public Side getSide(Tile tile, int n) {       
	// Retourne les coords math du côté 'n' de la tuile 'tile'
	Side side=new Side();

	int angle=tile.angle;
	int index=tile.type;
	int i;

	i=n;
	side.x1=tile.x + COS[angle]*POLS[index][i][0]
	               - SIN[angle]*POLS[index][i][1];
	side.y1=tile.y + SIN[angle]*POLS[index][i][0]
	               + COS[angle]*POLS[index][i][1];
	i=(n+1) % 4;
	side.x2=tile.x + COS[angle]*POLS[index][i][0]
	               - SIN[angle]*POLS[index][i][1];
	side.y2=tile.y + SIN[angle]*POLS[index][i][0]
	               + COS[angle]*POLS[index][i][1];

	return(side);
    }

    /*
     * Partie portée
     */
    public Side getSide2(int x, int y, int n) {
	Side side=new Side();

	double u,v;
	u=x-XOFFSET;
	u=u/scale-offx;
	v=YOFFSET-y;
	v=v/scale-offy;
	int angle=holdedAngle;
	int index=holdedType;
	int i;

	i=n;
	side.x1=u + COS[angle]*POLS[index][i][0] 
                  - SIN[angle]*POLS[index][i][1];
	side.y1=v + SIN[angle]*POLS[index][i][0]
                  + COS[angle]*POLS[index][i][1];
	i=(n+1) %4;
	side.x2=u + COS[angle]*POLS[index][i][0] 
                  - SIN[angle]*POLS[index][i][1];
	side.y2=v + SIN[angle]*POLS[index][i][0]
                  + COS[angle]*POLS[index][i][1];

	return(side);
    }

    /*
     * Constructeur de la classe principale
     */
    public void init() {

	// Toujours appeler le constructeur de la classe mère

	super.init();

	// Message d'aide

        StringBuffer auxString=new StringBuffer(
  "Mode d'emploi de l'applet\n"
+ "\n" 
+ "Affichage :\n"
+ "\n"
+ "  -  Jeu de pavages d'ordre 5, \n"
+ "     type \"Puzzle\".\n"
+ "\n"
);
	auxString.append(
  "\n"
+ "Commandes :\n"
+ "\n"
+ "  -  Cliquer sur une pièce dans la réserve pour la prendre.\n"
+ "  -  La faire éventuellement tourner avec le clavier.\n"
+ "  -  La déposer dans la zone blanche avec un nouveau click.\n"
+ "  -  Shift-click permet de faire glisser la zone blanche.\n"
+ "  -  Les boutons + et - permettent de (dé)zoomer.\n"
+ "  -  La touche '?' ou un click droit ouvrent cette fenêtre d'information.\n"
+ "\n" 
+ "Puzzle, ©2003 Arnaud Chéritat\n"
);

	// MyHelpApplet prendra en charge la gestion du message
	// d'aide, dont le contenu est défini par setHelpText("contenu");

        setHelpText(auxString.toString());

	// Création du contenu et affectation de celui-ci à l'applet

	//        makeContent();

	addKeyListener(this);
	addMouseListener(this);
	addMouseMotionListener(this);

	/*
	 * Initialisation des variables utilisateurs
	 */

	// Au début, on ne tient aucune pièce
	holdingPiece=false;

	// Aucune pièce posée
	droppedPieces=new Vector();

	// 
	dragging=false;

	//
	magnet=true;
	stuck=false;

	/*
	 * Initialisation mathématique
	 */

	// ...
	offx=0;
	offy=0;
	scaleIndex=0;
	setScale();

	// Remplissage du tableau des cos, sin de 2*k*Pi/10
	COS=new double[10];
	SIN=new double[10];
	for(int k=0;k<10;k++) {
	    COS[k]=Math.cos(2.0*((double)k)*Math.PI/10.0);
	    SIN[k]=Math.sin(2.0*((double)k)*Math.PI/10.0);
	}

	// APRES remplissage des cos,sin et ... : créér les polygônes du panier
	createBasketPolygons(); // Bien placé ???
    }

    /* Pour gérer l'affichage de la class Base,
     * il faut modifier la méthode offPaint
     */
    public void offPaint(Graphics g) {
  
	// Rectangle mathématique en blanc

	storeBounds();

	// Remplissage en blanc
	g.setColor(Color.white);
	g.fillRect(x1, y1, x2-x1, y2-y1);
	// Tracé du bord en noir : remarquer les "-1" en plus
	g.setColor(Color.black);
	g.drawRect(x1, y1, x2-x1-1, y2-y1-1);

	// Les deux pièces

	createBasketPolygons();

	// Remplissage en vert
	g.setColor(Color.green);
	g.fillPolygon(P0);
	// Tracé du bord en noir
	g.setColor(Color.black);
	g.drawPolygon(P0);

	// Remplissage en bleu
	g.setColor(Color.blue);
	g.fillPolygon(P1);
	// Tracé du bord en noir
	g.setColor(Color.black);
	g.drawPolygon(P1);

	// Les boutons
	// Bouton moins
	g.setColor(Color.pink);
	g.fillRect(but1.x,but1.y,but1.width,but1.height);
	g.setColor(Color.black);
	g.drawRect(but1.x,but1.y,but1.width-1,but1.height-1);
	// Tracé du signe moins
	g.fillRect(but1.x+5,but1.y+but1.height/2-3,but1.width-10,6);
	// Bouton plus
	g.setColor(Color.pink);
	g.fillRect(but2.x,but2.y,but2.width,but2.height);
	g.setColor(Color.black);
	g.drawRect(but2.x,but2.y,but2.width-1,but2.height-1);
	// Tracé du signe plus
	g.fillRect(but2.x+5,but2.y+but2.height/2-3,but2.width-10,6);
	g.fillRect(but2.x+but2.width/2-3,but2.y+5,6,but2.height-10);

	// Les pièces posées

	Shape savedClip=g.getClip();
	g.setClip(x1+1,y1+1,x2-x1-2,y2-y1-2);
	Tile tile;
	Polygon tp;
	int s=droppedPieces.size();
	for(int i=0 ; i<s ; i++) {
	    tile=(Tile) droppedPieces.elementAt(i);
	    tp=scaleAndPlace(offx+tile.x,offy+tile.y,scale,tile.angle,tile.type);
	    // Remplissage
	    g.setColor(tile.type==0 ? Color.green : Color.blue);
	    g.fillPolygon(tp);
	    // Tracé du bord en noir
	    g.setColor(Color.black);
	    g.drawPolygon(tp);	    
	}
	g.setClip(savedClip);

	// L'éventuelle pièce portée

	if(holdingPiece) {
	    Polygon hp=rotateAndScale(holdedX,holdedY,
		      scale,holdedAngle,holdedType);
	    // Remplissage
	    g.setColor(holdedType==0 ? Color.green : Color.blue);
	    g.fillPolygon(hp);
	    // Tracé du bord en noir
	    g.setColor(Color.black);
	    g.drawPolygon(hp);
	}

	/*	
	// Texte
	g.setColor(new Color(0.25f,0.5f,0.75f));
	g.setFont(myFont2);
	g.drawString("Vitesse : ",TEXTX,YOFFSET+SIZE+TEXTY);
	*/
    }

    // Interface MouseListener

    public void mouseClicked(MouseEvent e) {
	// Testons s'il s'agit du bouton gauche
	if((e.getModifiers() & InputEvent.BUTTON1_MASK)!=0) {
	    // Si oui
	    // Coordonnées du click :
	    int x=e.getX();
	    int y=e.getY();
	    if(holdingPiece) {
		// Si l'on est en train de porter une pièce
		holdingPiece=false;
		if(x>x1 && x<x2 && y>y1 && y<y2) {
		    Tile tile = new Tile();
		    if(stuck) {
			// Si la pièce est magnétiquement collée :
			tile.x = memX ;
			tile.y = memY ;
			stuck=false;
		    }
		    else {
			tile.x=((double)(x-XOFFSET))/scale-offx;
			tile.y=((double)(YOFFSET-y))/scale-offy;
		    }
		    tile.type=holdedType;
		    tile.angle=holdedAngle;
		    droppedPieces.addElement(tile);
		}
		repaint();
	    }
	    else {
		// quand on ne tient pas de piece
		if(x>x1 && x<x2 && y>y1 && y<y2) {
		    // Cas d'un click dans la zone de pose
		    // Cherchons si on a cliqué sur une pièce posée
		    int n=droppedPieces.size();
		    int k=-1;
		    Polygon p;
		    Tile tile;
		    for(int i=0; i<n; i++) {
			tile=(Tile) droppedPieces.elementAt(i);
			p=scaleAndPlace(offx+tile.x,offy+tile.y,
					 scale,tile.angle,tile.type);
			if(p.contains(x,y)) {
			    k=i;
			}
		    }
		    // Si oui
		    if(k>-1) {
			tile=(Tile) droppedPieces.elementAt(k);
			holdingPiece=true;
			holdedX=x;
			holdedY=y;
			holdedType=tile.type;
			holdedAngle=tile.angle;
			// Retirons la piece de la liste
			droppedPieces.removeElementAt(k);
			repaint();
		    }
		} 
		else if(x>but1.x && x<but1.x+but1.width 
	             && y>but1.y && y<but1.y+but1.height) {
		    if(scaleIndex>SCALE_INDEX_MIN) {
			double xs,ys;
			xs=-offx+((double)(x2-x1))/(2.0*scale);
			ys=-offy+((double)(y1-y2))/(2.0*scale);
			scaleIndex-=1;
			offx=-xs+(offx+xs)*Math.exp(SCALE_LOG_STEP);
			offy=-ys+(offy+ys)*Math.exp(SCALE_LOG_STEP);
			setScale();
			repaint();
		    }
		}
		else if(x>but2.x && x<but2.x+but2.width 
	             && y>but2.y && y<but2.y+but2.height) {
		    if(scaleIndex<SCALE_INDEX_MAX) {
			double xs,ys;
			xs=-offx+((double)(x2-x1))/(2.0*scale);
			ys=-offy+((double)(y1-y2))/(2.0*scale);
			scaleIndex+=1;
			offx=-xs+(offx+xs)*Math.exp(-SCALE_LOG_STEP);
			offy=-ys+(offy+ys)*Math.exp(-SCALE_LOG_STEP);
			setScale();
			repaint();
		    }
		}
		else {
		    if(P0.contains(x,y)) {
			holdingPiece=true;
			holdedType=0;
		    };
		    if(P1.contains(x,y)) {
			holdingPiece=true;
			holdedType=1;
		    };
		    if(holdingPiece) {
			holdedAngle=0;
			holdedX=x;
			holdedY=y;
			repaint();
		    }
		}
	    }
	}
    }
    public void mouseEntered(MouseEvent e) {
	// Do nothing
    }
    public void mouseExited(MouseEvent e) {
	// Do nothing
    }
    public void mousePressed(MouseEvent e) {
	// Do nothing
	    if((e.getModifiers() & InputEvent.SHIFT_MASK )!=0) {
		// En présence de Shift
		int x=e.getX();
		int y=e.getY();
		if(x>x1 && x<x2 && y>y1 && y<y2) {
		    draggingDropZone=true;
		    clickedX=x;
		    clickedY=y;
		    savedoffx=offx;
		    savedoffy=offy;
		}
	    }
    }
    public void mouseReleased(MouseEvent e) {
	if(dragging) {
	    // Ignorons la différence Dragged/Clicked
	    mouseClicked(e);
	    dragging=false;
	}
	if(draggingDropZone) {
	    draggingDropZone=false;
	}
    }

    // Interface MouseMotionListener

    public void mouseDragged(MouseEvent e) {
	if(draggingDropZone) {
	    int x=e.getX();
	    int y=e.getY();
	    offx=savedoffx+((double)(x-clickedX))/scale;
	    offy=savedoffy-((double)(y-clickedY))/scale;
	    repaint();
	}
	else {
//	    else {
		// En l'absence de Shift
		dragging=true;
//	    }
	}
		// Ignorons la différence Dragged/Clicked
		if(holdingPiece) {
		    mouseMoved(e);
		}
    }
    public void mouseMoved(MouseEvent e) {
	if(holdingPiece) {
	    int x=e.getX();
	    int y=e.getY();
	    holdedX=x;
	    holdedY=y;
	    if(magnet) {
		// Si le mode magnet est actif :
		int n=droppedPieces.size(); // nb de pièces posées
		double px1,py1,px2,py2;
		Side s1,s2;
		double record,sd;
		int ri,rj,rk; //,o;
		ri=-1;
		rj=-1;
		rk=-1;
		//		o=-1;
		record=SIDE_DIST_TRESH;
		//		Integer shift=new Integer(0);
		Tile tl;
		int a1,a2;
		for(int k=0; k<4; k++) {
		    // Pour chaque côté "s1" de la pièce portée
		    s1=getSide2(x,y,k);
		    a1=getSideAngle2(k);
		    for(int i=0; i<n; i++) {
			// Pour chaque pièce "tile"
			tl=(Tile) droppedPieces.elementAt(i);
			for(int j=0; j<4; j++) {
			    // Pour chaque côté "s2" de la pièce
			    a2=getSideAngle(tl,j);
			    // testons d'abord l'angle :
			    if(a1 == ((a2 + 5) % 10)) {
				// Si les angles sont opposés :
				s2=getSide(tl,j);
				// mesurons la distance entre les deux côtés
				sd=sideDistance(s1,s2);
				if(sd<record) {
				    record=sd;
				    ri=i;
				    rk=k;
				    rj=j;
//				o=shift.intValue();
				}
			    }
			}
		    }
		}
		// Au cas où on a détecté une pièce :
		if(ri>-1) {
		    stuck=true;
		    Tile tile=(Tile) droppedPieces.elementAt(ri);
		    Tile t1=new Tile();
		    t1.x=0;
		    t1.y=0;
		    t1.angle=holdedAngle;
		    t1.type=holdedType;
		    s1=getSide(t1,rk);
		    s2=getSide(tile,rj);
		    memX=s2.x2-s1.x1;
		    memY=s2.y2-s1.y1;
		    Polygon p1=scaleAndPlace(offx+tile.x,offy+tile.y,
					     scale,tile.angle,tile.type);
		    Polygon p2=rotateAndScale(x,y,
					      scale,holdedAngle,holdedType);
		    // On translate pour caler
		    holdedX=x+p1.xpoints[(rj+1) % 4]-p2.xpoints[rk];
		    holdedY=y+p1.ypoints[(rj+1) % 4]-p2.ypoints[rk];
		}
		else {
		    stuck=false;
		}
	    }
	    // Ordonnons le redessin de la fenêtre
	    repaint();
	    // ETC...
	}
    }

    // Interface KeyListener

    public void keyPressed(KeyEvent e) {
	int left=-1;
	int center=0;
	int right=1;

	int turn=center;

	if(holdingPiece) {


	    switch(e.getKeyChar()) {
	    case 'a' : case 'A' : case 'q' : case 'Q' : case 'l' :
	    case 'L' : turn=left; break;
	    case 'z' : case 'Z' : case 'w' : case 'W' : case 'r' :
            case 'R' : turn=right; break;
	    }
	    if(e.getKeyCode()==KeyEvent.VK_LEFT) { turn=left; }
	    //	    if(e.getKeyCode()==KeyEvent.VK_KP_LEFT) { turn=left; }
	    if(e.getKeyCode()==KeyEvent.VK_RIGHT) { turn=right; }
	    //	    if(e.getKeyCode()==KeyEvent.VK_KP_RIGHT) { turn=right; }

	    if(turn==left) {
		holdedAngle+= 1;
		// remarquer que la symétrie centrale des pièces
		// permet d'effectuer un modulo 5 au lieu de 10
		holdedAngle= (5+holdedAngle) % 5;
		repaint();
	    }
	    if(turn==right) {
		holdedAngle-= 1;
		holdedAngle= (5+holdedAngle) % 5;
		repaint();
	    }
	}

    }
    public void keyReleased(KeyEvent e) {
	// Do nothing
    }
    public void keyTyped(KeyEvent e) {
	// Do nothing
    }
 


    // Autres

    /*
     * Méthode "abstract" de la classe Base dont dérive cet applet.
     * Gère le Placement des composants en "absolute positioning"
     * Y mettre le code les positionnant --au premier affichage--
     */
    public void position() {
	// Rien pour l'instant
    }
    
    /* Cette fonction parle d'elle-même
     * elle n'est pas utilisée par les navigateurs actuels
     */
    public String getAppletInfo() {
         return "Puzzle, ©2003 Arnaud Chéritat";
    }
}
