                        (fnil str/lower-case "")
                        :manufacturer))))
 
+(defn levenshtein
+  "Computes the Levenshtein distance between two sequences."
+  [c1 c2]
+  (let [lev-next-row
+        (fn [previous current]
+            (reduce
+              (fn [row [diagonal above other]]
+                (let [update-val (if (= other current)
+                                   diagonal
+                                   (inc (min diagonal above (peek row))))]
+                  (conj row update-val)))
+              [(inc (first previous))]
+              (map vector previous (next previous) c2)))]
+      (peek
+        (reduce lev-next-row
+                (range (inc (count c2)))
+                c1))))
 
 (def manufacturer-matchers
   [(fn first-word? [manufacturers candidate]

  (:require [clojure.java.io :as io] 
            [clojure.string :as str]
            [cheshire.core :as json]
            [clj-fuzzy.metrics :refer [levenshtein]]
            [taoensso.timbre :as timbre]
            [taoensso.timbre.profiling :as p])
  (:gen-class))

(p/defnp match-listing
  "Attempts to match listing to a product in products, returning a vector
  [matching-product listing] if successful, else nil."
  [products manufacturer-matcher listing]
  (when-let [manufacturer-guess
             (p/p :match-manuf (match-manufacturer manufacturer-matcher
                                                   (or (:manufacturer listing)
                                                       (first-word (:title listing)))))]
    (if-let [product-guess
             (p/p :match-title (match-title (products manufacturer-guess)
                                            (:title listing)))]
      [product-guess listing]
      [nil listing])))

