/**
 * courbelissajous1.java	16 et 22/09/22
 * auteur : Jean-Paul Quelen
 */

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import geo.*;

public class courbelissajous1 extends JFrame implements  ActionListener, Runnable {
	static final long serialVersionUID = 220922L;
	JButton ok;
	JTextField tp, tq, tphi, ttmin, ttmax, tdt;
	JButton animok, animstop;
	JTextField ttempo, animtt, animtdt;
	double animt, animdt;
	long tempo;
	int w, h;
	static Image img;
	static Graphics g1;
	static Repere R;
	static PointLibre O;
	static PointSurDroite U;
	static Pt M, P, Q;
	static Segment PM, QM;
	static Droite OU;
	static Cercle Cx, Cy; 
	static CourbeFonction2 cf;
	static Lissajous fxy;
	Feuille dessin;
	static Thread animation;

	public courbelissajous1 (String titre) {
		super (titre);
		setFont (new Font (Font.SANS_SERIF, Font.PLAIN, 12));
		setLayout (new BorderLayout());
		JPanel p = new JPanel();
		p.setBackground (Color.LIGHT_GRAY);
		add (p, BorderLayout.NORTH);
		JLabel l = new JLabel ("x = Math.sin (p * t); y = Math.sin (q * t + phi)");
		l.setFont (new Font (Font.SANS_SERIF, Font.PLAIN, 10));
		p.add (l);
		p.add (new JLabel (" p ="));
		p.add (tp = new JTextField ("2.0", 5));
		p.add (new JLabel ("q ="));
		p.add (tq = new JTextField ("3.0", 5));
		p.add (new JLabel ("phi ="));
		p.add (tphi = new JTextField ("0.0", 5));
		p.add (new JLabel ("tmin ="));
		p.add (ttmin = new JTextField ("0.0", 5));
		p.add (new JLabel ("tmax ="));
		p.add (ttmax = new JTextField ("6.3", 5));
		p.add (new JLabel ("dt ="));
		p.add (tdt = new JTextField ("0.01", 5));
		p.add (ok = new JButton ("Ok"));
		ok.addActionListener (this);

		add (dessin = new Feuille(), BorderLayout.CENTER);

		p = new JPanel();
		p.setBackground (Color.LIGHT_GRAY);
		add (p, BorderLayout.SOUTH);
		l = new JLabel ("Animation");
		l.setFont (new Font (Font.SANS_SERIF, Font.PLAIN, 10));
		p.add (l);
		p.add (new JLabel (" tempo ="));
		p.add (ttempo = new JTextField ("10", 5));
		p.add (new JLabel ("ms     t ="));
		p.add (animtt = new JTextField ("0.0", 5));
		p.add (new JLabel (" dt ="));
		p.add (animtdt = new JTextField ("0.01", 5));
		p.add (animok = new JButton ("Ok"));
		animok.addActionListener (this);
		p.add (animstop = new JButton ("Stop"));
		animstop.addActionListener (this);
	}

/**
 * classe Feuille
 */

protected class Feuille extends Canvas implements MouseListener, MouseMotionListener {
	static final long serialVersionUID = 220922L;

	public Feuille() {
		setFont (new Font (Font.SANS_SERIF, Font.PLAIN, 10));
		setBackground (Color.WHITE);
		addMouseMotionListener (this);
		addMouseListener (this);
	}

	public void update (Graphics g) {
		paint (g);
	}

	public void paint (Graphics g) {
		int w1 = getWidth();
		int h1 = getHeight();
		if ((img == null) || (w1 != w) || (h1 != h)) {
			w = w1;
			h = h1;
			img = createImage (w, h);
			g1 = img.getGraphics();
			if (R == null) {
				R = new Repere (w / 2, h / 4, w, h, 100.0, 100.0);
				O = new PointLibre (0.0, 0.0);
				OU = new Droite (0.0, 1.0, 0.0);					// axe des x
				U = new PointSurDroite (1.0, 0.0, OU);
				fxy = new Lissajous(1.0, 1.0, 2.0, 3.0, 0.0);
				cf = new CourbeFonction2 (fxy, 0.0, 6.3, 0.01);
				Cx = new Cercle (-2.5, 0.0, 1.0);
				Cy = new Cercle (0.0, -2.5, 1.0);
				P =  new Pt (0.0, -1.5);
				Q =  new Pt (-1.5, 0.0);
				M = new Pt();
			}
		}

		R.MAJ (R.X (O.x), R.Y (O.y), w, h, R.unitex, R.unitex);
		O.MAJ (0.0, 0.0);
		if (U.deplace && (U.x > 0)) {
			R.unitex = R.unitey = O.distance (U) * R.unitex;
		}
		U.MAJ (1.0, 0.0);
		M.MAJ (P.x, Q.y);
		PM = new Segment (P, M);
		QM = new Segment (Q, M);

		g1.setColor (Color.WHITE);
		g1.fillRect (0, 0, R.XMAX, R.YMAX);

		g1.setColor (Color.YELLOW);
		R.trace (g1);

		g1.setColor (Color.GREEN);
		Cx.trace ("", R, g1);
		Cy.trace ("", R, g1);

		g1.setColor (Color.CYAN);
		cf.trace ("", R, g1);

		g1.setColor (Color.BLACK);
		PM.trace ("", R, g1);
		QM.trace ("", R, g1);
		P.trace ("P", R, g1);
		Q.trace ("Q", R, g1);
		M.trace ("M", R, g1);

		g1.setColor (Color.RED);
		O.trace ("O", R, g1);
		U.trace ("U", R, g1);
		
		g.drawImage (img, 0, 0, this);
	}

	public void mousePressed (MouseEvent e) {
		int X = e.getX();
		int Y =  e.getY();
		if ((U.deplace = U.zone (X, Y, R)) || (O.deplace = O.zone (X, Y, R))) {}
	}

	public void mouseDragged (MouseEvent e) {
		int X = e.getX();
		int Y =  e.getY();
		U.bouge (X, Y, R);
		O.bouge (X, Y, R);
		repaint();
	}

	public void mouseReleased (MouseEvent e) {
		U.deplace = O.deplace = false;
	}

	public void mouseMoved (MouseEvent e) {
		int X = e.getX();
		int Y = e.getY();
		if (U != null && U.zone (X, Y, R) || O != null && O.zone (X, Y, R)) {
			setCursor (new Cursor (Cursor.HAND_CURSOR));
		} else {
			setCursor (new Cursor (Cursor.DEFAULT_CURSOR));
		}
	}

	public void mouseClicked (MouseEvent e) {}
	public void mouseEntered (MouseEvent e) {}
	public void mouseExited (MouseEvent e) {}

} // fin classe Feuille

	public void run () {
		Thread th = Thread.currentThread();
		while (th == animation) {
				double[] xy = fxy.Image (animt);
				P.MAJ (Math.sin (fxy.p * animt), Math.cos (fxy.p * animt) - 2.5);
				Q.MAJ (Math.cos (fxy.q * animt + fxy.phi) - 2.5, Math.sin (fxy.q * animt + fxy.phi));
				dessin.repaint();
				animt += animdt;
				animtt.setText (Double.toString (animt));
				try {
					Thread.sleep (tempo);
				}
				catch (InterruptedException ie) {}
		}
	}

	public void actionPerformed (ActionEvent e) {
		if (e.getSource() == ok) {
			double p = Double.parseDouble (tp.getText());
			double q = Double.parseDouble (tq.getText());
			double phi = Double.parseDouble (tphi.getText());
			double tmin = Double.parseDouble (ttmin.getText());
			double tmax = Double.parseDouble (ttmax.getText());
			double dt = Double.parseDouble (tdt.getText());
			tp.setText (Double.toString (p));
			tq.setText (Double.toString (q));
			tphi.setText (Double.toString (phi));
			ttmin.setText (Double.toString (tmin));
			ttmax.setText (Double.toString (tmax));
			tdt.setText (Double.toString (dt));
			fxy.p = p;
			fxy.q = q;
			fxy.phi = phi;
			cf.MAJ (fxy, tmin, tmax, dt);
			animt = tmin;
			animtt.setText (Double.toString (animt));
			P.MAJ (Math.sin (p * tmin), Math.cos (p * tmin) - 2.5);
			Q.MAJ (Math.cos (q * tmin + phi) - 2.5, Math.sin (q * tmin + phi));

			dessin.repaint();
		} else if (e.getSource() == animok) {
			if (animation == null) {
				animation = new Thread(this);
				animation.start();
			}				
			tempo  = Long.parseLong (ttempo.getText());
			animt = Double.parseDouble (animtt.getText());
			animdt = Double.parseDouble (animtdt.getText());
			ttempo.setText (Long.toString (tempo));
			animtt.setText (Double.toString (animt));
			animtdt.setText (Double.toString (animdt));
		} else if (e.getSource() == animstop) {
			animation = null;
		}
	}

	public static void main (String args[]) {
		courbelissajous1 appl = new courbelissajous1 ("Lissajous 1");
		appl.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		appl.setSize (900, 600);
		appl.setVisible (true);
	}


/**
 * fonction Lissajous sur [0, 2pi[
 */

protected class Lissajous extends Fonction2 {
	public double p = 2.0;
	public double q = 3.0;
	public double phi = 0.0;
	public double a = 1.0;
	public double b = 1.0;

	public Lissajous (double a, double b, double p, double q, double phi) {
		this.a = a;
		this.b = b;
		this.p = p;
		this.q = q;
		this.phi = phi;
	}

	public boolean defini (double t) {
		return true;
	}

	public double[] Image (double t) {
		double[] d = new double [2];

		d [0] = a * Math.sin (p * t);
		d [1] = b * Math.sin (q * t + phi);
		return d;
	}
}

}
