; The dynamics model that I will simulate is shown below.
; Particle 0 has contant coordinates (c0, c1).
; Particle 1 is bound by spring with particle 0,
; and moves only vertically.
; Particle 2 must have same vertical position with particle 1,
; and has constant distance c2 between particle 1.
;
;  o (x0, y0) = (c0, c1)
;  |  m0
;  |
;  <
;   >
;  < spring k[N/m]
;   >
;  |
;  |        m2 (x2, y2) = (x1+c2, y1)
;  o=========o
; (x1, y1)
;  m1
;
; Constraints of coordinates are shown below.
; They should be automatically calculated from graph data.
; x0 = c0
; y0 = c1
; x1 = c0
; y1 = q0
; x2 = c0 + c2
; y2 = q0
;
; L(w/o prime) shows Lagrangian expressed by redundant
; coordinates(x = (x0, y0, x1, y1, x2, y2)).
; L' shown Lagrangian expressed by irredundant coordinates(q = q0).
;
; L(t; x; Dx) = 1/2*m0*(Dx0^2 + Dy0^2)
;             + 1/2*m1*(Dx1^2 + Dy1^2)
;             + 1/2*m2*(Dx2^2 + Dy2^2)
;             - 1/2*k*(y0 - y1 - l)^2
;
; F(t; q) is function that transform coordinates from irredundant one(q)
; to redundant one(x).
;
; x = F(t; q) = (c0, c1, c0, q0, c0+c2, q0)
; Dx = D(F(t; q)) = D(F o gamma[q]) = (DF o gamma[q])(D gamma[q])
;    = [ d0 F o gamma[q] ] (  1 )
;      [ d1 F o gamma[q] ] ( Dq )
;    = d0 F o gamma[q] + (d1 F o gamma[1])Dq
;
; C(t; q; Dq) = (t; F(t; q); d0 F(t; q) + d1 F(t; q) * Dq)
;    (              t                )
;  = ( (c0, c1, c0,  q0, c0+c2,  q0) )
;    ( ( 0,  0,  0, Dq0,     0, Dq0) )
;
; L'(t; q; Dq) = L o C(t; q; Dq)
; = 1/2*m1*Dq0^2 + 1/2*m2*Dq0^2 - 1/2*k(c1 - q0 - l)
;
; The acceralation operator A is expressed as below;
; A = (d2 d2 L')^(-1) (d1 L' - d0 d2 L' - (d1 d2 L')Qdot)
; A(t; q; Dq) = (m1 + m2)^(-1) (k(c1 - q0 - l))

(ns anime.mass2
  (:import (java.awt Dimension Color)
           (javax.swing JFrame JPanel)))

(require 'src.math)
(alias 'mt 'src.math)

; [q0 Dq0]
(defn phys [[q0 Dq0]]
  (let [k 100, m1 0.1, m2 0.1, l 1, c0 0, c1 0, c2 0.2]
    [Dq0
     (/ (* k (- c1 q0 l))
        (+ m1 m2)
        )]))

(def xi (ref [-1.2 0]))

(defn F [q0]
  (let [c0 0, c1 0, c2 0.2]
    [c0 c1 c0 q0 (+ c0 c2) q0]
    ))

(defn coord-real-to-display [[x y]]
  [(+ 50 (* x 100))
   (+ 50 (* y -100))])

(defn anime-panel []
  (proxy [JPanel] []
    (paintComponent [g]
      (proxy-super paintComponent g)
      (.setColor g Color/BLUE)
      (let [[x0 y0 x1 y1 x2 y2] (F (nth @xi 0))
            [x0 y0] (coord-real-to-display [x0 y0])
            [x1 y1] (coord-real-to-display [x1 y1])
            [x2 y2] (coord-real-to-display [x2 y2])]
        (.fillOval g x0 y0 10 10)
        (.fillOval g x1 y1 10 10)
        (.fillOval g x2 y2 10 10)
        ))
    (getPreferredSize []
      (Dimension. 240 240)
      )))

(defn make-panel []
  (let [frame (JFrame. "mass2")
        panel (anime-panel)]
    (doto frame
      (.add panel)
      (.pack)
      (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
      (.setVisible true))
    panel))

(let [panel (make-panel)]
  (loop [i 0]
    (if (>= i 100)
      true
      (do
        (dosync
          (ref-set xi (mt/eular-implicit phys @xi 0.02 0.01))
          (println @xi)
          (.repaint panel))
        (recur (inc i))
        ))))
