/**
 * sp1.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)
 * pas de récursivité
 * le calcul de la chaîne des déplacement ne se fait que si Niter, le nombre d'itérations a été modifié
 * et est plus grand que Niter0
 *
 * Jean-Paul Quelen 18/04/20
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class sp1 extends JPanel implements MouseListener {
	static final long serialVersionUID = 200418L;
// 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 sp1() {
		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);
		or = 'E';
		add (tor = new TextField ("E", 1));

		add (lbl = new Label ("Itérations : "));
		nlab (lbl, f);
		Niter = 2;
		add (tfn = new TextField ("2", 10));

		add (lbl = new Label ("Longueur d'un pas (en pixels)"));
		nlab (lbl, f);
		l = 8.0;
		add (tfl = new TextField ("8.0", 10));

		add (lcalc = new TextField (20));
		lcalc.setFont (f);
		lcalc.setBackground (Color.black);
		lcalc.setForeground (Color.white);
		addMouseListener (this);

		NiterOld = 1;
		mvt = "1";
		ls2 = 0.5 * l;
	}

	private void nlab (Label lbl, Font f) {
		lbl.setFont (f);
		lbl.setBackground (Color.black);
		lbl.setForeground (Color.white);
	}

	public void init() {
		x = Xp = X0;
		y = Yp = Y0;
		dir = "NESO".indexOf (or) * 2;
	}

	public 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;
		}
	}

	public 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);
	}

	private void calc (int deb, int fin) {
		for (int i = deb; i < fin; i++) {
			int mvtlm1 = mvt.length() - 1;
			mvt += '1';
			for (int j = mvtlm1; j >= 0; j--) {
				mvt += (mvt.charAt (j) == '1') ? '0' : '1';
			}
		}
		NiterOld = Niter;
	}

	public void paint (Graphics g) {
		lcalc.setText ("Calcul en cours");
		if (xmax != getWidth() || ymax != getHeight()) {
			xmax = getWidth();
			ymax = getHeight();
			X0 = xmax / 2;
			Y0 = ymax / 2;
		}
		init();

		if (Niter < NiterOld) {
			mvt = mvt.substring (0, (1 << Niter) - 1);
			NiterOld = Niter;
		} else {
			calc (NiterOld, Niter);		// ne fait rien si Niter == NiterOld
		}

		g.setColor (Color.black);
		g.fillRect (0, 0, xmax, ymax);
		g.setColor (Color.white);

		trace (g);

		lcalc.setText ("");
	}

	public void mousePressed (MouseEvent e) {
		char or1 = tor.getText().toUpperCase().charAt(0);
		if ("NSOE".indexOf (or1) != -1) {
			or = or1;
		}
		tor.setText (Character.toString (or));

		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();
		init();
		repaint();
	}

//	public void mousePressed (MouseEvent e) {}
	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 = 800;
		int h = 800;

		sp1 s = new sp1();

		JFrame f = new JFrame ("La symétrie perturbée v1");
		f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		f.add (s);
		f.setSize (w, h);
		f.setVisible (true);
	}

}

