package vox

import (
	"net/http"
)

// An Application is a container which includes middlewares and config, and implemented the GO's net/http.Handler interface https://golang.org/pkg/net/http/#Handler.
type Application struct {
	middlewares []Handler
	configs     map[string]string
}

// New returns a new vox Application.
func New() *Application {
	app := &Application{
		middlewares: []Handler{logging, respond},
		configs:     map[string]string{},
	}
	return app
}

// Use a vox middleware.
func (app *Application) Use(handler Handler) {
	app.middlewares = append(app.middlewares, handler)
}

// SetConfig sets an application level variable.
func (app *Application) SetConfig(key, value string) {
	app.configs[key] = value
}

// GetConfig application level variable by key.
func (app *Application) GetConfig(key string) string {
	return app.configs[key]
}

func (app *Application) ServeHTTP(rw http.ResponseWriter, rq *http.Request) {
	handler := compose(app.middlewares)
	req := createRequest(rq)
	res := createResponse(rw)
	req.response = res
	res.request = req
	handler(&Context{rq.Context(), app, nil}, req, res)
}

// Run the Vox application.
func (app *Application) Run(addr string) error {
	return http.ListenAndServe(addr, app)
}

func compose(middlewares []Handler) Handler {
	return func(ctx *Context, req *Request, res *Response) {
		next := func() {}
		for i := len(middlewares) - 1; i >= 0; i-- {
			func(i int, nenext func()) {
				next = func() {
					ctx.Next = nenext
					middlewares[i](ctx, req, res)
				}
			}(i, next)
		}
		next()
	}
}
