package muesli

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"testing"
)

/** Logger interface that Muesli uses,to allow external logging packages to be used easly.*/
type Logger interface {
	Log(level string, file string, line int, format string, args ...interface{})
}

func WriteLog(logger Logger, depth int, level string, format string, args ...interface{}) {
	if logger == nil {
		return
	}

	_, file, line, ok := runtime.Caller(depth)

	if !ok {
		file = "unknown"
		line = 0
	}

	logger.Log(level, file, line, format, args...)
}

type LoggerWrapper struct {
	Logger
}

func (lw LoggerWrapper) WriteLog(depth int, level string, format string, args ...interface{}) {
	WriteLog(lw.Logger, depth, level, format, args...)
}

func (lw LoggerWrapper) LogTrace(format string, args ...interface{}) {
	lw.WriteLog(3, "TRACE:", format, args...)
}

func (lw LoggerWrapper) LogDebug(format string, args ...interface{}) {
	lw.WriteLog(3, "DEBUG:", format, args...)
}

func (lw LoggerWrapper) LogInfo(format string, args ...interface{}) {
	lw.WriteLog(3, "INFO:", format, args...)
}

func (lw LoggerWrapper) LogWarning(format string, args ...interface{}) {
	lw.WriteLog(3, "WARNING:", format, args...)
}

func (lw LoggerWrapper) LogError(format string, args ...interface{}) {
	lw.WriteLog(3, "ERROR:", format, args...)
}

/* Logger used internally in Muesli for tests. */
type testLogger struct {
	last   string
	repeat int
	test * testing.T
}

func (tl *testLogger) Log(level string, file string, line int, format string, args ...interface{}) {
	text1 := fmt.Sprintf("%s:%s:%d: ", level, file, line)
	text2 := fmt.Sprintf(format, args...)
	if format[len(format)-1] != '\n' {
		text2 = text2 + "\n"
	}
	out := text1 + text2
	if strings.Compare(out, tl.last) == 0 {
		tl.repeat++
	} else {
		if tl.repeat > 0 {
			if tl.test == nil {
				fmt.Printf("%s:%s:%d: Above message repeated %d times.",
					level, file, line, tl.repeat)
			} else {
				tl.test.Logf("%s:%s:%d: Above message repeated %d times.",
					level, file, line, tl.repeat)
			}
		}
		tl.last = out
		tl.repeat = 0
		if tl.test == nil {
			fmt.Printf("%s", out)
		} else {
			tl.test.Logf("%s", out)
		}
	}
}

/* Useful when logging. */
func GetFunctionName(i interface{}) string {
	return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}