   {:midje/checker true}
   [expected]
     (named 'exactly expected
-	   (fn [actual] (= expected actual))))
+           (fn [actual] (= expected actual))))
 
 
 
	:else
	[actual expected kind]))

(defn- best-seq-match-actual [comparison]
  (str "Best match found: " (pr-str (:actual-found comparison))))

(defn- best-seq-match-expected [comparison expected]
  (if (or (some extended-fn? expected)
	  (some regex? expected))
    (str "      It matched: ["
	 (apply str
		(interpose " "
			   (map #(cond (and (fn? %) (:name (meta %)))
				       (:name (meta %))

				       :else
				       (pr-str %))
				(:expected-found comparison))))
	 "] (in that order)")))
    
(defn- best-map-match-actual [comparison]
  (str "Best match found: {"
       (apply str
	      (interpose ", "
			 (sort (map (fn [[k v]] (str (pr-str k) " " (pr-str v)))
				    (:actual-found comparison)))))
       "}."))

(defn- best-map-match-expected [comparison expected]
  (if (or (some extended-fn? (vals expected))
	  (some regex? (vals expected)))
    (str "      It matched: {"
	 (apply str
		(interpose ", "
			   (sort (map (fn [[k v]]
					(cond (and (fn? v) (:name (meta v)))
					      (str (pr-str k) " " (:name (meta v)))
					      
					      :else
					      (str (pr-str k) " " (pr-str v))))
				      (:expected-found comparison)))))
	 "}.")))
    

;; TODO: try different combinations?
(defn map-comparison--one-permutation [actual expected keys]
  ;;  (prn "map-comparison" actual expected)
  (reduce (fn [so-far key]
	    ;; (println so-far key)
	    (if (and (find actual key)
		     (extended-= (get actual key) (get expected key)))
	      (merge-with merge so-far {:actual-found {key (get actual key)}
					:expected-found {key (get expected key)} })
	      so-far))
	  {:actual-found {} :expected-found {} :expected expected}
	  keys))

(defn map-comparison [actual expected kind]
  (loop [expected-permutations (all-expected-permutations (keys expected))
	 best-so-far {:actual-found [], :expected-found [],
		      :expected expected }]
    (if (empty? expected-permutations)
      best-so-far
      (let [comparison (map-comparison--one-permutation actual
							expected
							(first expected-permutations))]
	(if (total-match? comparison)
	  comparison
	  (recur (rest expected-permutations)
		 (better-of comparison best-so-far)))))))


(defn map-match? [actual expected kind]
;  (println 'map-match actual expected kind)
  (let [comparison (map-comparison actual expected kind)
	mismatch-description (fn [comparison expected]
			       (remove nil? [ (best-map-match-actual comparison)
					      (best-map-match-expected comparison expected) ]))]
    (or (total-match? comparison)
	(tag-as-chatty-falsehood
	 {
	  :notes (mismatch-description comparison expected)}))))

(defn full-sequence-match? [actual expected kind]
  (let [comparison (seq-comparison actual expected kind)
	mismatch-description (fn [comparison expected]
			       (remove nil? [ (best-seq-match-actual comparison)
					      (best-seq-match-expected comparison expected) ]))]
    (or (total-match? comparison)
	(tag-as-chatty-falsehood
	 {
	  :notes (mismatch-description comparison expected) }))))

(defn- actual-x-contains? [actual expected kind]
  ;;  (prn 'actual-x-contains? actual expected kind)
  (cond (map? actual)
	(map-match? actual expected kind)

	:else
	(full-sequence-match? actual expected kind))
  )

(defn- add-actual [actual result]

  `(with-meta
     (fn [expected# & kind#]
       (vary-meta
         (named '~name expected#
                (fn [actual#]
                  ;; (prn "checking" actual# expected# kind#)
                  (add-actual actual#
                              (try (~checker-fn actual# expected# kind#)
                                   (catch Error ex#
                                     (tag-as-chatty-falsehood {
                                                               :notes [(.getMessage ex#)]}))))))
         merge
         {:midje/chatty-checker true, :midje/checker true}))
       {:midje/checker true}))

(def contains (container-checker contains
    (fn [actual expected kind]
      (let [ [actual expected kind] (standardized-arguments actual expected kind)]
        (cond (regex? expected)
              (try-re expected actual re-find)
                 
              :else
              (apply actual-x-contains? [actual expected kind]))))))

(def just (container-checker just
    (fn [actual expected kind]
      (let [ [actual expected kind] (standardized-arguments actual expected kind)]
        (cond (regex? expected)
              (try-re expected actual re-matches)
            
              (same-lengths? actual expected)
              (apply actual-x-contains? [actual expected kind])

              :else
              (tag-as-chatty-falsehood
               {
                :notes [(cl-format nil
                                   "Expected ~R element~:P. There ~[were~;was~:;were~]~:* ~R."
                                   (count expected)
                                   (count actual))]}))))))

(defn- has-xfix [x-name pattern-fn take-fn]
  (fn [actual expected kind]
    (cond (set? actual)
          (tag-as-chatty-falsehood {
                                    :notes [(str "Sets don't have " x-name "es.")]})

          (map? actual)
          (tag-as-chatty-falsehood {
                                    :notes [(str "Maps don't have " x-name "es.")]})
          
          :else
          (let [ [actual expected kind] (standardized-arguments actual expected kind)]
            (cond (regex? expected)
                  (try-re (pattern-fn expected) actual re-find)
                  
                  (expected-fits? actual expected)
                  (apply actual-x-contains?
                         [(take-fn (count expected) actual) expected kind])

                  :else
                  (tag-as-chatty-falsehood
                   {
                    :notes [(str (cl-format nil
                                            "A collection with ~R element~:P cannot match a "
                                            (count actual))
                                 x-name
                                 (cl-format nil " of size ~R." (count expected)))]}))))))

(def has-prefix
     (container-checker has-prefix
