-----------------------------------------------------------------------------
-- Xavante URL rules handler
--
-- Authors: Javier Guerra and Fabio Mascarenhas
-- Copyright (c) 2006-2007 Kepler Project
--
-- $Id: ruleshandler.lua,v 1.2 2007/08/20 22:20:44 carregal Exp $
-----------------------------------------------------------------------------

local httpd = require "xavante.httpd"

-- this is a coroutine-based iterator:
-- path_perputer takes a path and yields once for each handler key to try
--              first is the full path
--              next, anything with the same extension on the same directory
--              next, anything on the directory
--              strips the last subdirectory from the path, and repeats the last two patterns
--              for example, if the query was /first/second/file.ext , tries:
--                      /first/second/file.ext
--                      /first/second/*.ext
--                      /first/second/*
--                      /first/*.ext
--                      /first/*
--                      /*.ext
--                      /*
--              and, if the query was for a directory like /first/second/last/ , it tries:
--                      /first/second/last/
--                      /first/second/
--                      /first/
--                      /
local function path_permuter (path)
        coroutine.yield (path)
        local _,_,ext = string.find (path, "%.([^./]*)$")
        local notdir = (string.sub (path, -1) ~= "/")

        while path ~= "" do
                path = string.gsub (path, "/[^/]*$", "")
                if notdir then
                        if ext then
                                coroutine.yield (path .."/*."..ext)
                        end
                        coroutine.yield (path .."/*")
                else
                        coroutine.yield (path.."/")
                end
        end
end

-- given a path, returns an iterator to traverse all permutations
local function path_iterator (path)
        return coroutine.wrap (function () path_permuter (path) end)
end

-- parses the url, and gets the appropiate handler function
-- starts with the full path, and goes up to the root
-- until it finds a handler for the request method
local function match_url (req, conf)
        local path = req.relpath
        local h, set
        for p in path_iterator (path) do
                h = conf [p]
                if h then
                        req.match = p
                        break
                end
        end

        if req.match then
                local _,_,pfx = string.find (req.match, "^(.*/)[^/]-$")
                assert (string.sub (path, 1, string.len (pfx)) == pfx)
                req.relpath = string.sub (path, string.len (pfx)+1)
        end
        req.handler = h
end

return function (conf)
         if not conf or type (conf) ~= "table" then return nil end

         return function (req, res)
                  match_url (req, conf)
                  local h = req.handler or httpd.err_404
                  return h (req, res)
                end
       end

