(ns cc.journeyman.the-great-game.world.routes
  "Conceptual (plan level) routes, represented as tuples of location ids."
  (:require [cc.journeyman.the-great-game.utils :refer [cyclic?]]))

(defn find-routes
  "Find routes from among these `routes` from `from`; if `to` is supplied,
  to `to`, by breadth-first search."
  ([routes from]
   (map
     (fn [to] (cons from to))
     (remove
       empty?
       (map
         (fn [route]
           (remove
             #(= from %)
             (if (some #(= % from) route) route)))
         routes))))
  ([routes from to]
   (let [steps (find-routes routes from)
         found (filter
                 (fn [step] (if (some #(= to %) step) step))
                 steps)]
     (if
       (empty? found)
       (find-routes routes from to steps)
       found)))
  ([routes from to steps]
   (if
     (not (empty? steps))
     (let [paths (remove
                   cyclic?
                   (mapcat
                       (fn [path]
                         (map
                           (fn [x] (concat path (rest x)))
                           (find-routes routes (last path))))
                       steps))
           found (filter
                   #(= (last %) to) paths)]
       (if
         (empty? found)
         (find-routes routes from to paths)
         found)))))

(defn find-route
  "Find a single route from `from` to `to` in this `world-or-routes`, which
  may be either a world as defined in [[the-great-game.world.world]] or else
  a sequence of tuples of keywords."
  [world-or-routes from to]
  (first
    (find-routes
      (or (:routes world-or-routes) world-or-routes)
      from
      to)))
