*warn-on-reflection*
(require '(clojure.contrib [str-utils2 :as s]))

(declare rot-message
         rot-char
         ascii-uppercase-letter-or-space?)

(defn rot-message
    "cipher a message via caesarian rotation.
     Accepts only uppercase ascii and spaces."
    [message i]
    (s/map-str #(rot-char % i) message))

;; TODO: not done. Doesn't wrap around.
(defn rot-char
    "caesar cipher function
     c - a single ascii character, A - Z
     i - the factor by which to rotate the character if letter A-Z.
           Valid values are 0 - 25"
    [c i] {:pre [(>= i 0) (< i 25) (ascii-uppercase-letter-or-space? c)]}
    (if (.equals c \space)
        c 
        (char (+ (int c) i))))

;; TODO: could use various static methods of java.lang.Character here...
(defn ascii-uppercase-letter-or-space?
    "checks if a character is an uppercase ascii letter"[c]
    (and (char? c)
         (or (.equals c \space)
             (let [compared-to-A (compare c \A)
                   compared-to-Z (compare c \Z)]
                   (or (= 0 compared-to-A)
                       (= 0 compared-to-Z)
                       (and (pos? compared-to-A) (neg? compared-to-Z)))))))