             augmented-substitutions (augment-substitutions substitutions target)
             flattened-target (flatten-fake target augmented-substitutions)
             generated-fakes (generate-fakes
-                             (map-difference augmented-substitutions substitutions)
-                             overrides)]
-        [ (conj finished flattened-target)
-          (concat generated-fakes (rest pending))
-          augmented-substitutions])
-    [(conj finished target), (rest pending), substitutions])))
-  
-(defn unfold-expect-form__then__stay_put [loc]
-  (loop [ [finished pending substitutions] [ [] (zip/node loc) {} ]]
+          (map-difference augmented-substitutions substitutions)
+          overrides)]
+        [(conj finished flattened-target)
+         (concat generated-fakes (rest pending))
+         augmented-substitutions])
+      [(conj finished target), (rest pending), substitutions])))
+
+(defn- unfold-expect-form__then__stay_put [loc]
+  (loop [[finished pending substitutions] [[] (zip/node loc) {}]]
     (if (empty? pending)
       (zip/replace loc (apply list finished))
       (recur (unfolding-step finished pending substitutions)))))

;; mapping. These substitutions are used both to "flatten" a fake form and also
;; to generate new fakes.

(def special-forms '[quote fn let new])

(defn- constructor? [symbol]
  (.endsWith (name symbol) "."))

(defn- mockable-function-symbol? [symbol]
  (not (or (some #{symbol} special-forms)
           (some #{symbol} checker-makers)
           (constructor? symbol)
           (checker? (resolve symbol)))))



(defn mockable-funcall? [thing]
  (and (list? thing)
       (mockable-function-symbol? (first thing))))


(defn folded-fake? [form]
  (and (sequential? form)
       (= 'midje.semi-sweet/fake (first form))
       ;; We now know this: (fake (f ...arg... ...arg...) ...)
       (some mockable-funcall? (fake-form-funcall-arglist form))))

(defn augment-substitutions [substitutions fake-form]
  (let [needed-keys (filter mockable-funcall?
                            (fake-form-funcall-arglist fake-form))]
    (reduce (fn [substitutions needed-key]
              ;; Note: because I like for a function's metaconstants to be
              ;; easily mappable to the original fake, I don't make one

;; -*- indent-tabs-mode: nil -*-

(ns midje.internal-ideas.fakes
  (:use [utilize.seq :only (separate)]
        [midje.util.object-utils :only [object-name]]
        [clojure.test :only [report]]
        [midje.checkers :only [exactly]]
        [midje.checkers.defining :only [checker? checker-makers]]
        [midje.internal-ideas.expect :only [expect? up-to-full-expect-form]]
        [midje.util.form-utils :only [first-named?
                                      translate-zipper
                                      map-difference
                                      hash-map-duplicates-ok]]
        [midje.ideas.metaconstants :only [metaconstant-for-form
                                          with-fresh-generated-metaconstant-names]]
        [midje.checkers.extended-equality :only [extended-= extended-list-= extended-fn?]]
        [midje.internal-ideas.file-position :only [user-file-position]]
        [midje.util.thread-safe-var-nesting :only [namespace-values-inside-out
                                                   with-pushed-namespace-values
                                                   with-altered-roots]]
        [midje.util.exceptions :only [user-error]]
        [midje.internal-ideas.wrapping :only [with-wrapping-target]]
        [midje.ideas.arrow-symbols])
  (:require [clojure.zip :as zip])
  (:import midje.ideas.metaconstants.Metaconstant))

;;; Questions to ask of fakes // accessors

(defn implements-a-fake? [function]
  (:midje/faked-function (meta function)))

(defn- function-fake? [form]
  (first-named? form "fake"))

(defn- data-fake? [form]
  (first-named? form "data-fake"))

(defn fake? [form]
  (or (function-fake? form)
    (data-fake? form)))

(defn- fake-form-funcall [[fake funcall => value & overrides]]
  funcall)

(defn- fake-form-funcall-arglist [fake-form]
  (rest (fake-form-funcall fake-form)))

;;; Creation

(defn- common-to-all-fakes [var-sym]
  `{:lhs (var ~var-sym)
    :count-atom (atom 0)
    :position (user-file-position)})

(defn make-fake-map
  [var-sym special-to-fake-type user-override-pairs]
  (merge
    (common-to-all-fakes var-sym)
    special-to-fake-type
    (apply hash-map-duplicates-ok user-override-pairs)))

(defn arg-matcher-maker
  "Based on an expected value, generates a function that returns true if the 
actual value matches it."
  [expected]
  (if (and (extended-fn? expected)
        (not (checker? expected)))
    (fn [actual] (extended-= actual (exactly expected)))
    (fn [actual] (extended-= actual expected))))

(defmulti make-result-supplier (fn [arrow & _] arrow))

(defmethod make-result-supplier => [arrow result] #(identity result))

(defmethod make-result-supplier =streams=> [arrow result-stream]
  (let [current-stream (atom result-stream)]
    #(let [current-result (first @current-stream)]
       (swap! current-stream rest)
       current-result)))

(defmethod make-result-supplier :default [arrow result-stream]
  (throw (user-error (str "It's likely you misparenthesized your metaconstant prerequisite."))))

(defn fake* [[[var-sym & args :as call-form] arrow result & overrides]]
  ;; The (vec args) keeps something like (...o...) from being
  ;; evaluated as a function call later on. Right approach would
  ;; seem to be '~args. That causes spurious failures. Debug
  ;; someday.
  (make-fake-map var-sym
    `{:arg-matchers (map midje.internal-ideas.fakes/arg-matcher-maker ~(vec args))
      :call-text-for-failures (str '~call-form)
      :value-at-time-of-faking (if (bound? (var ~var-sym)) ~var-sym)
      :result-supplier (make-result-supplier ~arrow ~result)
      :type :fake}
    overrides))

(defn data-fake* [[metaconstant arrow contained & overrides]]
  (make-fake-map metaconstant
    `{:contained ~contained
      :count-atom (atom 1) ;; CLUDKJE!
      :type :fake
      :data-fake :data-fake}
    overrides))

(defn tag-as-background-fake [fake]
  (concat fake `(:background :background :times (~'range 0))))

;;; Binding


(defn- var-handled-by-fake? [function-var fake]
  (= function-var (fake :lhs )))

(defmulti ^{:private true} call-handled-by-fake? (fn [function-var actual-args fake] (:type fake)))

(defmethod ^{:private true} call-handled-by-fake? :not-called [function-var actual-args fake]
  (var-handled-by-fake? function-var fake))

(defmethod ^{:private true} call-handled-by-fake? :default [function-var actual-args fake]
  (and (var-handled-by-fake? function-var fake)
    (= (count actual-args) (count (fake :arg-matchers )))
    (extended-list-= actual-args (fake :arg-matchers ))))

(defn- fakes-for-call [fakes function-var actual-args]
  (filter (partial call-handled-by-fake? function-var actual-args) fakes))

(defn usable-default-function? [fake]
