 
 (defn height-of-lower-neighbors [node]
   (let [lowers (lower-neighbors node)]
-    (if (not lowers)
+    (if (empty? lowers)
       nil
-      (reduce min (map (fn [conn] ((start-of-connection conn) 1)) lowers)))))
+      (reduce min (map (fn [node]
+			 ((position node) 1))
+		       lowers)))))
 
 (defn height-of-upper-neighbors [node]
   (let [uppers (upper-neighbors node)]
-    (if (not uppers)
+    (if (empty? uppers)
       nil
-      (reduce max (map (fn [node] ((end-of-connection node) 1)) uppers)))))
+      (reduce max (map (fn [node] 
+			 ((position node) 1))
+		       uppers)))))
 
 (defn move-node-by [node dx dy] ; race condition when move nodes too fast?
   (let [[x y] (position node)
-	max-y (height-of-lower-neighbors node)
-	min-y (height-of-upper-neighbors node)
+
+	; make sure nodes don't go too far
+	max-y (height-of-upper-neighbors node)
+	min-y (height-of-lower-neighbors node)
 	dy    (if max-y (min dy (- max-y y)) dy)
 	dy    (if min-y (max dy (- min-y y)) dy)
+
 	[new-x new-y] [(+ x dx) (+ y dy)]]
-    (doseq [segment (.getSegments node)]
-      (.translate segment dx dy))
-    (doseq [c (upper-neighbors node)]
-      (let [c (.getSegment c)
-	    c1 (aget (.getX c) 0)
-	    c2 (aget (.getY c) 0)
-	    d1 (aget (.getX c) 1)
-	    d2 (aget (.getY c) 1)]
-	(.setGeometry c (+ c1 dx) (+ c2 dy) d1 d2)))
-    (doseq [c (lower-neighbors node)]
-      (let [c (.getSegment c)
-	    c1 (aget (.getX c) 0)
-	    c2 (aget (.getY c) 0)
-	    d1 (aget (.getX c) 1)
-	    d2 (aget (.getY c) 1)]
-	(.setGeometry c c1 c2 (+ d1 dx) (+ d2 dy))))
+
+    ; move nodes on the device
+    (let [[dx-1 dy-1] (world-to-device scn dx dy)
+	  [zx zy]     (world-to-device scn 0 0)
+	  device-dx   (- dx-1 zx)
+	  device-dy   (- dy-1 zy)]
+      (doseq [segment (.getSegments node)]
+	(.translate segment device-dx device-dy)))
+
+    ; update self position
     (dosync
      (alter (.getUserData node) assoc :position [new-x new-y]))
+
+    ; update connections to upper neighbors
+    (doseq [c (upper-connections node)]
+      (.redraw c))
+
+    ; update connections to lower neighbors
+    (doseq [c (lower-connections node)]
+      (.redraw c))
+
+    ; done
     [new-x new-y]))
 
 (defn move-node-to [node x y]

	   [no.geosoft.cc.graphics GWindow GScene GObject ZoomInteraction GSegment GStyle
	                           GText GPosition GScene GInteraction]))

;;; nodes and connections

(defn node? [thing]

(defn position [node]
  (:position @(.getUserData node)))

(defn lower-node [conn]
  (:lower @(.getUserData conn)))

(defn upper-node [conn]
  (:upper @(.getUserData conn)))

(defn upper-connections [node]
  (:upper @(.getUserData node)))

(defn lower-connections [node]
  (:lower @(.getUserData node)))

(defn upper-neighbors [node]
  (map upper-node (upper-connections node)))

(defn lower-neighbors [node]
  (map lower-node (lower-connections node)))


;;; create and connect nodes

(defn add-node [scn x y]
  (let [segment (GSegment.)
	object (proxy [GObject] []
		 (draw []
		   (let [[x y] (position this)]
		     (.setGeometryXy segment (Geometry/createCircle (double x) (double y) 10.0)))))
	style (GStyle.)]
    (.addSegment object segment)
    (doto style
      (.setForegroundColor (Color.  6  6 86))
      (.setBackgroundColor (Color. 23 11 84)))
    (.setStyle segment style)
    (.setUserData object (ref {:type :node,
			       :position [x y]}))
    (.setName object (str [x y]))
    (.add scn object)
    object))

(defn connect-nodes [scn x y]
  (let [line (GSegment.)
	c       (proxy [GObject] []
		  (draw []
		    (let [[x1 y1] (position (lower-node this))
			  [x2 y2] (position (upper-node this))]
		      (.setGeometry line (double x1) (double y1) (double x2) (double y2)))))]
    (.add scn c)
    (.addSegment c line)
    (.toBack c)
    (.setUserData c (ref {:type :connection,
			  :lower x,
			  :upper y}))
    (dosync
     (alter (.getUserData x) update-in [:upper] conj c)
     (alter (.getUserData y) update-in [:lower] conj c))))
