/**
 * sp3.java
 *
 * La symétrie perturbée, d'après l'ouvert n°49 de décembre 1987
 * fabrique une chaîne de 1 et de 0 dans un String (g = 1, d = 0) de façon récursive.
 *
 * Jean-Paul Quelen 04/05/20
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class sp3 extends JPanel implements MouseListener {
	static final long serialVersionUID = 200504L;
// dir =	0	1	2	3	4	5	6	7
//			N	NE	E	SE	S	SO	O	NO
	int xmax, ymax, Niter, X0, Y0, dir, Xp, Yp, NiterOld;
	double l, x, y, ls2;
	char or;
	TextField tfn, tfl, tor, lcalc;
	String mvt;

	public sp3() {
		Font f = new Font (Font.SANS_SERIF, Font.PLAIN, 10);
		Label lbl;

		add (lbl = new Label ("Orientation initiale (N, S, O, E)"));
		nlab (lbl, f);
		add (tor = new TextField ("E", 1));
		tor.setFont (f);
		or = 'E';
		dir = 2;	//"NESO".indexOf (or) * 2;

		add (lbl = new Label ("Itérations : "));
		nlab (lbl, f);
		add (tfn = new TextField ("2", 10));
		tfn.setFont (f);
		Niter = NiterOld = 2;
		mvt = "110";

		add (lbl = new Label ("Longueur d'un pas (en pixels)"));
		nlab (lbl, f);
		add (tfl = new TextField ("8.0", 10));
		tfl.setFont (f);
		l = 8.0;
		ls2 = 4.0;

		add (lcalc = new TextField ("", 20));
		lcalc.setFont (f);
		lcalc.setBackground (Color.black);
		lcalc.setForeground (Color.white);
		addMouseListener (this);

	}

	private void nlab (Label lbl, Font f) {
		lbl.setFont (f);
		lbl.setBackground (Color.black);
		lbl.setForeground (Color.white);
	}

	private void avance (Graphics g, double l) {
		switch (dir) {
			case 1, 2, 3 :
				x += l;
				break;
			case 5, 6, 7 :
				x -= l;
		}
		switch (dir) {
			case 3, 4, 5 :
				y += l;
				break;
			case 7, 0, 1 :
				y -= l;
		}
		int X = (int) x;
		int Y = (int) y;
		if (X != Xp || Y != Yp) {
			g.drawLine (Xp, Yp, X, Y);
			Xp = X;
			Yp = Y;
		}
	}

	private void trace (Graphics g) {
		avance (g, l);
		int mvtl = mvt.length();
		for (int i = 0; i < mvtl; i++) {
			int gd = (mvt.charAt (i) == '1') ? 7 : 1;
			avance (g, l);
			dir = (dir + gd) & 7;			// ne pas faire (dir - 1) % 8
			avance (g, ls2);
			dir = (dir + gd) & 7;			// <==> (dir + gd) % 8;
			avance (g, l);
		}
		avance (g, l);
	}

	public void update (Graphics g) {
		paint (g);
	}

	public void paint (Graphics g) {
		if (xmax != getWidth() || ymax != getHeight()) {
			xmax = getWidth();
			ymax = getHeight();
			X0 = xmax / 2;
			Y0 = ymax / 2;
		}
		x = Xp = X0;
		y = Yp = Y0;

		g.setColor (Color.black);
		g.fillRect (0, 0, xmax, ymax);
		g.setColor (Color.white);

		lcalc.setText ("Dessin en cours");
		trace (g);
		lcalc.setText ("");

	}

	public String sn (int n, String mvt) {
		if (n > 1) {
			return sn (n - 1, mvt) + "1" + snm1 (n - 1, mvt);
		}
		return "1";
	}

	public String snm1 (int n, String mvt) {
		if (n > 1) {
			return sn (n - 1, mvt) + "0" + snm1 (n - 1, mvt);
		}
		return "0";
	}

	public void mousePressed (MouseEvent e) {
// récupération des paramètres
		char or1 = tor.getText().toUpperCase().charAt(0);
		if ("NSOE".indexOf (or1) != -1) {
			or = or1;
		}
		tor.setText (Character.toString (or));
		dir = "NESO".indexOf (or) * 2;

		int niter1 = Niter;
		try {
			niter1 = Integer.parseInt (tfn.getText());
			if (niter1 > 0)
				Niter = niter1;
		}
		catch (NumberFormatException nfe) {}
		tfn.setText (Integer.toString (Niter));

		double l1 = l;
		try {
			l1 = Double.parseDouble (tfl.getText());
			if (l1 > 0.0)
				l = l1;
		}
		catch (NumberFormatException nfe) {}
		tfl.setText (Double.toString (l));
		ls2 = 0.5 * l;
		X0 = e.getX();
		Y0 = e.getY();

		lcalc.setText ("Calcul en cours");
		mvt = sn (Niter, "");
		lcalc.setText ("");
		repaint();
	}

	public void mouseReleased (MouseEvent e) {}
	public void mouseClicked (MouseEvent e) {}
	public void mouseEntered (MouseEvent e) {}
	public void mouseExited (MouseEvent e) {}

////////////////////////////////////////////////////////////////////////////////

	public static void main (String [] args) {
		int w = 1000;
		int h = 1000;

		sp3 s = new sp3();

		JFrame f = new JFrame ("La symétrie perturbée sp3.java");
		f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		f.add (s);
		f.setSize (w, h);
		f.setVisible (true);
	}

}

