;; vars
(def check-until 1000000000001)
(def max-diff    (atom 0.0))
(def max-factor  (atom 0.0))
(def time-format (new java.text.SimpleDateFormat "HH:mm:ss"))


;; functions
(defn now []
  (new java.util.GregorianCalendar))

(defn give-message [message]
  (println (format "%s: %s" (. time-format format (. (now) getTime)) message)))

(defn init [type]
  (give-message (format "Start %s" type))
  (reset! max-diff   0.0)
  (reset! max-factor 0.0))

(defn main-function [i diff]
      (when (> diff @max-diff)
        (give-message (format "Different for %12d (%e, %e)" i diff (/ diff i)))
        (swap! max-diff max diff)
        (when (> (/ diff i) @max-factor)
          (swap! max-factor max (/ diff i)))))


(defn deinit [max-factor]
  (give-message (format "Stop, max-factor: %e" max-factor)))

(defn do-sequential [start stop step]
      (doseq [i (range start stop step)]
             (let [val (Math/sqrt i)
                  diff (Math/abs (- (Math/pow val 2) (* val val)))]
                  (main-function i diff))))


(defn check-concurrent []
  (init "concurrent")

  (doseq [i (range 1 check-until)]
         (let [val (Math/sqrt i)
              a1 (future (Math/pow val 2))
              a2 (future (* val val))
              diff (Math/abs (- @a1 @a2))]
              (main-function i diff)))
  (deinit @max-factor))

(defn check-concurrent2 []
  (init "concurrent2")
  (let [c1 (future (do-sequential 1 check-until 4))
       c2 (future (do-sequential 2 check-until 4))
       c3 (future (do-sequential 3 check-until 4))
       c4 (future (do-sequential 4 check-until 4))]
       @c1 @c2 @c3 @c4)
  (deinit @max-factor))

(defn check-sequential []
  (init "sequential")
  (do-sequential 1 check-until 1)
  (deinit @max-factor))


;; program
;;(check-sequential)
;;(println "\n")
;;(check-concurrent)
;;(println "\n")
(check-concurrent2)
(shutdown-agents)
