--[[

                                                                                                       
  ,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(players, seed, start_level, max_level)
	local o = instance(self)
	o.time = 0
	o.step_time = 0
	o.view = View:new()
	o.seed = seed
	o.start_level = start_level
	o.max_level = max_level
	o.players = players
	o.camera = Camera:new(o.view)
	o.camera:setZoom(2)
	o.camera:setPerspective(0.7)
	o.mouse = Mouse:new()
	return o
end

function GameState:init()
	self:generate()
	self:spawn_players()
end

function GameState:generate()
	assert(self.players, "no players!")
	assert(self.seed, "no seed!")
	assert(self.start_level, "no seed!")
	assert(self.max_level, "no seed!")
	local seed = self.seed
	local num_players = #self.players
	local start_level = self.start_level
	local max_level = self.max_level
	local rules = Rules:new(seed, start_level, max_level)
	local chunks = 64
	local chunk_size = 8
	local cell_pixels = 20	

	local universe = Universe:new("default", seed, num_players, chunks, chunks, chunk_size, cell_pixels, start_level, max_level, rules)
	self.universe = universe
	self.rules = rules

	local world = World:new(universe, rules)
	for index, sys_class in ipairs(SYSTEMS) do --retain order
		world:add_system(sys_class:new())
	end
	self.world = world

	universe:generate(world)
end

function GameState:spawn_players()
	local spawn = self.universe:get_spawn_point()
	local team = self.universe:get_player_team()
	for index, player in pairs(self.players) do
		local ent = self.rules:generate_instance("character", "hero", self.start_level)		
		ent:set_position(spawn.x, spawn.y, 400)
		ent:set_player(player)
		ent:set_team(team)
		player:set_game(self)
		player:set_ent(ent)

		self.universe:add_ent(ent)
		self.camera:set_position(ent.x, ent.y)
	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
	local world = self.world
	local universe = self.universe
	if universe:is_generating() then
		universe:update_generation()
	else
		local camera = self.camera
		
		for index, player in pairs(self.players) do
			local x,y = daisy.getMousePosition()
			local cx,cy = self:screen_to_camera(x,y)
			player:check_input()
			player:update_gui(time, x, y)
			player:set_cursor(x, y, cx, cy)
			local col,row = universe:position_to_col_row(cx,cy)
			--universe:set_tile(col,row, "graveyard_path")
		end

		world:watch_universe(camera, time)
		self.world:step(time)
		
			
		local cx, cy = 0,0
		local num_mid = 0
		local ox,oy = self:get_render_origo()
		for index, player in pairs(self.players) do
			local ent = player.ent
			if ent then			
				local cursor = player.input.cursor
				cx = cx + ent.rx --+ (cursor.x-ox)*0.5
				cy = cy + ent.ry --+ (cursor.y-oy)*0.5
				num_mid = num_mid + 1
			end
		end

		if num_mid > 0 then
			local avg_x = cx/num_mid
			local avg_y = cy/num_mid
			self.camera:move_smooth(time, avg_x, avg_y, 8*camera.zoom)
			--self.camera:set_position(avg_x, avg_y)
		end

		camera:update(time)
		universe.stepped = true
	end
end

function GameState:interpolate(prg)
	local universe = self.universe
	if not universe:is_generating() then
		self.world:interpolate(prg)
	end
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:onStarted()
end

--[[
                                         
 ad88888ba                               
d8"     "8b ,d                           
Y8,         88                           
`Y8aaaaa, MM88MMM ,adPPYba, 8b,dPPYba,   
  `"""""8b, 88   a8P_____88 88P'    "8a  
        `8b 88   8PP""""""" 88       d8  
Y8a     a8P 88,  "8b,   ,aa 88b,   ,a8"  
 "Y88888P"  "Y888 `"Ybbd8"' 88`YbbdP"'   
                            88           
                            88           

]]

function GameState:onStep(time)
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, ...)
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          
                                                                     

]]

function GameState:view_to_screen(x,y)
	return self.view:x_to_screen(x), self.view:y_to_screen(y)
end

function GameState:screen_to_view(x,y)
	return self.view:screen_x_to_view(x), self.view:screen_y_to_view(y)
end

function GameState:screen_to_camera(x,y)
	local camera = self.camera
	local world = self.world
	local ox,oy = self:get_render_origo()
	local scale = camera.zoom
	local perspective = camera.perspective
	local offset_x = (x-ox)
	local offset_y = (y-oy)	
	local rx = offset_x/scale
	local ry = offset_y/scale/perspective
	local vx,vy = self:screen_to_view(rx,ry)
	local cx,cy = world:screen_to_camera(vx,vy,camera)
	return cx,cy
end

function GameState:camera_to_screen(cx,cy)
	local camera = self.camera
	local world = self.world
	local scale = camera.zoom
	local perspective = camera.perspective
	local vx,vy = world:camera_to_screen(cx,cy, camera)
	local rx,ry = self:view_to_screen(vx,vy)
	local offset_x = rx*scale
	local offset_y = ry*scale*perspective
	local ox,oy = self:get_render_origo()
	local x = offset_x+ox
	local y = offset_y+oy	
	return x,y
end

function GameState:get_render_origo()
	return canvas.w*0.5,canvas.h*0.5
end

function GameState:render()
	local universe = self.universe
	if universe:is_generating() then
		local cx,cy = canvas.w*0.5, canvas.h*0.5
		video.renderTextSprites("GENERATING...",cx,cy,1, "big", 255, 255, 255, 255)
		local prg = universe:get_generating_progress()
		local percent = string.getPercent(prg)
		video.renderTextSprites(percent,cx,cy+fonts.getHeight("big")*1.1,1, "big", 255, 128, 128, 128)
	elseif universe.stepped then
		local camera = self.camera
		local ox,oy = self:get_render_origo()
		local cx,cy = self:view_to_screen(ox,oy)
		
		self.world:render(camera, cx,cy,255,255,255,255)	
		for index, player in pairs(self.players) do		
			player:render_gui(1, 0, 255, 255, 255, 255)
		end
		self.world:render_hud(camera, cx,cy,255,255,255,255)	
		for index, player in pairs(self.players) do
			local cursor = player.input.cursor		
			local rx,ry = self:camera_to_screen(cursor.camera_x, cursor.camera_y)
			--print(cox,coy)
			video.renderSpriteState(SPRITES.plus, rx,ry, 0.25, 0, 128, 255, 255, 0)
			player:render_hud(1, 0, 255, 255, 255, 255)
		end
	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)
end

function GameState:mouseClick(x, y, button, clickCount)
end


--[[


88888888ba             88                                                              
88      "8b            ""              ,d                             ,d               
88      ,8P                            88                             88               
88aaaaaa8P' 8b,dPPYba, 88 8b,dPPYba, MM88MMM ,adPPYba,  88       88 MM88MMM ,adPPYba,  
88""""""'   88P'   "Y8 88 88P'   `"8a  88   a8"     "8a 88       88   88    I8[    ""  
88          88         88 88       88  88   8b       d8 88       88   88     `"Y8ba,   
88          88         88 88       88  88,  "8a,   ,a8" "8a,   ,a88   88,   aa    ]8I  
88          88         88 88       88  "Y888 `"YbbdP"'   `"YbbdP'Y8   "Y888 `"YbbdP"'  
                                                                                       
                                                                                                                                                                            
]]

function GameState:onError(err)
	print("ERR "..err)
end

function GameState:onMessage(msg)
	print("MSG "..msg)
end

function GameState:onData(data)
	print("DATA "..tostring(data))
end

--[[

video.renderRectangle(0,0,canvas.w, canvas.h, 255,255,255,255)
	local rx = 100
	for index, shap in pairs(shapes) do
		video.renderSpriteState(shap, rx, 300, 1, 0, 255,255,255,255)
		rx = rx + 80
	end
	
		for index, shap in pairs(video.getSpriteStateNames("defs/shapes.dat")) do
		shapes[shap] = video.createSpriteState(shap, "defs/shapes.dat")
	end
	
]]