 (defprotocol ICalendarValue
   (serialize-value [_] ""))
 
-(def DATE-PATTERN (java.time.format.DateTimeFormatter/ofPattern "YYYYMMdd"))
-
-(def DATE-TIME-FORM-1-PATTERN (java.time.format.DateTimeFormatter/ofPattern "YYYYMMdd'T'HHmmss"))
+(def DATE-TIME-FORM-1-PATTERN (DateTimeFormatter/ofPattern "YYYYMMdd'T'HHmmss"))
 
 ;; Only call with ZoneID of UTC otherwise produces invalid ICAL format
-(def DATE-TIME-FORM-2-PATTERN (java.time.format.DateTimeFormatter/ofPattern "YYYYMMdd'T'HHmmssX"))
-
-(def DATE-TIME-FORM-3-PATTERN (java.time.format.DateTimeFormatter/ofPattern "YYYYMMdd'T'HHmmss"))
+(def DATE-TIME-FORM-2-PATTERN (DateTimeFormatter/ofPattern "YYYYMMdd'T'HHmmssX"))
+
+(def DATE-TIME-FORM-3-PATTERN (DateTimeFormatter/ofPattern "YYYYMMdd'T'HHmmss"))
 
 (extend-protocol ICalendarValue
   String

   [tick.core :as t]
   )
  (:import
   [java.time Instant LocalDate LocalDateTime ZonedDateTime ZoneId]))

;; Have considered wrapping ical4j. However, since ical4j does not
;; use Java 8 time (as of the time of writing), any appeals to


(defmethod add-contentline-to-model "END"
  [acc contentline]
  ;; END means place the current object in the stack, and start a new
  ;; one
  (let [curr-object (instantiate (:curr-object acc))
        restore-object (some-> (:stack acc) last) ; check if nil, bad state
        restore-object (update restore-object :subobjects (fnil conj []) curr-object)]
    (-> acc
        (assoc :curr-object restore-object
               :stack (vec (butlast (:stack acc)))))))

(defmulti coerce-to-value (fn [value-type value] value-type))
(defmethod coerce-to-value "DATE" [_ value] (LocalDate/parse value DateTimeFormatter/BASIC_ISO_DATE))
(defmethod coerce-to-value nil [_ value] value)

(defn add-property [acc contentline]
  (update-in
    acc [:curr-object :properties] (fnil conj [])
    (update contentline
            :value
            #(coerce-to-value (get-in contentline [:params "VALUE"]) %))))

(defmethod add-contentline-to-model :default
  [acc contentline]
  (add-property acc contentline))

(defn parse-icalendar [^java.io.BufferedReader r]
  (->> r
       unfolding-line-seq
       (map line->contentline)
       (map-indexed (fn [n o] (assoc o :lineno (inc n))))
       (reduce add-contentline-to-model {})
       :curr-object
       :subobjects))

(defn property [obj prop-name]
  (filter #(= (:name %) (str/upper-case (name prop-name))) (:properties obj)))

;; Now individual calendar sources

(defn bank-holidays-in-england-and-wales [] nil)

(defn events
  "Given a vcalendar object, return only the events"
  [vcalendar]
  (filter #(= "VEVENT" (:object %)) (:subobjects vcalendar)))

#_(parse-icalendar (io/reader (io/file "test.ics")))

#_(parse-icalendar (io/reader (io/resource "ics/gov.uk/england-and-wales.ics")))

#_(events (first (parse-icalendar (io/reader (io/resource "ics/gov.uk/england-and-wales.ics")))))
