// Package logger provides a wrapper around log that adds color support with github.com/fatih/color.
package logger

import (
	"errors"
	"io"
	"log"
	"runtime"
	"strconv"

	c "github.com/fatih/color"
)

// type Logger interface {
// 	Printf(format string, v ...interface{})
// 	Print(v ...interface{})
// 	Println(v ...interface{})
// 	Fatal(v ...interface{})
// 	Fatalf(format string, v ...interface{})
// 	SetFatalFunc(f func(err interface{}))
// }

type Logger struct {
	empty     bool
	logger    *log.Logger
	shortfile bool
	printer   *c.Color
	fatalFunc func(err interface{})
}

// Lshortfile is a re-implemented log.Lshortfile with a modifiable call level.
func Lshortfile(level int) string {
	// 0 = This function, 1 = Print/Printf/Println, 2 = Caller of Print/Printf/Println
	_, file, line, ok := runtime.Caller(level)
	lineString := strconv.Itoa(line)
	if !ok {
		return ""
	}
	if file == "" {
		return lineString
	}
	for i := len(file) - 1; i > 0; i-- {
		if file[i] == '/' || file[i] == '\\' {
			file = file[i+1:]
			break
		}
	}
	return file + ":" + lineString + ":"
}

func lshortfile() string {
	return Lshortfile(2)
}

func NewLogger(out io.Writer, prefix string, flag int, color c.Attribute) (l *Logger) {
	l = &Logger{}
	// Use reimplemented Lshortfile since wrapping the log functions messes them up
	if flag&log.Lshortfile != 0 {
		flag -= log.Lshortfile
		l.shortfile = true
	}

	l.logger = log.New(out, prefix, flag)
	l.printer = c.New(color)
	return l
}

func NewEmptyLogger() (l *Logger) {
	l = &Logger{
		empty: true,
	}
	return
}

func (l *Logger) Printf(format string, v ...interface{}) {
	if l.empty {
		return
	}
	var out string
	if l.shortfile {
		out = lshortfile()
	}
	out += " " + l.printer.Sprintf(format, v...)
	l.logger.Print(out)
}

func (l *Logger) Print(v ...interface{}) {
	if l.empty {
		return
	}
	var out string
	if l.shortfile {
		out = lshortfile()
	}
	out += " " + l.printer.Sprint(v...)
	l.logger.Print(out)
}

func (l *Logger) Println(v ...interface{}) {
	if l.empty {
		return
	}
	var out string
	if l.shortfile {
		out = lshortfile()
	}
	out += " " + l.printer.Sprintln(v...)
	l.logger.Print(out)
}

func (l *Logger) Fatal(v ...interface{}) {
	if l.empty {
		return
	}
	var out string
	if l.shortfile {
		out = lshortfile()
	}
	out += " " + l.printer.Sprint(v...)
	l.logger.Fatal(out)
}

func (l *Logger) Fatalf(format string, v ...interface{}) {
	if l.empty {
		return
	}
	var out string
	if l.shortfile {
		out = lshortfile()
	}
	out += " " + l.printer.Sprintf(format, v...)
	if l.fatalFunc != nil {
		l.fatalFunc(errors.New(out))
	} else {
		l.logger.Fatal(out)
	}
}

func (l *Logger) SetFatalFunc(f func(err interface{})) {
	l.fatalFunc = f
}
