GameLobby = inherited("GameLobby", State)

GameLobby.packets =
{
	{name = "startCountdown", host = true, callSelf = true, structure = {"i"}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		call = "startCountdown"},
		
	{name = "stopCountdown", host = true, callSelf = true, structure = {}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		call = "stopCountdown"},
		
	{name = "launchGame", host = true, callSelf = true, structure = {}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		call = "launchGame"},
		
	{name = "blinkPlayer", host = true, callSelf = true, structure = {"g"}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		call = "blinkPlayer"},
		
	{name = "requestStartGame", client = true, structure = {}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		relayCall = "relayRequestStartGame",},
		
	{name = "setPlayerData", host = true, callSelf = true, structure = {"g","t"}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		call = "setPlayerData"},
		
	{name = "removePlayer", host = true, callSelf = true, structure = {"g"}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		call = "removePlayer"},
		
	{name = "addPlayer", host = true, callSelf = true, structure = {"g"}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		call = "addPlayer"},
		
	{name = "requestUpdatePlayer", client = true, structure = {"t"}, prio = PACKETS.IMMEDIATE, mode = PACKETS.RELIABLE, 
		relayCall = "relayRequestUpdatePlayer"},
}

function GameLobby:newHost(gameString, versionString, port, maxPlayers)
	local g = instance(self)
	g.host = true
	g.players = {}
	g.maxPlayers = maxPlayers
	g.network = Network:new(gameString, versionString, self.packets)
	g.network:setCallback(g)
	if g.network:host(port, maxPlayers) then
		g:addPlayer(g.network:getGuid(), true)
	end
	return g
end

function GameLobby:newClient(gameString, versionString, ip, port)
	local g = instance(self)
	g.client = true
	g.players = {}
	g.network = Network:new(gameString, versionString, self.packets)
	g.network:setCallback(g)
	g.network:join(ip, port)
	return g
end

function GameLobby:setCallback(c)
	self.callback = c
end

function GameLobby:updatePongData()
	local dataString = table.join({"description,players,maxPlayers,creator,map",self:getDescription(),self:getNumberOfPlayers(),self:getMaxPlayers(),self:getCreator(),self:getMap()}, "|")
	self.network:setPongDataString(dataString)
end

function GameLobby:getNumberOfPlayers()
	return #self.players
end

function GameLobby:setCreator(creator)
	self.creator = creator 
	self:updatePongData()
end
	
function GameLobby:setNick(nick)
	self.nick = nick 
	self:updateMyPlayer()
end

function GameLobby:setMap(map)
	self.map = map
	self:updatePongData()
end

function GameLobby:setDescription(description)
	self.description = description
	self:updatePongData()
end

function GameLobby:setMaxPlayers(maxPlayers)
	self.maxPlayers = maxPlayers
	self:updatePongData()
end

function GameLobby:getMaxPlayers()
	return self.maxPlayers or 0
end

function GameLobby:getPort()
	return self.network.port 
end

function GameLobby:getIp()
	return self.network.ip
end

function GameLobby:getCreator()
	return self.creator or "-"
end

function GameLobby:getDescription()
	return self.description or "-"
end

function GameLobby:getMap(map)
	return self.map or "-"
end

function GameLobby:update(time)
	self.network:update(time)
	
	for index, player in pairs(self.players) do
		if player.blinkTimer then
			player.blinkTimer = player.blinkTimer - time
			if player.blinkTimer <= 0 then
				player.blinkTimer = nil
			end
		end
	end
	
	if self.starting then
		if self.startDelay > 0 then
			local last = self.startDelay
			self.startDelay = self.startDelay - time
			if math.floor(self.startDelay) < math.floor(last) then
				audio.playSound("sfx/starting.ogg", 0.5)
			end
			if self.startDelay <= 0 then
				if self.host then
					self.network:sendPacket("launchGame")
				end
				self.startDelay = 0
			end
		end
	end
end

function GameLobby:isFull()
	return self:getNumberOfPlayers() >= self:getMaxPlayers()
end

function GameLobby:getPlayer(guid)
	for index, player in pairs(self.players)do
		if player.guid == guid then
			return player
		end
	end
end

function GameLobby:disconnect()
	self.network:setCallback()
	self.network:disconnect()
end

function GameLobby:updateMyPlayer()
	self.network:sendPacket("requestUpdatePlayer", {nick = self.nick or "-"})
end

function GameLobby:getPlayerList()
	return self.players
end

function GameLobby:isLocalPlayer(player)
	return player.guid == self.network:getGuid()
end

function GameLobby:start()
	if not self:isStarting() then
		if self.client then
			self.network:sendPacket("requestStartGame")
		elseif self.host then
			self.network:sendPacket("startCountdown", self:getNumberOfPlayers())
		end
	end
end

function GameLobby:setTotalPlayers(p)
	self.totalPlayers = p
end

function GameLobby:getTotalPlayers(p)
	return self.totalPlayers
end

function GameLobby:isStarting()
	return self.starting
end

function GameLobby:getStartDelay()
	return self.startDelay
end

--[[
                                          
  ,ad8888ba,             88 88            
 d8"'    `"8b            88 88            
d8'                      88 88            
88            ,adPPYYba, 88 88 ,adPPYba,  
88            ""     `Y8 88 88 I8[    ""  
Y8,           ,adPPPPP88 88 88  `"Y8ba,   
 Y8a.    .a8P 88,    ,88 88 88 aa    ]8I  
  `"Y8888Y"'  `"8bbdP"Y8 88 88 `"YbbdP"'  
                                          
                                          
]]

function GameLobby:setPlayerData(guid, updates)
	local p = self:getPlayer(guid)
	if p then
		for index, val in pairs(updates) do
			p[index] = val
		end
	else
		self:onError("player "..guid.. " does not exist")
	end
end

function GameLobby:addPlayer(guid, host)
	for index, player in pairs(self.players) do
		if player.guid == guid then
			return player
		end
	end
	local player = {guid = guid, nick = "-"}
	table.insert(self.players, player)
	
	if player.guid == self.network:getGuid() then
		self:updateMyPlayer()
	end
	
	return player
end

function GameLobby:removePlayer(guid)
	for index, player in pairs(self.players)do
		if player.guid == guid then
			table.remove(self.players, index)
		end
	end
end

function GameLobby:stopCountdown()
	self.starting = false
end

function GameLobby:blinkPlayer(guid)
	local p = self:getPlayer(guid)
	if p then
		p.blinkTimer = 3
		audio.playSound("sfx/ready.ogg", 0.5)
	end
end

function GameLobby:startCountdown(totalPlayers)
	self:setTotalPlayers(totalPlayers)
	self.starting = true
	if totalPlayers <= 1 then
		self.startDelay = 0.1
	else
		self.startDelay = 1
	end
end

function GameLobby:launchGame()
	if self.callback then
		if self.host then
			if self.callback.onLaunchHost then
				self.callback.onLaunchHost(self.callback, self.network.port, self:getMap(), self:getTotalPlayers())
			end
		elseif self.client then
			if self.callback.onLaunchClient then
				self.callback.onLaunchClient(self.callback, self.network.ip, self.network.port, self:getMap(), self:getTotalPlayers())
			end
		end
	end
end

--[[
                                                           
88888888ba            88                                   
88      "8b           88                                   
88      ,8P           88                                   
88aaaaaa8P' ,adPPYba, 88 ,adPPYYba, 8b       d8 ,adPPYba,  
88""""88'  a8P_____88 88 ""     `Y8 `8b     d8' I8[    ""  
88    `8b  8PP""""""" 88 ,adPPPPP88  `8b   d8'   `"Y8ba,   
88     `8b "8b,   ,aa 88 88,    ,88   `8b,d8'   aa    ]8I  
88      `8b `"Ybbd8"' 88 `"8bbdP"Y8     Y88'    `"YbbdP"'  
                                        d8'                
                                       d8'                 

]]

function GameLobby:relayRequestUpdatePlayer(requestGuid, updates)
	self.network:sendPacket("setPlayerData", requestGuid, updates)
end

function GameLobby:relayRequestStartGame(requestGuid)
	if not self:isStarting() then
		self.network:sendPacket("blinkPlayer", requestGuid)
	end
end

--[[
                                                                                     
888b      88                                                              88         
8888b     88              ,d                                              88         
88 `8b    88              88                                              88         
88  `8b   88  ,adPPYba, MM88MMM 8b      db      d8  ,adPPYba,  8b,dPPYba, 88   ,d8   
88   `8b  88 a8P_____88   88    `8b    d88b    d8' a8"     "8a 88P'   "Y8 88 ,a8"    
88    `8b 88 8PP"""""""   88     `8b  d8'`8b  d8'  8b       d8 88         8888[      
88     `8888 "8b,   ,aa   88,     `8bd8'  `8bd8'   "8a,   ,a8" 88         88`"Yba,   
88      `888  `"Ybbd8"'   "Y888     YP      YP      `"YbbdP"'  88         88   `Y8a  
                                                                                     
                                                                                     
                                                                                      
  ,ad8888ba,             88 88 88                                88                   
 d8"'    `"8b            88 88 88                                88                   
d8'                      88 88 88                                88                   
88            ,adPPYYba, 88 88 88,dPPYba,  ,adPPYYba,  ,adPPYba, 88   ,d8  ,adPPYba,  
88            ""     `Y8 88 88 88P'    "8a ""     `Y8 a8"     "" 88 ,a8"   I8[    ""  
Y8,           ,adPPPPP88 88 88 88       d8 ,adPPPPP88 8b         8888[      `"Y8ba,   
 Y8a.    .a8P 88,    ,88 88 88 88b,   ,a8" 88,    ,88 "8a,   ,aa 88`"Yba,  aa    ]8I  
  `"Y8888Y"'  `"8bbdP"Y8 88 88 8Y"Ybbd8"'  `"8bbdP"Y8  `"Ybbd8"' 88   `Y8a `"YbbdP"'  
  
]]

function GameLobby:onConnectedToServer(myGuid)
	
end

function GameLobby:onClientConnected(guid)
	if not self:isFull() and not self:isStarting() then
		self.network:sendPacket("addPlayer", guid)
		for index, player in pairs(self.players) do
			self.network:sendPacketTo(guid, "addPlayer", player.guid)
			self.network:sendPacketTo(guid, "setPlayerData", player.guid, player)
		end
	end
end

function GameLobby:onClientDisconnected(guid)
	self.network:sendPacket("removePlayer", guid)
	self.network:sendPacket("stopCountdown")
end

function GameLobby:onDisconnected()
	if self.callback then
		if self.callback.onLobbyClosed then
			self.callback.onLobbyClosed(self.callback)
		end
	end
end