-- Server network messages
-- TODO: Make net send functions all take a player structure instead of a player id.
net.recv = {}

function GAME:NetRecv(uid,msg)
	local id = msg:bin(1)
	if net.recv[id]
		net.recv[id](uid,msg:sub(2))
	else
		console.print("WARNING: Unhandled message type "..(NETMSG[id] or id).." recieved!")
	end
end

net.recv[NETMSG.TITLE] = function(uid,msg)
	local player = players[uid]
	if not player.title
		return
	end
	player.title = false
	GAME:Start(player,msg:bin(1) ~= 0,true)
end

net.recv[NETMSG.CL_ANIM] = function(uid,msg)
	-- Checking an area? Find an NPC to trigger!
	local player = players[uid]
	local x = msg:bin(1,4)
	local y = msg:bin(5,4)
	player.x = x
	player.y = y
	for k,v in pairs(player.events)
		if v.flags & NPC.CHECK_EVENT == 0
			continue
		end
		local b = NPC[v.type].collision
		if x >= v.x - b[BBOX.LEFT] and x <= v.x + b[BBOX.RIGHT]
		and y >= v.y - b[BBOX.TOP] and y <= v.y + b[BBOX.BOTTOM]
			tsc.start(player,v.event)
			return
		end
	end
end

net.recv[NETMSG.CL_MOVE] = function(uid,msg)
	local player = players[uid]
	player.x = msg:bin(1,4)
	player.y = msg:bin(5,4)
	player.mx = msg:bin(9,2)
	if player.mx > 0x7FFF
		player.mx = player.mx - 0xFFFF
	end
	player.mx = player.mx / 0x200
	player.my = msg:bin(11,2)
	if player.my > 0x7FFF
		player.my = player.my - 0xFFFF
	end
	player.my = player.my / 0x200
	player.anim = msg:bin(13)
	local flags = msg:bin(14)
	player.flip = flags & 1 ~= 0
	player.grounded = flags & 1<<1 ~= 0
	net.cl_move(player)
end

net.recv[NETMSG.TSC_TEXT] = function(uid,msg)
	local player = players[uid]
	if player.tsc and player.tsc.wait == "text"
		player.tsc.wait = nil
	end
end

net.recv[NETMSG.TSC_NOD] = function(uid,msg)
	local player = players[uid]
	if player.intro
		tsc.cmd.END(player)
		return
	end
	if player.tsc and (player.tsc.wait == "nod" or player.tsc.wait == "ynj")
		player.tsc.wait = nil
	end
end

net.recv[NETMSG.TSC_YNJ] = function(uid,msg)
	local player = players[uid]
	if player.tsc and player.tsc.wait == "ynj"
		tsc.start(player,player.tsc.ynj,true)
	end
end

function net.send_console(text)
	net.send(1,string.num(NETMSG.CHAT) .. text)
end

function net.send_map(uid,map)
	local player = players[uid]
	if player.stage
		player.stage.players[player.id] = nil
		player.spawned = false
	end
	player.stage = stages[map]
	player.tsc = nil
	player.ents = {}
	player.events = {}
	net.send(player.id,string.num(NETMSG.MAP) .. map)
	if stages[map]
		stages[map].players[player.id] = player
		for i,v in ipairs(stages[map].ents)
			net.ent_spawn(uid,v)
		end
		for k,v in pairs(stages[map].players)
			if v.spawned
				net.cl_spawn(uid,v)
			end
		end
	end
end

function net.send_title(uid)
	local player = players[uid]
	player.title = true
	net.send(player.id,string.num(NETMSG.TITLE))
end

function net.spawn_client(player,pos)
	player.x, player.y = (pos[1] or 0)*16+8, (pos[2] or 0)*16+8
	player.mx, player.my = 0, 0
	player.anim = ANIM.STAND
	player.spawned = true
	player.damage = false
	for k,v in pairs(player.stage.players)
		net.cl_spawn(k,player)
	end
end

function net.cl_spawn(uid,player)
	local id = player.id
	if uid == id
		id = 0
	end
	local x = math.floor(player.x)
	local y = math.floor(player.y)
	local flip = 0
	if player.flip
		flip = 2
	end
	-- TODO: Add the client's user name somewhere so it can be shown as floating text?
	net.send(uid,string.num(NETMSG.CL_SPAWN) .. string.num(id) .. string.num(x,4) .. string.num(y,4) .. string.num(player.anim) .. string.num(flip) .. player.skin.name)
end

function net.cl_move(player)
	if not player.spawned
		return
	end
	local x = math.floor(player.x)
	local y = math.floor(player.y)
	local flags = 0
	if player.flip
		flags = flags | 1
	end
	if player.grounded
		flags = flags | 1<<1
	end
	local msg = string.num(NETMSG.CL_MOVE) .. string.num(player.id) .. string.num(x,4) .. string.num(y,4) .. string.num(math.floor(player.mx*0x200),2) .. string.num(math.floor(player.my*0x200),2) .. string.num(player.anim) .. string.num(flags)
	for k,v in pairs(player.stage.players)
		if v.id ~= player.id
			net.send(v.id,msg)
		end
	end
end

function net.ent_spawn(uid,e)
	local player = players[uid]
	if e.flags & NPC.IF_FLAG ~= 0 and not player.eventflags[e.flagnum]
		return
	elseif e.flags & NPC.DEAD_FLAG ~= 0 and player.eventflags[e.flagnum]
		return
	end
	if e.flags & NPC.CHECK_EVENT
		player.events[e.id] = e
	end
	local flags = e.flags & (~NPC.SERVER_ONLY)
	player.ents[e.id] = true
	local msg = string.num(NETMSG.ENT_SPAWN) .. string.num(e.id) .. string.num(e.type,2) .. string.num(math.floor(e.x),4) .. string.num(math.floor(e.y),4) .. string.num(flags,4) .. string.num(e.anim)
	if NPC[e.type].send_event
		msg = msg .. string.num(e.event,e.send_event)
	end
	net.send(uid,msg)
end

function net.ent_update(ent,changed)
	local msg = string.num(NETMSG.ENT_UPDATE) .. string.num(ent.id) .. string.num(changed) .. string.num(math.floor(ent.x),4) .. string.num(math.floor(ent.y),4)
	if changed & CHANGE.ANIM
		msg = msg .. string.num(ent.anim)
	end
	if changed & CHANGE.FLIP
		msg = msg .. string.num(ent.flags & NPC.FLIP ~= 0)
	end
	if changed & CHANGE.MX
		msg = msg .. string.num(math.floor(ent.mx * 0x200),2)
	end
	if changed & CHANGE.MY
		msg = msg .. string.num(math.floor(ent.my * 0x200),2)
	end
	for _,player in pairs(ent.stage.players)
		if not player.ents[ent.id]
			continue
		end
		net.send(player.id,msg)
	end
end

function net.ent_remove(uid,e)
	local player = players[uid]
	if not player.ents[e.id]
		return
	end
	player.ents[e.id] = nil
	net.send(uid,string.num(NETMSG.ENT_REMOVE) .. string.num(e.id))
end

function net.tsc_end(uid)
	net.send(uid,string.num(NETMSG.TSC_END))
end

function net.tsc_keylock(uid)
	if not players[uid].spawned
		return
	end
	local keylock = 0
	if players[uid].tsc
		keylock = players[uid].tsc.keylock or 0
	end
	net.send(uid,string.num(NETMSG.TSC_KEY) .. string.num(keylock))
end

function net.tsc_fai(uid,dir)
	net.send(uid,string.num(NETMSG.TSC_FAI) .. string.num(dir))
end

function net.tsc_fao(uid,dir)
	net.send(uid,string.num(NETMSG.TSC_FAO) .. string.num(dir))
end

function net.tsc_msg(uid)
	local msg
	if not players[uid].tsc or not players[uid].tsc.msg
		msg = 0
	else
		msg = players[uid].tsc.msg
	end
	net.send(uid,string.num(NETMSG.TSC_MSG) .. string.num(msg))
end

function net:tsc_mna()
	net.send(self.id,string.num(NETMSG.TSC_MNA) .. self.stage.header.title)
end

function net.tsc_text(uid,text)
	local tur = 0
	if players[uid].tsc and players[uid].tsc.tur
		tur = 1 -- tur or cat is 1
		if players[uid].tsc.tur == "sat"
			tur = 2 -- sat is 2
		end
	end
	net.send(uid,string.num(NETMSG.TSC_TEXT) .. string.num(tur) .. text)
end

function net.tsc_nod(uid)
	net.send(uid,string.num(NETMSG.TSC_NOD))
end

function net.tsc_ynj(uid)
	net.send(uid,string.num(NETMSG.TSC_YNJ))
end

function net.tsc_clr(uid)
	net.send(uid,string.num(NETMSG.TSC_CLR))
end
