require 'rack'

if ARGV.size > 0 then
  Dir.chdir ARGV[0]
end

def add_server(dir)
  def read_field (dir, field, default)
    file = File.join(dir, field)
    if File.exists? file then
      File.open(file).read.chomp
    else
      default
    end
  end

  return [{
    :path   => read_field(dir, "path", "*"),
    :domain => read_field(dir, "domain", "*"),
    :host   => read_field(dir, "host", "localhost"),
    :port   => read_field(dir, "port", "80"),
    :mode   => read_field(dir, "mode", "http"),
    :path   => read_field(dir, "path", "/dev/null"),
   }]
end

def match(spec, str)
  stack = [[0,0]]
  while not stack.empty? do
    i, j = stack.pop
    if i >= spec.size and j >= str.size then
      return true
    elsif i >= spec.size or j >= str.size then
      next
    elsif spec[i] == '*' then
      stack.push([ i, j+1 ])
      stack.push([ i+1, j+1 ])
    elsif spec[i] == str[j] then
      stack.push([ i+1, j+1 ])
    end
  end
  return false
end

def init_paths
  ss = Dir.new(Dir.pwd).sort.map do |f|
    unless f.start_with? "." then
      add_server(f)
    else
      []
    end
  end
  return ss.flatten
end

def find_server(env, paths)
  paths.each do |s|
    if match(s[:path], env['PATH_INFO']) and match(s[:domain], env['SERVER_NAME']) then
      if s[:mode] == "http" then
        return [ 200, { 'Content-Type' => 'text/html'},
                 [ "Forwarding to #{s[:mode]}://#{s[:host]}:#{s[:port]}" ] ]
      elsif s[:mode] == "aloys" then
        return [ 200, { 'Content-Type' => 'text/html'}
                 [ "Deferring to aloys dir at #{s[:path]}" ] ]
      end
    end
  end
  return [ 500, { 'Content-Type' => 'text/html' },
           [ "Unable to find server to forward to" ] ]
end

def serve_paths(paths)
  app = Proc.new do |env|
    find_server(env, paths)
  end
  Rack::Handler::WEBrick.run app
end

serve_paths(init_paths)
