 (ns multicodec.codecs.mux
-  "Multiplexing codec which uses a set of iternal functions to decide which
-  codec to use when encoding or decoding data.
+  "Multiplexing codec which uses the codec predicates `encodable?` and
+  `decodable?` to decide which codec to use when encoding or decoding data.
 
-  - `codecs` is a map from keys to codecs.
-  - `select-encoder` takes the collection of codecs and the value to be encoded
-    and returns a key identifying the codec to write the value with.
-  - `select-decoder` takes the collection of codecs and the header path and
-    returns a key identifying the codec to read the value with.
+  `codecs` should be a map from (arbitrary) keys to codecs with headers and
+  support for the codec predicates.
 
-  By default, the selection functions will look for codecs which can encode and
-  decode the values and headers passed to the mux codec."
+  The actual codec delegated to can be determined by binding
+  `*dispatched-codec*` to `nil` and checking the result after an operation."
   (:require
     [multicodec.core :as codec]
     [multicodec.header :as header]
     [multicodec.codecs.wrap :as wrap]))
 
 
-(defn find-encodable
-  "Finds a codec in the map which can encode the given value. Returns the key
-  for the codec, or nil if none are found."
+(defn- find-encodable
+  "Finds the first codec in the map which can encode the given value. Returns a
+  vector of the key and codec entry, or nil if none are found."
   [codecs value]
-  (ffirst (filter #(codec/encodable? (val %) value) codecs)))
+  (first (filter #(codec/encodable? (val %) value) codecs)))
 
 
-(defn find-decodable
-  "Finds a codec in the map which can decode the given header. Returns the key
-  for the codec, or nil if none are found."
+(defn- find-decodable
+  "Finds the first codec in the map which can decode the given header. Returns
+  a vector of the key and codec entry, or nil if none are found."
   [codecs header]
-  (ffirst (filter #(codec/decodable? (val %) header) codecs)))
-
-
-(defn- resolve-codec!
-  "Returns the selected codec, if it exists. Otherwise, throws an exception."
-  [codecs selected value]
-  (when-not selected
-    (throw (ex-info
-             (str "No codec selected for: " (pr-str value))
-             {:codecs (keys codecs)
-              :value value})))
-  (when-not (get codecs selected)
-    (throw (ex-info
-             (str "Selected codec " selected " which is not present in"
-                  " the codec map " (pr-str (seq (keys codecs)))
-                  " for: " (pr-str value))
-             {:codecs (keys codecs)
-              :selected selected
-              :value value})))
-  (get codecs selected))
+  (first (filter #(codec/decodable? (val %) header) codecs)))
 
 
 



(defrecord MuxCodec
  [header codecs select-encoder select-decoder]

  codec/Encoder

  (encodable?
    [this value]
    (boolean (when-let [codec (get codecs (select-encoder codecs value))]
               (codec/encodable? codec value))))


  (encode!
    [this output value]
    (let [codec-key (select-encoder codecs value)
          codec (resolve-codec! codecs codec-key value)]
      (when (bound? #'*dispatched-codec*)
        (set! *dispatched-codec* codec-key))
      (wrap/write-header-encoded! codec output (:header codec) value)))


      (throw (IllegalArgumentException.
               (str "Every codec must specify a header path: "
                    (pr-str bad-codecs)))))
    (MuxCodec. "/multicodec" codec-map)))


;; Remove automatic constructor functions.
