// Package middleware includes a variety of middleware for
// the servers to use, according to their configuration.
package middleware

import (
	"net/http"
	"strings"
)

// This init function registers middleware. Register middleware
// in the order they should be executed during a request.
// Middlewares execute in an order like A-B-C-C-B-A.
func init() {
	register("gzip", Gzip)
	register("header", Headers)
	register("log", RequestLog)
	register("rewrite", Rewrite)
	register("redir", Redirect)
	register("ext", Extensionless)
	register("fastcgi", FastCGI)
}

type (
	// Generator represents the outer layer of a middleware that
	// parses tokens to configure the middleware instance.
	Generator func(parser) Middleware

	// Middleware is the middle layer which represents the traditional
	// idea of middleware: it is passed the next HandlerFunc in the chain
	// and returns the inner layer, which is the actual HandlerFunc.
	Middleware func(http.HandlerFunc) http.HandlerFunc

	// parser is the type which middleware generators use to access
	// tokens and other information they need to configure the instance.
	parser interface {
		Next() bool
		NextArg() bool
		NextLine() bool
		NextBlock() bool
		Val() string
		Args(...*string) bool
		ArgErr() Middleware
		Err(string) Middleware
		Startup(func() error)
		Root() string
		Host() string
		Port() string
	}
)

var (
	// registry stores the registered middleware:
	// both the order and the directives to which they
	// are bound.
	registry = struct {
		directiveMap map[string]Generator
		order        []string
	}{
		directiveMap: make(map[string]Generator),
	}
)

// GetGenerator gets the generator function (outer layer)
// of a middleware, according to the directive passed in.
func GetGenerator(directive string) (Generator, bool) {
	rm, ok := registry.directiveMap[directive]
	return rm, ok
}

// register binds a middleware generator (outer function)
// to a directive. Upon each request, middleware will be
// executed in the order they are registered.
func register(directive string, generator Generator) {
	registry.directiveMap[directive] = generator
	registry.order = append(registry.order, directive)
}

// Ordered returns the ordered list of registered directives.
func Ordered() []string {
	return registry.order
}

// Registered returns whether or not a directive is registered.
func Registered(directive string) bool {
	_, ok := GetGenerator(directive)
	return ok
}

// Path represents a URI path, maybe with pattern characters.
type Path string

// Path matching will probably not always be a direct
// comparison; this method assures that paths can be
// easily matched.
func (p Path) Matches(other string) bool {
	return strings.HasPrefix(string(p), other)
}