              (valid-attrs? attrs :job))
       (letfn [(add-doc [doc-map]
                 (assoc-in doc-map [:obj] (delay (make-doc doc-map))))
-              (add-docs [m]
-                (update-in m [:docs] (fn [doc-list] (map add-doc  doc-list))))
-              (add-jobs [m]
-                (assoc-in m [:jobs] (for [d docs] (.. printer createPrintJob))))]
-        (-> spec add-docs add-jobs)))))
+              (add-docs [spec]
+                (update-in spec [:docs] (fn [doc-list] (map add-doc  doc-list))))
+              (add-jobs [spec]
+                (assoc-in spec [:jobs] (for [doc docs] (.. printer createPrintJob))))]
+        (-> spec add-docs add-jobs map->MultiJobSpec)))))
 
 ;; (defn make-job
 ;;   "Returns a JobSpec map that is the result of

          :attrs #{MediaTray/MAIN}
          :listener (listeners/basic-listener)})

(defprotocol ISpoolable
  (submit [this]) ;; Submit the job 
  (add-listener [this listener])) ;; Attach an event listener that
                                  ;; returns a value when the process is complete
(defrecord JobSpec [doc printer job attrs]
  ISpoolable
  (submit [this]
    (let [doc-obj (make-doc doc)
          {:keys [^DocPrintJob job attrs]} this
          attr-set (make-set attrs :request)]
      (.. job (print doc-obj attr-set))))
  (add-listener [this listener]
    (if-let [{^DocPrintJob job :job} this]
      (do (doto job (.addPrintJobListener listener))
          (assoc this :listener listener))
      (throw IllegalStateException "No DocPrintJob keyed at :job."))))

(defrecord MultiJobSpec [docs printer jobs attrs]
  ISpoolable
  (submit [this]
    (let [{:keys [docs jobs]} this
          doc-objs (map :obj docs)]
      (map (fn [d j] (.. j (print @d (make-set attrs :request)))) doc-objs jobs))) ;; TODO: reflection
  ;; (add-listener [this listener]
  ;;   (if-let [{^DocPrintJob job :job} this]
  ;;     (do (doto job (.addPrintJobListener listener))
  ;;         (assoc this :listener listener))
  ;;     (throw IllegalStateException "No DocPrintJob keyed at :job.")))
  )

;; TODO: SEE http://oobaloo.co.uk/clojure-from-callbacks-to-sequences!!!

(defmulti make-job
  "Dispatch on which key is present in the spec map."
  (fn [spec] (apply (some-fn #{:doc} #{:docs}) (keys spec))))

(defmethod make-job :doc [spec]
  (let [{{doc-attrs :attrs} :doc} spec
        {:keys [doc ^PrintService printer attrs ^PrintJobtListener listener]
         :or {printer (printer :default)
              attrs #{MediaTray/MAIN}}} spec
              maybe-listen #(if listener (add-listener % listener) %)]
    (if  (and (valid-attrs? doc-attrs :doc)
             (valid-attrs? attrs :job))
      (-> (map->JobSpec {:doc doc
                         :printer printer
                         :attrs attrs
                         :job (.. printer createPrintJob)})
          maybe-listen))))

(defmethod make-job :docs [spec]
  (let [{:keys [^PrintService printer

      :author "Roberto Acevedo"}
  clj-print.core
  (:require [clj-print [doc-flavors :as flavors]
             [listeners :as listeners]]
            [clojure.java [io :as io]]
            [clojure.pprint :refer [pprint]]
            [taoensso.timbre :as timbre])
