--[[

                                                                                                       
  ,ad8888ba,                                            ad88888ba                                      
 d8"'    `"8b                                          d8"     "8b ,d                 ,d               
d8'                                                    Y8,         88                 88               
88            ,adPPYYba, 88,dPYba,,adPYba,   ,adPPYba, `Y8aaaaa, MM88MMM ,adPPYYba, MM88MMM ,adPPYba,  
88      88888 ""     `Y8 88P'   "88"    "8a a8P_____88   `"""""8b, 88    ""     `Y8   88   a8P_____88  
Y8,        88 ,adPPPPP88 88      88      88 8PP"""""""         `8b 88    ,adPPPPP88   88   8PP"""""""  
 Y8a.    .a88 88,    ,88 88      88      88 "8b,   ,aa Y8a     a8P 88,   88,    ,88   88,  "8b,   ,aa  
  `"Y88888P"  `"8bbdP"Y8 88      88      88  `"Ybbd8"'  "Y88888P"  "Y888 `"8bbdP"Y8   "Y888 `"Ybbd8"'  
                                                                                                       
                                                                                                       
]]

GameState = inherited("GameState", State)

local shapes = {}
function GameState:new()
	local o = instance(self)
	o.time = 0
	o.view = View:new()
	o.camera = Camera:new(o.view)
	o.camera:setZoom(1)
	o.sync = ActionSync:new(APP.gameString, APP.versionString)
	o.sync:setCallback(o)
	o.mouse = Mouse:new()
	o.optionsFade = 0
	o.whiteOut = 0
	o.resetDelay = 0
	return o
end

function GameState:init()
end

function GameState:setMap(mapString)
	if self.hosted then
		local map = string.split(mapString, ":")
		local dim = string.split(map[1], "x")
		local width = tonumber(dim[1])
		local height = tonumber(dim[2])
		local seed = tonumber(map[2])
		
		self.width = width
		self.height = height


		self.sim:setMap(width, height, seed)
		
		self.camera:setZoom(0.5)
		self:onMessage("Map Loaded!")
	end
end

function GameState:startHost(port, expectedPlayers, nick)
	if not self.hosted and not self.connected then
		--print("hosting "..port.. " players "..expectedPlayers)
		self.hosted = true
		
		self.sim = Simulation:new(self.sync, true)
		self.fake = Simulation:new(nil, nil, true)
		self.nick = nick
		if self.sync:host(port, expectedPlayers, nick) then
			return true
		end
	end
end

function GameState:startClient(ip, port, nick)
	if not self.hosted and not self.connected then
		self.connected = true

		self.sim = Simulation:new(nil, true)
		self.fake = Simulation:new()
		self.nick = nick
		--print("joining " ..ip.. " "..port)
		self.sync:join(ip, port)
	end
end

--[[
                                                                  
88        88                      88                               
88        88                      88              ,d               
88        88                      88              88               
88        88 8b,dPPYba,   ,adPPYb,88 ,adPPYYba, MM88MMM ,adPPYba,  
88        88 88P'    "8a a8"    `Y88 ""     `Y8   88   a8P_____88  
88        88 88       d8 8b       88 ,adPPPPP88   88   8PP"""""""  
Y8a.    .a8P 88b,   ,a8" "8a,   ,d88 88,    ,88   88,  "8b,   ,aa  
 `"Y8888Y"'  88`YbbdP"'   `"8bbdP"Y8 `"8bbdP"Y8   "Y888 `"Ybbd8"'  
             88                                                    
             88          

]]

function GameState:update(time)
	self.time = self.time + time	
	
	if self.mouse:update(time) then
		local nx = self.view:xToCamera(self.mouse.screenX, self.camera)
		local ny = self.view:yToCamera(self.mouse.screenY, self.camera)
		self.mouse:set(nx,ny)
	end

	if self.sync then
		local player = self.sync:getLocalPlayer()
		if player then
			if player.pilot then
				local pilot = player.pilot
				if pilot.ship then
					local ship = pilot.ship
					if self.fake:hasEid(pilot.ship.eid) then
						ship = self.fake:getProxy(pilot.ship)

						ship:updateHudSounds(time)
						local interp = ship:getInterpolation(self.fake.time) or 0
						if interp then
							local speed = math.distance(0,0,ship:interp("dx", interp), ship:interp("dy", interp))

							
							--self.camera:setPosition(ship.x, ship.y)
							local zoomTarget = math.max(0.05,(100/(100+math.sqrt(speed)*14)))
							self.camera:zoomSmooth(zoomTarget, 10, time, 0.1)
							local wx = ship.map:cameraToMapX(self.mouse.x, self.camera)
							local wy = ship.map:cameraToMapY(self.mouse.y, self.camera)
							local relX = wx - ship:interp("x", interp)
							local relY = wy - ship:interp("y", interp)
							local angle = math.angleBetweenPoints(0,0, relX, relY)
							local amt = math.distance(0,0, relX, relY*canvas.factor)/(canvas.w*0.5)*self.camera.zoom*1.25
							self.sync:broadcast("relayInput", angle, amt, self.mouse.left, self.mouse.right)

							local tx, ty = ship:interp("x", interp) + relX*0.3, ship:interp("y", interp) + relY*0.3
							if math.distance(self.camera.x, self.camera.y, tx, ty) > 25000 then
								self.camera:setPosition(tx, ty)
							else
								self.camera:moveSmooth(time,tx, ty, 10 + speed/200)
							end
							self.camera:setPosition(self.camera.x, self.camera.y)
						end

					end
				end
			end
		end
	end
	

	self.sync:update(time)
		
	self.sim:update(time)

	if self.hosted then
		self.sim:broadcast(time)
		for index, team in pairs(self.sim.map.teams) do
			if team.dead then
				self.resetDelay = self.resetDelay + time
			end
		end
		if self.resetDelay > 10 then
			self.sim:setMap(self.width, self.height, os.time())
			self.resetDelay = nil
		end
	end

	self.fake:updateTowards(self.sim, time)
	
	self.sim:clearChanges()

	self.view:update(time)
	self.camera:update(time)
	self.mouse:postUpdate()

	if self.whiteOut > 0 then
		self.whiteOut = math.max(0,self.whiteOut  -time)
	end

	self.optionsFade = math.crossFade(self.showOptions, self.optionsFade, time*2)
end

--[[

                                                                                                                                        
 ad88888ba                                          ,ad8888ba,             88 88 88                                88                   
d8"     "8b                                        d8"'    `"8b            88 88 88                                88                   
Y8,                                               d8'                      88 88 88                                88                   
`Y8aaaaa,   8b       d8 8b,dPPYba,   ,adPPYba,    88            ,adPPYYba, 88 88 88,dPPYba,  ,adPPYYba,  ,adPPYba, 88   ,d8  ,adPPYba,  
  `"""""8b, `8b     d8' 88P'   `"8a a8"     ""    88            ""     `Y8 88 88 88P'    "8a ""     `Y8 a8"     "" 88 ,a8"   I8[    ""  
        `8b  `8b   d8'  88       88 8b            Y8,           ,adPPPPP88 88 88 88       d8 ,adPPPPP88 8b         8888[      `"Y8ba,   
Y8a     a8P   `8b,d8'   88       88 "8a,   ,aa     Y8a.    .a8P 88,    ,88 88 88 88b,   ,a8" 88,    ,88 "8a,   ,aa 88`"Yba,  aa    ]8I  
 "Y88888P"      Y88'    88       88  `"Ybbd8"'      `"Y8888Y"'  `"8bbdP"Y8 88 88 8Y"Ybbd8"'  `"8bbdP"Y8  `"Ybbd8"' 88   `Y8a `"YbbdP"'  
                d8'                                                                                                                     
               d8'                                                                                                
               
               
]]

function GameState:onEntChanged(ent)
	if self.fake then
		if self.fake:hasEid(ent.eid) then
			self.fake:interpolateEnt(self.fake:getProxy(ent), ent)
		end
	end
end

function GameState:selectOption(player, optionsId, option)
	if self.sim then
		self.sim:selectOption(player,optionsId, option)
	end
end

function GameState:setOptions(description, options)
	self.showOptions = true
	self.optionsDescription = description
	self.options = options
end

function GameState:onStarted()
	self.sync:broadcast("setNick", self.nick or "-")
end

function GameState:getEnt(eid)
	if self.sim then
		return self.sim:getEnt(eid)
	else
		print("does not have sim, cannot get ent")
	end
end

function GameState:onJoined(player)
	if self.sim then
		self.sim:sendTo(player)
		for index, p in pairs(self.sync.players) do
			self.sync:sendTo(player.guid, "assignNick", p.guid, p.nick)
		end
		--print(player.id, "joined")
	end
end

function GameState:removeEnt(eid)
	if self.sim then
		if self.sim:hasEid(eid) then
			local ent = self.sim:getEnt(eid)
			if ent then
				ent:remove()
			else
				print("warning: ", eid, "did not exist")
			end
		end
	end
end

function GameState:createEnt(eid, ...)
	if self.sim then
		self.sim:implement(eid, ...)
	end
end

function GameState:assignEnt(parent, index, child)
	if self.sim then
		self.sim:assignEnt(parent, index, child)
	end
end


--[[

                                                        
  ,ad8888ba,                              88            
 d8"'    `"8b                             88            
d8'                                       88            
88            88,dPYba,,adPYba,   ,adPPYb,88 ,adPPYba,  
88            88P'   "88"    "8a a8"    `Y88 I8[    ""  
Y8,           88      88      88 8b       88  `"Y8ba,   
 Y8a.    .a8P 88      88      88 "8a,   ,d88 aa    ]8I  
  `"Y8888Y"'  88      88      88  `"8bbdP"Y8 `"YbbdP"'  
                                                                                                                                                                      

]]

function GameState:onCommand(guid, commandType, ...)
	print(commandType)
end

--[[
                                                                     
88888888ba                                 88                        
88      "8b                                88                        
88      ,8P                                88                        
88aaaaaa8P' ,adPPYba, 8b,dPPYba,   ,adPPYb,88  ,adPPYba, 8b,dPPYba,  
88""""88'  a8P_____88 88P'   `"8a a8"    `Y88 a8P_____88 88P'   "Y8  
88    `8b  8PP""""""" 88       88 8b       88 8PP""""""" 88          
88     `8b "8b,   ,aa 88       88 "8a,   ,d88 "8b,   ,aa 88          
88      `8b `"Ybbd8"' 88       88  `"8bbdP"Y8  `"Ybbd8"' 88          
                                                                     

]]

local LowhudColor = {a = 64, r = 64, g = 255, b = 64}
local HighhudColor = {a = 128, r = 128, g = 255, b = 128}

function GameState:render()
	self.view:apply()
	
	if self.fake then
		self.fake:renderInterpolatedAt(self.camera, canvas.w*0.5,canvas.h*0.5, 1, 0, 255, 255, 255, 255)
	end

	--if self.sim then
	--	self.sim:renderAt(self.camera, canvas.w*0.5,canvas.h*0.5, 1, 0, 128, 0, 255, 0)
	--end

	self.view:restore()
	--self.view:render()
	if self.sync then
		self.sync:renderPlayers(canvas.w*0.5,canvas.h*0.5, 1, 0, 255, 255, 255, 255)
	end

	if self.sync then
		local player = self.sync:getLocalPlayer()
		if player then
			if player.team then
				self.fake.map:renderTeamsHud(canvas.w*0.5, canvas.h*0.95, 128,255,255,255)
				--for index, team in ipairs(self.fake.map.teams) do
				--	local friend = (team == player.team)
				--	local x = canvas.w*0.25
				--	local y = canvas.h*0.9
--
				--	--team:renderHud(canvas.w*0.5, canvas.h*0.05, HighhudColor.a,HighhudColor.r,HighhudColor.g,HighhudColor.b)
				--	--video.renderSpriteState(SPRITES.hud_friendlyBat, x, y)
				--end
				video.renderTextSprites(player.team:getName(), canvas.w*0.02, canvas.h*0.02, 0, "small", 128,255,255,255)
			end
			if player.pilot then
				if player.pilot.ship then
					if self.fake:hasEid(player.pilot.ship.eid) then
						local ship = self.fake:getProxy(player.pilot.ship)
						if ship then
							--ship:renderTargetHud(canvas.w*0.5, canvas.h*0.5,HighhudColor.a,HighhudColor.r,HighhudColor.g,HighhudColor.b)
							local interp = ship:getInterpolation(self.fake.time) or 0
							ship:renderHudBars(canvas.w*0.5, canvas.h*0.05, HighhudColor.a,HighhudColor.r,HighhudColor.g,HighhudColor.b, interp)
							ship:renderHudAltitude(canvas.w*0.97, canvas.h*0.5, LowhudColor.a,LowhudColor.r,LowhudColor.g,LowhudColor.b, interp)
						end
					end
				end
			end
		end
	end

	if self.showOptions or self.optionsFade > 0 then
		video.renderRectangle(0,0,canvas.w, canvas.h, self.optionsFade*200, 0,0,0)
		video.renderShadowedTextSprites(self.optionsDescription, canvas.w*0.5, canvas.h*0.4,1, "big", self.optionsFade*255, 255, 255, 255)
		for index, option in ipairs(self.options) do
			local txt = index..". "
			if option.ent then
				txt = txt .. option.ent:getName()
			end
			local light = 120
			if option.highlight then
				light = 255 - math.abs(math.cos(self.time*30))*150
			end
			video.renderShadowedTextSprites(txt, canvas.w*0.5, canvas.h*0.4 + 50 + 30*index,1, "medium", self.optionsFade*255, light, light, light)
		end
	end

	if self.whiteOut > 0 then
		video.renderRectangle(0,0,canvas.w,canvas.h, 255*math.min(1,self.whiteOut), 255, 255, 255)
	end


end
                                                                                                    
--[[
                                                          
88        88                         88                   
88        88                         88                   
88        88                         88                   
88aaaaaaaa88  ,adPPYba,   ,adPPYba,  88   ,d8  ,adPPYba,  
88""""""""88 a8"     "8a a8"     "8a 88 ,a8"   I8[    ""  
88        88 8b       d8 8b       d8 8888[      `"Y8ba,   
88        88 "8a,   ,a8" "8a,   ,a8" 88`"Yba,  aa    ]8I  
88        88  `"YbbdP"'   `"YbbdP"'  88   `Y8a `"YbbdP"'  
                                                          
                                                          
]]

function GameState:keyPressed(key)
	if key >= 49 and key <= 49+9 then
		local num = key - 48
		if self.showOptions then
			if self.options[num] then
				self.options[num].highlight = true
			end
			self.sync:broadcast("selectOption", num)
			self.showOptions = false
		end
	end
end

function GameState:mouseClick(x, y, button, clickCount)
	self.mouse:onClick(x,y,button,clickCount)
end