       :request (HashPrintRequestAttributeSet. (into-array PrintRequestAttribute s))
       nil)))
 
+;; TODO: Validate attrs here?
 (defn- make-doc
   "Returns a javax.print.Doc object for the print data in this
    job map. SimpleDoc will throw an IllegalArgumentException if

;;             job (.. printer createPrintJob)]
;;         (submit spec)))))

;; TODO: Need to be able to ensure that the PrintService does not
;; process incoming jobs until it has finished processing the MultiDoc
;; (all calls to print on DocPrintJob objects dispensed by it should
;; block until the the current job signals completion/no more events).

(defn make-job
  "Returns a JobSpec map that is the result of
   assoc'ing required values to it. The values are:

   1. A SimpleDoc object (wrapped in a Delay) made from
   the map keyed at :doc.
   2. A DocPrintJob object that is retrieved from the
   PrintService.

   The following defaults are also assoc'd to the job-spec
   if no values are supplied for them:

   1. The default system printer.
   2. An attribute set with the single attribute MediaTray/MAIN.
   3. A basic PrintJobListener that prints any events that occur
   on the DocPrintJob."
  {:since "0.0.1"}
  [spec]
  (if (: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 (assoc doc :obj (make-doc doc))
                           :printer printer
                           :attrs attrs
                           :job (.. printer createPrintJob)})
            maybe-listen)))))

(defn -main [& args]
  (if (seq args)

;;  :attrs #{(Copies. 5) MediaTray/MAIN}
;;  :listener SimpleJobListener}

;; (defprotocol ISpoolable
;;   "This protocol defines a contract that states the
;;    responsibilities of any implementation that wishes
;;    to be considered 'spoolable,' which implies that it
;;    can be queued for later processing such that it is
;;    another process' resonsibility to handle the ISpoolable
;;    and block until it has been processed. For an implementation
;;    to be spoolable, it must be able to do the following:"
;;   (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 [{{obj :obj} :doc} this
;;           {:keys [^DocPrintJob job attrs]} this]
;;       (.. job (print @obj (make-set attrs :request)))))
;;   (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."))))

(defn submit [jobspec]
  (let [{{obj :obj} :doc} jobspec
        {:keys [^DocPrintJob job attrs]}jobspec]
    (.. job (print @obj (make-set attrs :request)))))

(defn add-listener [jobspec listener]
    (if-let [{^DocPrintJob job :job} jobspec]
      (do (doto job (.addPrintJobListener listener))
          (assoc jobspec :listener listener))
      (throw IllegalStateException "No DocPrintJob keyed at :job.")))

;; (defn job-seq [job-map]
;;   (let [{docs :docs ^PrintService printer :printer} job-map]
;;     (for [d docs]
;;       [(make-doc d) (.. printer createPrintJob)])))

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