;;
;; Copyright 2010-2015 Mikhail Kryshen <mikhail@kryshen.net>
;;
;; This file is part of Indyvon.
;;
;; Indyvon is free software: you can redistribute it and/or modify it
;; under the terms of the GNU Lesser General Public License version 3
;; only, as published by the Free Software Foundation.
;;
;; Indyvon is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Lesser General Public License for more details.
;;
;; You should have received a copy of the GNU Lesser General Public
;; License along with Indyvon.  If not, see
;; <http://www.gnu.org/licenses/>.
;;

(ns indyvon.component
  "Integrating Indyvon into AWT and Swing components."
  (:use
   indyvon.core)
  (:import
   (java.awt Graphics Component Dimension Color EventQueue)
   (java.awt.geom Rectangle2D$Double)
   (javax.swing JFrame JPanel JOptionPane)))

(defn- paint-component [^Component c ^Graphics g scene]
  (let [w (.getWidth c)
        h (.getHeight c)]
    (.setColor g (theme-get :back-color))
    (.fillRect g 0 0 w h)
    (draw-scene! scene g w h)))

(defn- preferred-size [^Component c scene]
  (let [geom (scene-geometry scene)]
    (Dimension. (width geom) (height geom))))

(defn ^JPanel make-jpanel
  "Creates a JPanel to display the specified View."
  ([view]
     (make-jpanel view (root-event-dispatcher)))
  ([view event-dispatcher]
     (let [panel (proxy [JPanel] [])
           scene (make-scene
                  view event-dispatcher panel
                  (.getDesktopProperty (java.awt.Toolkit/getDefaultToolkit)
                                       "awt.font.desktophints"))]
       (update-proxy
        panel
        {"paintComponent" #(paint-component %1 %2 scene)
         "getPreferredSize" #(preferred-size % scene)})
       (.setBackground panel (theme-get :back-color))
       (add-observer! panel scene (fn [w _]
                                    ;; Use the first observer argument
                                    ;; instead of closing over panel to
                                    ;; allow the panel and associated
                                    ;; observer to be gc'd.
                                    (.repaint ^Component w)))
       (listen! event-dispatcher panel)
       panel)))

(defn ^JFrame make-jframe
  "Creates a JFrame to display the specified View."
  [^String title view]
  (doto (JFrame. title)
    (.. (getContentPane) (add (make-jpanel view)))
    (.pack)))

(defn ^JFrame show-view!
  "Creates and shows a JFrame with the specified View."
  ([view]
     (show-view! "Indyvon" view))
  ([title view]
     (let [f (atom nil)]
       (EventQueue/invokeAndWait
        #(doto ^JFrame (reset! f (make-jframe title view))
           (.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)
           (.setVisible true)))
       @f)))

(defn message [m]
  (JOptionPane/showMessageDialog (:component *scene*) m))