;;  Copyright (c) Jason Wolfe. All rights reserved.  The use and
;;  distribution terms for this software are covered by the Eclipse Public
;;  License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
;;  be found in the file epl-v10.html at the root of this distribution.  By
;;  using this software in any fashion, you are agreeing to be bound by the
;;  terms of this license.  You must not remove this notice, or any other,
;;  from this software.
;;
;;  map_utils.clj
;;
;;  Utilities for operating on Clojure maps.
;;
;;  jason at w01fe dot com
;;  Created 25 Feb 2009

(ns 
  #^{:author "Jason Wolfe, Chris Houser",
     :doc "Utilities for operating on Clojure maps."}
  clojure.contrib.map-utils)


(defmacro lazy-get 
  "Like get, but doesn't evaluate not-found unless it is needed."
  [map key not-found]
  `(if-let [pair# (find ~map ~key)] 
       (val pair#)
     ~not-found))

(defn safe-get 
  "Like get, but throws an exception if the key is not found."
  [map key] 
  (lazy-get map key 
   (throw (IllegalArgumentException. (format "Key %s not found in %s" key map)))))

(defn safe-get-in 
  "Like get-in, but throws an exception if any key is not found."
  [map ks]
  (reduce safe-get map ks))

; by Chouser:
(defn deep-merge-with
  "Like merge-with, but merges maps recursively, applying the given fn
  only when there's a non-map at a particular level.

  (deepmerge + {:a {:b {:c 1 :d {:x 1 :y 2}} :e 3} :f 4}
               {:a {:b {:c 2 :d {:z 9} :z 3} :e 100}})
  -> {:a {:b {:z 3, :c 3, :d {:z 9, :x 1, :y 2}}, :e 103}, :f 4}"
  [f & maps]
  (apply
    (fn m [& maps]
      (if (every? map? maps)
        (apply merge-with m maps)
        (apply f maps)))
    maps))

