/**
 * pliagep.java
 * date : 12 et 22/09/22 (reprise d'un programme écrit le 05/10/99)
 * auteur : Jean-Paul QUELEN
 */

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import geo.*;

public class pliagep extends JFrame implements ActionListener, Runnable {
	static final long serialVersionUID = 220922L;
	static final int netapemax = 10, nbclmax = 20;
	static final long tempo = 100L;
	static Image img;
	static Graphics g1;
	int gw, gh;

	int netape = 0;
	int nbcl = -1;
	JButton plier, deplier, reinit;
	boolean bcouleur;
	boolean bcouleurABD;
	double dDBmin;
	boolean bchgtcoul;
	boolean bplier = true;

// objets géométriques
	static Repere R;
	static Pt A;
	static Pt B;
	static Pt C;
	static Pt D;
	static Triangle[] ACD = new Triangle [netapemax];
	static Pt[] B0 = new Pt [netapemax];
	static Thread monpliage;
	Feuille dessin = new Feuille();

	public pliagep (String titre) {
		super (titre);
		setLayout (new BorderLayout());
		JPanel jp = new JPanel();
		add (jp, BorderLayout.NORTH);
		jp.add (plier = new JButton ("Plier"));
		plier.addActionListener (this);
		jp.add (deplier = new JButton ("Déplier"));
		deplier.addActionListener (this);
		jp.add (reinit = new JButton ("Réinitialisation"));
		reinit.addActionListener (this);
		add (dessin, BorderLayout.CENTER);
		monpliage = new Thread (this);
		monpliage.start();
	}

/**
 * class feuille
 */

protected class Feuille extends Canvas {
	static final long serialVersionUID = 220912L;

	public Feuille() {
		setBackground (Color.WHITE);
	}

	public void update (Graphics g) {
		paint (g);
	}

	public void paint (Graphics g) {
		if (img == null || gw != getSize().width || gh != getSize().height) {
			gw = getSize().width;
			gh = getSize().height;
			img = createImage (gw, gh);
			g1 = img.getGraphics ();
			g1.setFont (new Font ("Arial", Font.PLAIN, 10));

// Au démarrage nouveau repère et création des points A, B, C
			double echelle = 0.2 * gh;
			if (R == null) {
				R = new Repere (40, gh - 40, gw, gh, echelle, echelle);
				A = new Pt (0.0, 0.0);
				B = new Pt (6.0, 0.0);
				C = new Pt (3.0, 3.0);
				netape = 0;
				nbcl = -1;
				bcouleurABD = false;
			} else {
				R.MAJ (40, gh - 40, gw, gh, echelle, echelle);
			}
		}

// si l'image est fixe on recalcule D puis on crée ACD[netape]
		if (nbcl < 0) {
			Droite dBC = new Droite (B, C);
			Droite dAD = Droite.bissectrice (B, A, C);
			D = Pt.intersection (dBC, dAD);
			ACD[netape] = new Triangle (A, C, D);
			dDBmin = B.distance (D);
			bchgtcoul = true;
			bcouleur = bcouleurABD;
		}
		Triangle ABD = new Triangle (A, B, D);

// on efface
		g1.setColor (getBackground());
		g1.fillRect (0, 0, gw, gh);

// et on trace
		g1.setColor (Color.BLACK);
		R.cadre (g1);

		boolean bcoul = bcouleur;
		g1.setColor ((bcoul)? Color.RED : Color.GREEN);
		if (ACD[netape] != null)
				ACD[netape].trace (true, "", R, g1);

		for (int i = netape - 1; i >= 0; i--) {
			g1.setColor ((bcoul)? Color.RED : Color.GREEN);
			bcoul = !bcoul;
				ACD[i].trace (true, "", R, g1);
		}

// Si la distance de B à D est minimale alors B est sur la droite (AD) => on change la couleur
		double dDB = B.distance (D);
		if (dDB <= dDBmin)
			dDBmin = dDB;
		else if (bchgtcoul) {
			bchgtcoul = !bchgtcoul;
			bcouleurABD = !bcouleurABD;
		}

		g1.setColor ((bcouleurABD)? Color.RED : Color.GREEN);
		ABD.trace (true, "", R, g1);

		if (nbcl > 0) {
			g1.setColor (Color.ORANGE);
			Segment AD = new Segment (A, D);
			AD.trace ("", R, g1);
		}

// pour mise au point
/*		g1.setColor (Color.BLUE);
		A.traceNom ("A", R, g1);
		B.traceNom ("B", R, g1);
		C.traceNom ("C", R, g1);
		D.traceNom ("D", R, g1); */

		g.drawImage (img, 0, 0, this);
	}

} // fin protected class Feuille

// exécution de l'animation dans un Thread différent
	public void run () {
		Thread t = Thread.currentThread();
		Pt E = new Pt();
		while (t == monpliage) {
			if (nbcl >= 0 && nbcl < nbclmax) {
				try {
					Thread.sleep (tempo);
				}
				catch (InterruptedException ie) {}
				if (nbcl == 0) {
					if (!bplier) {
// on récupère A et D du pliage précédent
						netape--;
						A.MAJ (ACD[netape].xi[0], ACD[netape].yi[0]);
						D.MAJ (ACD[netape].xi[2], ACD[netape].yi[2]);
						dDBmin = B.distance (D);
						E.MAJ (B0[netape]);				// l'ancienne position de B devient le point E de destination
						bchgtcoul = true;
						bcouleur = !bcouleurABD;
					} else {
						double k = A.distance (B) / A.distance (C);
						E = C.homothetie (A, k);
						B0[netape] = new Pt (B);	// on garde en réserve l'ancienne position de B pour un éventuel dépliage
					}
				}
// pliage ou dépliage => B se déplace de sa position initiale jusqu'à son position sur E, point de (AC) tel que AE = AB
// B ne se déplace pas de façon linéaire
				B.MAJ (B.x + (double)nbcl / nbclmax * (E.x - B.x), B.y + (double)nbcl / nbclmax * (E.y - B.y));
				nbcl++;
				dessin.repaint();
			}
			if (nbcl == nbclmax) {
				nbcl = -1;
				if (netape < netapemax - 1 && bplier) {
					netape++;
					A.MAJ (D);
					dessin.repaint();
				} else if (netape > 0 && !bplier) {
					A.MAJ (ACD[netape].xi[0], ACD[netape].yi[0]);
					dessin.repaint();
				}
			}
			try {
				Thread.sleep (0L);
			}
			catch (InterruptedException ie) {}
		}
	}

	public void actionPerformed (ActionEvent e) {
		if (e.getSource () == plier) {
// bouton actif seulement si l'image est fixe
			if (netape < netapemax && nbcl == -1) {
					nbcl = 0;
					bplier = true;
			}
		} else if (e.getSource () == deplier) {
// bouton actif seulement si l'image est fixe
			if (netape > 0 && nbcl == -1) {
					nbcl = 0;
					bplier = false;
			}
			
		} else if (e.getSource () == reinit) {
			while (nbcl != -1) {
				try {
					Thread.sleep (0L);
				}
				catch (InterruptedException ie) {}
			}
			img = null;
			R = null;
			dessin.repaint();
		}
	}

	public static void main (String[] args) {
		pliagep p = new pliagep ("Pliage Dépliage");
		p.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);		// EXIT_ON_CLOSE pour la fermeture du Thread
		p.setSize (500, 400);
		p.setVisible (true);
	}

}
