#!/usr/bin/python3
# -*- coding: utf-8 -*-
import asyncio
import logging
import numpy
from .Constants import *

class PlayerManager():
	def __init__(self, master):
		self.Logger = logging.getLogger(__class__.__name__)
		self.Torchlight = master

		self.Players = numpy.empty(MAXPLAYERS + 1, dtype = object)
		self.Storage = self.StorageManager(self)

		self.Torchlight().GameEvents.HookEx("player_connect", self.Event_PlayerConnect)
		self.Torchlight().GameEvents.HookEx("player_activate", self.Event_PlayerActivate)
		self.Torchlight().Forwards.HookEx("OnClientPostAdminCheck", self.OnClientPostAdminCheck)
		self.Torchlight().GameEvents.HookEx("player_info", self.Event_PlayerInfo)
		self.Torchlight().GameEvents.HookEx("player_disconnect", self.Event_PlayerDisconnect)
		self.Torchlight().GameEvents.HookEx("server_spawn", self.Event_ServerSpawn)

	def Event_PlayerConnect(self, name, index, userid, networkid, address, bot):
		index += 1
		self.Logger.info("OnConnect(name={0}, index={1}, userid={2}, networkid={3}, address={4}, bot={5})"
			.format(name, index, userid, networkid, address, bot))
		if self.Players[index] != None:
			self.Logger.error("!!! Player already exists, overwriting !!!")

		self.Players[index] = self.Player(self, index, userid, networkid, address, name)
		self.Players[index].OnConnect()

	def Event_PlayerActivate(self, userid):
		self.Logger.info("Pre_OnActivate(userid={0})".format(userid))
		index = self.FindUserID(userid).Index
		self.Logger.info("OnActivate(index={0}, userid={1})".format(index, userid))

		self.Players[index].OnActivate()

	def OnClientPostAdminCheck(self, client):
		self.Logger.info("OnClientPostAdminCheck(client={0})".format(client))

		asyncio.ensure_future(self.Players[client].OnClientPostAdminCheck())

	def Event_PlayerInfo(self, name, index, userid, networkid, bot):
		index += 1
		self.Logger.info("OnInfo(name={0}, index={1}, userid={2}, networkid={3}, bot={4})"
			.format(name, index, userid, networkid, bot))

		# We've connected to the server and receive info events about the already connected players
		# Emulate connect message
		if not self.Players[index]:
			self.Event_PlayerConnect(name, index - 1, userid, networkid, bot)
		else:
			self.Players[index].OnInfo(name)

	def Event_PlayerDisconnect(self, userid, reason, name, networkid, bot):
		index = self.FindUserID(userid).Index
		self.Logger.info("OnDisconnect(index={0}, userid={1}, reason={2}, name={3}, networkid={4}, bot={5})"
			.format(index, userid, reason, name, networkid, bot))

		self.Players[index].OnDisconnect(reason)
		self.Players[index] = None

	def Event_ServerSpawn(self, hostname, address, ip, port, game, mapname, maxplayers, os, dedicated, password):
		self.Logger.info("ServerSpawn(mapname={0})"
			.format(mapname))

		self.Storage.Reset()

		for i in range(1, self.Players.size):
			if self.Players[i]:
				self.Players[i].OnDisconnect("mapchange")
				self.Players[i].OnConnect()

	def FindUniqueID(self, uniqueid):
		for Player in self.Players:
			if Player and Player.UniqueID == uniqueid:
				return Player

	def FindUserID(self, userid):
		for Player in self.Players:
			if Player and Player.UserID == userid:
				return Player

	def FindName(self, name):
		for Player in self.Players:
			if Player and Player.Name == name:
				return Player

	def __len__(self):
		Count = 0
		for i in range(1, self.Players.size):
			if self.Players[i]:
				Count += 1
		return Count

	def __setitem__(self, key, value):
		if key > 0 and key <= MAXPLAYERS:
			self.Players[key] = value

	def __getitem__(self, key):
		if key > 0 and key <= MAXPLAYERS:
			return self.Players[key]

	def __iter__(self):
		for i in range(1, self.Players.size):
			if self.Players[i]:
				yield self.Players[i]

	class StorageManager():
		def __init__(self, master):
			self.PlayerManager = master
			self.Storage = dict()

		def Reset(self):
			self.Storage = dict()

		def __getitem__(self, key):
			if not key in self.Storage:
				self.Storage[key] = dict()

			return self.Storage[key]

	class Admin():
		def __init__(self):
			self._FlagBits = 0

		def FlagBits(self):
			return self._FlagBits

		def Reservation(self): return (self._FlagBits & ADMFLAG_RESERVATION)
		def Generic(self): return (self._FlagBits & ADMFLAG_GENERIC)
		def Kick(self): return (self._FlagBits & ADMFLAG_KICK)
		def Ban(self): return (self._FlagBits & ADMFLAG_BAN)
		def Unban(self): return (self._FlagBits & ADMFLAG_UNBAN)
		def Slay(self): return (self._FlagBits & ADMFLAG_SLAY)
		def Changemap(self): return (self._FlagBits & ADMFLAG_CHANGEMAP)
		def Convars(self): return (self._FlagBits & ADMFLAG_CONVARS)
		def Config(self): return (self._FlagBits & ADMFLAG_CONFIG)
		def Chat(self): return (self._FlagBits & ADMFLAG_CHAT)
		def Vote(self): return (self._FlagBits & ADMFLAG_VOTE)
		def Password(self): return (self._FlagBits & ADMFLAG_PASSWORD)
		def RCON(self): return (self._FlagBits & ADMFLAG_RCON)
		def Cheats(self): return (self._FlagBits & ADMFLAG_CHEATS)
		def Root(self): return (self._FlagBits & ADMFLAG_ROOT)
		def Custom1(self): return (self._FlagBits & ADMFLAG_CUSTOM1)
		def Custom2(self): return (self._FlagBits & ADMFLAG_CUSTOM2)
		def Custom3(self): return (self._FlagBits & ADMFLAG_CUSTOM3)
		def Custom4(self): return (self._FlagBits & ADMFLAG_CUSTOM4)
		def Custom5(self): return (self._FlagBits & ADMFLAG_CUSTOM5)
		def Custom6(self): return (self._FlagBits & ADMFLAG_CUSTOM6)

	class Player():
		def __init__(self, master, index, userid, uniqueid, address, name):
			self.PlayerManager = master
			self.Torchlight = self.PlayerManager.Torchlight
			self.Index = index
			self.UserID = userid
			self.UniqueID = uniqueid
			self.Address = address
			self.Name = name
			self.Access = None
			self.Admin = self.PlayerManager.Admin()
			self.Storage = None
			self.Active = False
			self.ChatCooldown = 0

		def OnConnect(self):
			self.Storage = self.PlayerManager.Storage[self.UniqueID]

			if not "Audio" in self.Storage:
				self.Storage["Audio"] = dict({"Uses": 0, "LastUse": 0.0, "LastUseLength": 0.0, "TimeUsed": 0.0})

			self.Access = self.Torchlight().Access[self.UniqueID]

		def OnActivate(self):
			self.Active = True

		async def OnClientPostAdminCheck(self):
			self.Admin._FlagBits = (await self.Torchlight().API.GetUserFlagBits(self.Index))["result"]
			self.PlayerManager.Logger.info("#{0} \"{1}\"({2}) FlagBits: {3}".format(self.UserID, self.Name, self.UniqueID, self.Admin._FlagBits))
			if not self.Access:
				if self.Admin.RCON():
					self.Access = dict({"level": 6, "name": "SAdmin"})
				elif self.Admin.Generic():
					self.Access = dict({"level": 3, "name": "Admin"})
				elif self.Admin.Custom1():
					self.Access = dict({"level": 1, "name": "VIP"})

			if self.PlayerManager.Torchlight().Config["DefaultLevel"]:
				if self.Access and self.Access["level"] < self.PlayerManager.Torchlight().Config["DefaultLevel"]:
					self.Access = dict({"level": self.PlayerManager.Torchlight().Config["DefaultLevel"], "name": "Default"})

		def OnInfo(self, name):
			self.Name = name

		def OnDisconnect(self, message):
			self.Active = False
			self.Storage = None
			self.Torchlight().AudioManager.OnDisconnect(self)