/*08-07-98 modifié le 30/09/99
 * adapté jdk 1.2 le 7/03/09
 * j.-p. quelen
 * modifié le 18/12/17 ajout de main()
 * modification 03/02/21
 */

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;


public class ressort extends JPanel implements Runnable {
  static final long serialVersionUID = 210203L;
  commandes cmd;
  dessin d;
  courbe c;
  Thread trace;

  public void init() {
	setFont (new Font ("Arial", Font.PLAIN, 10));
  	setLayout (new BorderLayout ());
    cmd = new commandes ();
    d = new dessin (cmd, getSize().height);
    c = new courbe (cmd, d);
    add (cmd, BorderLayout.NORTH);
    add (d, BorderLayout.WEST);
    add (c, BorderLayout.CENTER);
    trace = new Thread (this);
    trace.start ();
  }

  public void run ()
  { while (true)
    { d.repaint ();
    	c.repaint ();
      if (! d.deplace)
      { if (cmd.l < cmd.limit) { cmd.l = cmd.limit; cmd.lp = 0.0; }
        cmd.ls = cmd.g + cmd.ksm * (cmd.l0 - cmd.l) - cmd.amort * cmd.lp;
        cmd.lp += cmd.ls * cmd.dt;
        cmd.l += cmd.lp * cmd.dt;
      }
      try { Thread.sleep (cmd.tempo); }
      catch (InterruptedException e) { }
    }
  }
////////////////////////////////////////////////////////////////////////////////
protected class commandes extends Panel implements ActionListener {
	static final long serialVersionUID = 210203L;
  double g, k, dt, ksm, lr, l0, m, l, lp, ls, limit, amort, amortsl, gsl;
  int tempo;  
  TextField tfdt, tfk, tm, tamort, ttempo;
  Button ok;

  private void ajoutlbl (String s)
  { Label lbl = new Label (s);
    lbl.setBackground (Color.lightGray);
    add (lbl);
  } 

  private TextField ajouttf (String s)
  { TextField tf = new TextField (s, 5);
    add (tf);
    return tf;
  }

  public commandes ()
  { setLayout (new FlowLayout ());
    setBackground (Color.lightGray);
    ajoutlbl ("k = ");
    tfk = ajouttf ("20.0");
    k = 20.0;
    ajoutlbl ("dt = ");
    tfdt = ajouttf ("0.014");
    add (tfdt);
    dt = 0.014;
    ajoutlbl ("m = ");
    tm = ajouttf ("1.0");
    add (tm);
    m = 1.0;
    ajoutlbl ("amort. = ");
    tamort = ajouttf ("0.2");
    add (tamort);
    amort = 0.2;
    ajoutlbl ("tempo = ");
    ttempo = ajouttf ("10");
    ok = new Button ("Ok");
    ok.addActionListener (this);
    add (ok);
    tempo = 10;
    g = 9.81;
    ksm = k / m;
    l0 = 1.0; limit = 0.1;
    l = l0 + g / ksm;
    lp = 0.0;
  }

  private double sd (String s, double d) {
	try {
	  d = Double.parseDouble (s);
	}
    catch (NumberFormatException nfe) { }
    return d;
  }

  private int si (String s, int i)
  { try {i = Integer.parseInt (s); }
    catch (NumberFormatException nfe) { }
    return i;
  }

  public void actionPerformed (ActionEvent e)
  { if (e.getSource () == ok)
	  { k = Math.abs (sd (tfk.getText (), k));
      tfk.setText (Double.toString (k));
      dt = Math.abs (sd (tfdt.getText (), dt));
      tfdt.setText (Double.toString (dt));
      m = Math.abs (sd (tm.getText (), m));
      tm.setText (Double.toString (m));
      amort = Math.abs (sd (tamort.getText (), amort));
      tamort.setText (Double.toString (amort));
      amortsl = amort / l; gsl = 9.81 / l;
      tempo = Math.abs (si (ttempo.getText (), tempo));
      ttempo.setText (Integer.toString (tempo));
      ksm = k / m;
      lp = 0.0;
    }
  }
}
////////////////////////////////////////////////////////////////////////////////
protected class dessin extends Canvas implements MouseListener, MouseMotionListener {
	static final long serialVersionUID = 210203L;
  commandes cmd;
  Image img;
  Graphics g;
  boolean deplace;
  int XMAX, YMAX, X0, Y0, L, ECH, Y;

  public dessin (commandes cmd, int H)
  { this.cmd = cmd;
    addMouseMotionListener (this);
    addMouseListener (this);
    setSize (100, H);
  }

  public void update (Graphics g1)
  { paint (g1); }

  public void paint (Graphics g1)
  { if (img == null || YMAX != getSize().height - 1 || XMAX != getSize().width - 1)
    { img = createImage (getSize().width, getSize().height);
      g = img.getGraphics ();
      YMAX = getSize().height - 1;
      XMAX = getSize().width - 1;
      X0 = 50; Y0 = 50; ECH = 100;
    }
    L = (int) (cmd.l * ECH);
    g.setColor (Color.white);
    g.fillRect (0, 0, XMAX, YMAX);
    g.setColor (Color.blue);
    g.fillRect (X0 - 2, Y0 - 12, 5, 5);
    g.drawLine (X0, Y0 - 10, X0, Y0);
    g.drawLine (X0, Y0 + L, X0, Y0 + L + 10);
    g.drawOval (X0 - 20, Y0 + L + 10, 40, 40);
    g.setColor (Color.green);
    g.drawRect (X0 - 10, Y0, 20, L);
    g.setColor (Color.black);
    g.drawRect (0, 0, XMAX, YMAX);

    g1.drawImage (img, 0, 0, this);
  }

//----attrape la boule suspendue au ressort

  public void mousePressed (MouseEvent e)
  { e.consume ();
    deplace = (e.getX () >=  X0 - 20) && (e.getX () <= X0 + 20)
              && (e.getY () >= Y0 + L) && (e.getY () <= Y0 + L + 50);
  }

//----déplace cette boule

  public void mouseDragged (MouseEvent e)
  { e.consume ();
    if (deplace)
    { L = e.getY () - Y0 - 30;
      cmd.l = (double) (L) / ECH;
      if (cmd.l < cmd.limit) cmd.l = cmd.limit;
    }
  }

//----lache la boule -> début du mouvement

  public void mouseReleased (MouseEvent e)
  { e.consume ();
    deplace = false;
  }

  public void mouseMoved (MouseEvent e) { }
  public void mouseClicked (MouseEvent e) { }
  public void mouseEntered (MouseEvent e) { }
  public void mouseExited (MouseEvent e) { }

}
////////////////////////////////////////////////////////////////////////////////
protected class courbe extends Canvas {
	static final long serialVersionUID = 210203L;
  commandes cmd;
  dessin d;
  int XMAX, YMAX, T;

  public courbe (commandes cmd, dessin d) {
	this.cmd = cmd;
    this.d = d;
    repaint();
  }

  public void update (Graphics g)
  { paint (g); }

  public void paint (Graphics g)
  { if (XMAX != getSize().width - 1 || YMAX != getSize().height - 1)
    { XMAX = getSize().width - 1;
      YMAX = getSize().height - 1;
      T = XMAX;
    }
    if (T == XMAX)
    { T = 0;
      g.setColor (Color.lightGray);
      g.fillRect (0, 0, XMAX, YMAX);
      g.setColor (Color.red);
      int Y0 = 80 + (int)((cmd.l0 + cmd.g /cmd.ksm) * d.ECH);
      g.drawLine (0, Y0, XMAX, Y0);
    }
    g.fillRect (T ++, 80 + (int)(cmd.l * d.ECH), 1, 1);
  }

}
////////////////////////////////////////////////////////////////////////////////

  public static void main (String [] args) {
	int w = 600;
	int h = 600;

	ressort r = new ressort();
	r.init();

	JFrame f = new JFrame ("Mouvement du ressort");
	f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
	f.add (r);
	f.setSize (w, h);
	f.setVisible (true);
  }

}
