(ns japji
  (:require [reagent.core :as r]
           [reagent.dom :as rdom]))

(declare launch-popup markup-phrase data-js)

(def recording (.getElementById js/document "japji-bindranwale"))

(def data (js->clj data-js))

(.log js/console (str "Data has " (count data) " entries"))

;; bits of Scittle stuff that need to be set up for recordStudentSound to 
;; work

(def student-recordings (atom (apply vector (repeat (count data) nil))))

(defn enable-play-button! [phrase-no])

(defn record-student-sound!
  [phrase-no]
  (.info js/console "Recording student sound for phrase " phrase-no)

  (try
    (.then (.getUserMedia (.mediaDevices js/navigator) {:audio true})
           (fn [arg]
             (let [media-recorder (js/MediaRecorder. arg)
                   audio-chunks (atom [])]
               (.start media-recorder)
               (set! (.-onerror media-recorder)
                     (fn [s]
                       (.log js/console (str "Error while recording sound: " s))))
               (.addEventListener media-recorder "dataavailable"
                                  (fn [event]
                                    (.info js/console "Audio recorded...")
                                    (swap! audio-chunks conj (.-data event))))
               (set! (.-onstop media-recorder)
                     (fn [e]
                       (js/console.log "data available after MediaRecorder.stop() called.")
                       (if (> (count @audio-chunks) 0)
                         (do
                           ;; Store the blob in the student-recordings data structure
                           (swap! student-recordings assoc phrase-no
                                  (js/Blob. (clj->js @audio-chunks)))
                           (enable-play-button! phrase-no))))))))
    (catch js/Error e
      (.log js/console
            (str "Error thrown while recording sound: " (.-message e))))
    (catch :default x
      (str "Unexpected object thrown while recording " x))))

(defn interval-watcher
  "Returns a closure over this `audio` and this `end`,
        which pauses and clears down the interval of the audio when it is 
        called after the current time of the `audio` exceeds `end`."
  [audio end]
  (fn []
    (let [audio-time (.-currentTime audio)]
      (.log js/console (str "interval: current time now "
                            audio-time "; end " end))
      (when (> audio-time end)
        (.log js/console (str "current time now "
                              (.-currentTime audio) "; end " end "; pausing recording"))
        (.pause audio)
        (.clearInterval js/window (.-int audio))))))

(defn play-segment [audio start end]
  ;; adapted from https://stackoverflow.com/questions/5932412/html5-audio-how-to-play-only-a-selected-portion-of-an-audio-file-audio-sprite
  (.log js/console (str "Playing recording from " start " to " end))
  (let [clone (.cloneNode audio true)]
    (set! (.-currentTime clone) start)
    (.log js/console (str "current time now set to " (.-currentTime clone)))
    (.play clone)
    (set! (.-int clone)
          (.setInterval js/window
                        (interval-watcher clone end)
                        10))))

(defn markup-word [record phrase-no word-no]
  [:span {:class "word, gurmukhi"
          :id (str "word-" phrase-no "-" word-no)
          :lang "pa"
          :on-click #(play-segment recording (:start record) (:end record))}
   (str " " (:text record))])

(defn close-popup []
  (let [popup (.getElementById js/document "popup")]
    (when popup
      (rdom/render "" popup))))

(def popup-control-style {:border "thin solid #331f16"
                          :padding "0 0.5em"})

(defn play-student!
  [phrase-no]
  (.play (js/Audio. (.createObjectURL js/URL (@student-recordings phrase-no)))))

(defn animate-progress-bar!
  [id duration]
  (let [progress-step (int (* duration 10))]
    (do
      (.info js/console (str "Duration is: " duration "; step is: " progress-step))
      (loop [i 1
             e (.getElementById js/document id)]
        (when (< i 99)
          (js/setTimeout
           #(do (.setAttribute e "value" i)
                (.info js/console (str "progress-width updated to " i))) (* i progress-step))
          (recur (inc i)))))))

(defn record-student! [phrase-no]
  (let [phrase-data (nth data phrase-no)
        duration (- (:lineEnd phrase-data) (:lineStart phrase-data))]
    (record-student-sound! phrase-no)
    (animate-progress-bar! "progress-bar" duration)))

(defn launch-popup [phrase-no event]
  (.log js/console (str "Launching popup for phrase " phrase-no))
  ;; OK, there's a problem here. The popup is not getting style from the 
  ;; style element, probably because it doesn't exist when the page is
  ;; initially styled; so style needs to be embedded.
  (let [popup (.getElementById js/document "popup")
        phrase-data (nth data phrase-no)
        duration (- (:lineEnd phrase-data) (:lineStart phrase-data))
        progress-width (atom 0)
        progress-step (int (* duration 10))
        content [:div {:id "popup-content"
                       :style {:border "thin solid #331f16"
                               :background-color "whitesmoke"
                               :left (- (.-pageX event) 100)
                               :top (.-pageY event)
                               :position "absolute"
                               :display "block"
                               :z-index 10}}
                 [:div {:style {:background-color "#331f16"
                                :color "red"
                                :height "1.2em"
                                :width "100%"}}
                  [:span {:id "popup-closebox" :on-click #(close-popup)
                          :title "Close popup"
                          :style {:float "right"}} "x"]]
                 (apply vector (concat [:p {:id "popup-phrase" :class "gurmukhi"}]
                                       (map #(markup-word %1 phrase-no %2) (:words phrase-data) (range))))
                 [:table {:id "popup-controls"
                          :summary "Controls for audio playback and recording"
                          :style {:border "thin solid #331f16"
                                  :padding "0.25em 1em"
                                  :width "100%"}}
                  [:tr [:td "Tutor"] [:td {:id "popup-play-tutor"
                                           :on-click #(play-segment recording
                                                                    (:lineStart phrase-data)
                                                                    (:lineEnd phrase-data))
                                           :style popup-control-style
                                           :title "Play the tutor's recording"}
                                      "►"]]
                  [:tr [:td "You"]
                   (when (@student-recordings phrase-no)
                     [:td {:id "popup-play-student"
                           :on-click #(play-student! phrase-no)
                           :style popup-control-style
                           :title "Play your own recording"} "►"])
                   [:td {:id "popup-record-stop"
                         :on-click #(record-student! phrase-no)
                         :style popup-control-style
                         :title "Record yourself saying this phrase"}
                    "⏺"]]
                  [:tr [:td {:id "progress"
                             :colspan 3}
                        [:progress {:id "progress-bar"
                                    :max 100
                                    :value 0
                                    :style {:width "100%"}}]]]]]]
    (rdom/render content popup)))

(defn markup-phrase [record n]
  [:div {:class "phrase" :id (str "phrase-" n)}
   [:span {:class "play-control" :lang "en-GB"
           :on-click #(play-segment recording (:lineStart record) (:lineEnd record))} "•"]
   (map #(markup-word %1 n %2) (:words record) (range))
   [:span {:class "popup-launcher"
           :on-click #(launch-popup n %)} "..."]])

(let [content (map markup-phrase data (range))]
  (rdom/render content (.getElementById js/document "content")))