package etdd

import (
	"./obituaries"
	"fmt"
	"math"
	"os"
	"regexp"
	"strings"
)

var r = regexp.MustCompile(`\^.`)

type line struct {
	s string
	e bool
}

type Logger struct {
	colored  bool
	Complete bool
	lines    []line
}

func NewLogger(colored bool) Logger {
	return Logger{colored, false, []line{}}
}

func (l *Logger) Error(error error) {
	l.e("%s", error.Error())
}

func (l *Logger) Chat(serverTime int, player PlayerState, message string, channel string) {
	l.p(serverTime, "[chat] %s: %s", player.Name, message)
}

func (l *Logger) Print(serverTime int, message string) {
	l.p(serverTime, "[info] %s", message)
}

func (l *Logger) Start(hostname string, mapname string) {
	l.Write(l.c("Server: %s", hostname))
	l.Write(l.c("Map:    %s", mapname))
}

func (l *Logger) End() {
	l.Complete = true
}

func (l *Logger) Write(message string) {
	l.lines = append(l.lines, line{message, false})
}

func (l *Logger) WriteTo(output *os.File, error *os.File) {
	for _, line := range l.lines {
		if line.e {
			_, _ = error.WriteString(line.s)
		} else {
			_, _ = output.WriteString(line.s)
		}
	}
}

func (l *Logger) Obituary(serverTime int, victim *PlayerState, attacker *PlayerState, mod int) {

	message := ""

	switch mod {
	case obituaries.Suicide:
		message = "committed suicide"
		break
	case obituaries.Falling:
		message += "fell to his death"
		break
	case obituaries.Crush:
		message += "was crushed"
		break
	case obituaries.Water:
		message += "drowned"
		break
	case obituaries.Slime:
		message += "died by toxic materials"
		break
	case obituaries.TriggerHurt, obituaries.Telefrag, obituaries.TargetLaser:
		message += "was killed"
		break
	case obituaries.CrushConstructiondeathNoattacker:
		message += "got buried under a pile of rubble"
		break
	case obituaries.Lava:
		message += "was incinerated"
		break
	}

	if attacker == victim {
		switch mod {
		case obituaries.Dynamite:
			message = "dynamited himself to pieces"
			break
		case obituaries.GrenadeLauncher, obituaries.GrenadePineapple:
			message = "dove on his own grenade"
			break
		case obituaries.Panzerfaust:
			message = "vaporized himself"
			break
		case obituaries.Flamethrower:
			message = "played with fire"
			break
		case obituaries.Airstrike:
			message = "obliterated himself"
			break
		case obituaries.Arty:
			message = "fired-for-effect on himself"
			break
		case obituaries.Explosive:
			message = "died in his own explosion"
			break
		case obituaries.Gpg40, obituaries.M7:
			message = "ate his own rifle grenade"
			break
		case obituaries.Landmine:
			message = "failed to spot his own landmine"
			break
		case obituaries.Satchel:
			message = "embraced his own satchel explosion"
			break
		case obituaries.Tripmine:
			message = "forgot where his tripmine was"
			break
		case obituaries.CrushConstruction:
			message = "engineered himself into oblivion"
			break
		case obituaries.CrushConstructiondeath:
			message = "buried himself alive"
			break
		case obituaries.Mortar:
			message = "never saw his own mortar round coming"
			break
		case obituaries.Smokegrenade:
			message = "danced on his airstrike marker"
			break
		case obituaries.SwitchTeams:
			return
		default:
			message = "killed himself"
			break
		}
	}

	if len(message) > 0 {
		l.p(serverTime, "[kill] %d %d %d: %s ^7%s.", -1, victim.Num, mod, victim.Name, message)
		return
	}

	if attacker != nil {

		message2 := ""

		switch mod {
		case obituaries.Knife:
			message = "was stabbed by"
			message2 = "'s knife"
			break

		case obituaries.AkimboColt, obituaries.AkimboSilencedcolt:
			message = "was killed by"
			message2 = "'s Akimbo .45ACP 1911s"
			break

		case obituaries.AkimboLuger, obituaries.AkimboSilencedluger:
			message = "was killed by"
			message2 = "'s Akimbo Luger 9mms"
			break

		case obituaries.Silencer, obituaries.Luger:
			message = "was killed by"
			message2 = "'s Luger 9mm"
			break

		case obituaries.SilencedColt, obituaries.Colt:
			message = "was killed by"
			message2 = "'s .45ACP 1911"
			break

		case obituaries.Mp40:
			message = "was killed by"
			message2 = "'s MP40"
			break

		case obituaries.Thompson:
			message = "was killed by"
			message2 = "'s Thompson"
			break

		case obituaries.Sten:
			message = "was killed by"
			message2 = "'s Sten"
			break

		case obituaries.Dynamite:
			message = "was blasted by"
			message2 = "'s dynamite"
			break

		case obituaries.Panzerfaust:
			message = "was blasted by"
			message2 = "'s Panzerfaust"
			break

		case obituaries.GrenadeLauncher, obituaries.GrenadePineapple:
			message = "was exploded by"
			message2 = "'s grenade"
			break

		case obituaries.Flamethrower:
			message = "was cooked by"
			message2 = "'s flamethrower"
			break

		case obituaries.Mortar:
			message = "never saw"
			message2 = "'s mortar round coming"
			break

		case obituaries.Machinegun:
			message = "was perforated by"
			message2 = "'s crew-served MG"
			break

		case obituaries.Browning:
			message = "was perforated by"
			message2 = "'s tank-mounted browning 30cal"
			break

		case obituaries.Mg42:
			message = "was perforated by"
			message2 = "'s tank-mounted MG42"
			break

		case obituaries.Airstrike:
			message = "was blasted by"
			message2 = "'s support fire"
			break

		case obituaries.Arty:
			message = "was shelled by"
			message2 = "'s artillery support"
			break

		case obituaries.SwapPlaces:
			message = "^2swapped places with^7"
			message2 = ""
			break

		case obituaries.Kar98, obituaries.K43:
			message = "was killed by"
			message2 = "'s K43"
			break

		case obituaries.Carbine, obituaries.Garand:
			message = "was killed by"
			message2 = "'s Garand"
			break

		case obituaries.Gpg40, obituaries.M7:
			message = "was killed by"
			message2 = "'s rifle grenade"
			break

		case obituaries.Landmine:
			message = "failed to spot"
			message2 = "'s Landmine"
			break

		case obituaries.CrushConstruction:
			message = "got caught in"
			message2 = "'s construction madness"
			break

		case obituaries.CrushConstructiondeath:
			message = "got burried under"
			message2 = "'s rubble"
			break

		case obituaries.MobileMg42:
			message = "was mown down by"
			message2 = "'s Mobile MG42"
			break

		case obituaries.GarandScope:
			message = "was silenced by"
			message2 = "'s Garand"
			break

		case obituaries.K43Scope:
			message = "was silenced by"
			message2 = "'s K43"
			break

		case obituaries.Fg42:
			message = "was killed by"
			message2 = "'s FG42"
			break

		case obituaries.Fg42scope:
			message = "was sniped by"
			message2 = "'s FG42"
			break

		case obituaries.Satchel:
			message = "was blasted by"
			message2 = "'s Satchel Charge"
			break

		case obituaries.Tripmine:
			message = "was detonated by"
			message2 = "'s trip mine"
			break

		case obituaries.Smokegrenade:
			message = "stood on"
			message2 = "'s airstrike marker"
			break

		default:
			message = "was killed by"
			break
		}

		if victim.Team == attacker.Team {
			message = "^1WAS KILLED BY TEAMMATE^7"
			//message2 = ""
		}

		if message != "" {

			if message2 != "" {
				l.p(serverTime, "[kill] %d %d %d: %s ^7%s %s^7%s.", attacker.Num, victim.Num, mod, victim.Name, message, attacker.Name, message2)
			}

			return

		}

	}

	l.p(serverTime, "[kill] %d %d %d: %s ^7died.", -1, victim.Num, mod, victim.Name)

}

func (l *Logger) p(serverTime int, format string, a ...interface{}) {
	l.Write(formatTime(serverTime) + " " + l.c(format, a...))
}

func (l *Logger) e(format string, a ...interface{}) {
	l.lines = append(l.lines, line{l.c(format, a...), true})
}

func (l *Logger) c(format string, a ...interface{}) string {

	message := strings.Replace(fmt.Sprintf(format, a...), "\n", " ", -1) + "\n"

	if l.colored {
		return message
	}

	return r.ReplaceAllString(message, "")

}

func formatTime(time int) string {

	time = time / 1000
	h, m := 0, 0

	if time > 3600 {
		h = int(math.Floor(float64(time / 3600)))
		time -= h * 3600
	}

	if time > 60 {
		m = int(math.Floor(float64(time / 60)))
		time -= m * 60
	}

	return fmt.Sprintf("[%02d:%02d:%02d]", h, m, time)

}