package accesslog

import (
	"bytes"
	"fmt"
	"time"

	"github.com/Sirupsen/logrus"
)

// default format for time presentation
const (
	commonLogTimeFormat = "02/Jan/2006:15:04:05 -0700"
	defaultValue        = "-"
)

// CommonLogFormatter provides formatting in the Traefik common log format
type CommonLogFormatter struct{}

//Format formats the log entry in the Traefik common log format
func (f *CommonLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	b := &bytes.Buffer{}

	timestamp := entry.Data[StartUTC].(time.Time).Format(commonLogTimeFormat)
	elapsedMillis := entry.Data[Duration].(time.Duration).Nanoseconds() / 1000000

	_, err := fmt.Fprintf(b, "%s - %s [%s] \"%s %s %s\" %v %v %s %s %v %s %s %dms\n",
		entry.Data[ClientHost],
		entry.Data[ClientUsername],
		timestamp,
		entry.Data[RequestMethod],
		entry.Data[RequestPath],
		entry.Data[RequestProtocol],
		toLog(entry.Data[OriginStatus]),
		toLog(entry.Data[OriginContentSize]),
		toLog(entry.Data["request_Referer"]),
		toLog(entry.Data["request_User-Agent"]),
		toLog(entry.Data[RequestCount]),
		toLog(entry.Data[FrontendName]),
		toLog(entry.Data[BackendURL]),
		elapsedMillis)

	return b.Bytes(), err
}

func toLog(v interface{}) interface{} {
	if v == nil {
		return defaultValue
	}

	switch s := v.(type) {
	case string:
		return quoted(s, defaultValue)

	case fmt.Stringer:
		return quoted(s.String(), defaultValue)

	default:
		return v
	}

}

func quoted(s string, defaultValue string) string {
	if len(s) == 0 {
		return defaultValue
	}
	return `"` + s + `"`
}
