dofile "../media/scripts/editorCreation.lua"
dofile "../media/scripts/editorObjectControl.lua"

function Initialize()
	-- no smart pointer support for swig<->lua, inputController gets created in the c++ code
	--OWNER:SetInputController( "inputController", game.InputController_Create( GAME:GetInputSystem(), "../media/data/editorKeys.xml" )  )
	
	local viewport = game.RenderSystem_GetInstance():GetDefaultViewport()
	viewport:GetCameraPointer():SetZoom( game.Vector( 20, 20 ) )
	
	GAME:GetGameState():GetEntityManager():GetEntity( "Selection" ):Disable()
	
	mouseDown = false
	movable = false
   
	OWNER:SetString( "filename", "../media/data/levels/level_test.xml" )
	
	OWNER:SetString( "lastAction", "" )
	OWNER:SetInt( "numRotators", 0 )
	OWNER:SetInt( "numWalls", 0 )
	OWNER:SetInt( "numDeathZones", 0 )
	OWNER:SetInt( "numGoals", 0 )
	OWNER:SetInt( "numCheckpoints", 0 )

	OWNER:SetString( "selectedEntity", "" )
	
	LoadLevel()
	
	print( "Editor - Initialization finished" )
end

function Update()
	if OWNER:GetInputController( "inputController" ):IsAction( "newRotator" ) then
		CreateRotator()
	elseif OWNER:GetInputController( "inputController" ):IsAction( "newWall" ) then
		CreateWall()
	elseif OWNER:GetInputController( "inputController" ):IsAction( "newDeathZone" ) then
		CreateDeathZone()
	elseif OWNER:GetInputController( "inputController" ):IsAction( "newGoal" ) then
		CreateGoal()
	elseif OWNER:GetInputController( "inputController" ):IsAction( "newCheckpoint" ) then
		CreateCheckpoint()
	elseif OWNER:GetInputController( "inputController" ):IsAction( "save" ) then
		Save()
	else
		OWNER:SetString( "lastAction", "" )
	end
	
	MoveScreenBorders()
	
	if OWNER:GetString( "selectedEntity" ) ~= "" then
		if mouseDown and not GAME:GetInputSystem():IsKeyboardButtonPressed( GAME:GetInputSystem():GetButtonByName( "K_Ctrl" ) ) and 
		   movable   and not GAME:GetInputSystem():IsKeyboardButtonPressed( GAME:GetInputSystem():GetButtonByName( "K_Shift" ) ) then
			Translate()
		end
		
		local selectedEnt = GAME:GetGameState():GetEntityManager():GetEntity( OWNER:GetString( "selectedEntity" ) )
		local selectedEntPos = game.Vector( selectedEnt:GetNode():GetPosition() )
		selectedEntPos.m_z = 0.1
		GAME:GetGameState():GetEntityManager():GetEntity( "Selection" ):GetNode():SetPosition( selectedEntPos )
	end
	
	
	
end

function HandleEvent( event )
	if event:GetID() == "Event_MouseButtonPressed" then

		if OWNER:GetString( "selectedEntity" ) == nil or ( not GAME:GetInputSystem():IsKeyboardButtonPressed( GAME:GetInputSystem():GetButtonByName( "K_Ctrl" ) ) and 
		                                                   not GAME:GetInputSystem():IsKeyboardButtonPressed( GAME:GetInputSystem():GetButtonByName( "K_Shift" ) ) ) then
			SelectEntity()
			local selection = GAME:GetGameState():GetEntityManager():GetEntity( "Selection" )
			if OWNER:GetString( "selectedEntity" ) ~= "" then
				local selectedEnt = GAME:GetGameState():GetEntityManager():GetEntity( OWNER:GetString( "selectedEntity" ) )
				selection:GetNode():Set( selectedEnt:GetNode():GetPosition(), selectedEnt:GetNode():GetOrientation(), selectedEnt:GetNode():GetScale() )
				selection:Enable()
				movable = true
			else
				selection:Disable()
			end
		end
		
		mouseDown = true
		
	elseif event:GetID() == "Event_MouseButtonReleased" then	
		mouseDown = false
		
	elseif event:GetID() == "Event_MouseMoved" then
		--MoveScreenBordersDelta( event:GetDelta() )
	
		if event:GetDelta().m_z ~= 0 then
			Zoom( event:GetDelta().m_z )
		end
		
		if mouseDown and OWNER:GetString( "selectedEntity" ) ~= "" then
			if GAME:GetInputSystem():IsKeyboardButtonPressed( GAME:GetInputSystem():GetButtonByName( "K_Ctrl" ) ) then
				Scale( event:GetDelta() )
			elseif GAME:GetInputSystem():IsKeyboardButtonPressed( GAME:GetInputSystem():GetButtonByName( "K_Shift" ) ) then
				Rotate( event:GetDelta() )
			end
		end
	elseif event:GetID() == "Event_KeyboardButtonPressed" then
		if event:GetButtonName() == "K_Del" and OWNER:GetString( "selectedEntity" ) ~= "" then
			DeleteEntity()
		end
	end
end

-- only moving when mouse is moved
function MoveScreenBordersDelta( deltas )
	local position = game.Vector( GAME:GetInputSystem():GetMousePosition().m_x, GAME:GetInputSystem():GetMousePosition().m_y )
	local viewport = game.RenderSystem_GetInstance():GetDefaultViewport()
	local camera = viewport:GetCameraPointer()

	if position.m_x <= 1 and deltas.m_x < 0 then
		camera:Translate( game.Vector( deltas.m_x / camera:GetZoom().m_x, 0 ) )
	elseif position.m_x >= viewport:GetWidth() - 1 and deltas.m_x > 0 then
		camera:Translate( game.Vector( deltas.m_x / camera:GetZoom().m_x, 0 ) )
	elseif position.m_y <= 1 and deltas.m_y < 0 then
		camera:Translate( game.Vector( 0, deltas.m_y / camera:GetZoom().m_y ) )
	elseif position.m_y >= viewport:GetHeight() - 1 and deltas.m_y > 0 then
		camera:Translate( game.Vector( 0, deltas.m_y / camera:GetZoom().m_y ) )
	end
end

-- moving when cursor is at the border
function MoveScreenBorders()
	local position = game.Vector( GAME:GetInputSystem():GetMousePosition().m_x, GAME:GetInputSystem():GetMousePosition().m_y )
	local viewport = game.RenderSystem_GetInstance():GetDefaultViewport()
	local camera = viewport:GetCameraPointer()
	
	if position.m_x <= 5 then
		camera:Translate( game.Vector( -5 / camera:GetZoom().m_x, 0 ) )
	elseif position.m_x >= viewport:GetWidth() - 5 then
		camera:Translate( game.Vector( 5 / camera:GetZoom().m_x, 0 ) )
	elseif position.m_y <= 5 then
		camera:Translate( game.Vector( 0, 5 / camera:GetZoom().m_y ) )
	elseif position.m_y >= viewport:GetHeight() - 5 then
		camera:Translate( game.Vector( 0, -5 / camera:GetZoom().m_y ) )
	end
end

function Zoom( delta )
	local factor = 1 + math.abs( 0.2 * delta / 120 ) -- multiple of 120
	local zoom = game.RenderSystem_GetInstance():GetDefaultViewport():GetCameraPointer():GetZoom().m_x
	local oldZoom = zoom
	
	if delta < 0 then 
		zoom = zoom / factor
	else
		zoom = zoom * factor
	end
	
	print( "zoom: " .. zoom )
	local position = game.Vector( GAME:GetInputSystem():GetMousePosition().m_x, GAME:GetInputSystem():GetMousePosition().m_y )
	
	local dx = -( game.RenderSystem_GetInstance():GetDefaultViewport():GetWidth() / 2 - position.m_x )
	local dy = -( game.RenderSystem_GetInstance():GetDefaultViewport():GetHeight() / 2 - position.m_y )
	

	local newDx = dx / oldZoom * zoom
	local newDy = dy / oldZoom * zoom
	
	game.RenderSystem_GetInstance():GetDefaultViewport():GetCameraPointer():Translate( game.Vector( -( dx - newDx ) / zoom, ( dy - newDy ) / zoom ) )
	game.RenderSystem_GetInstance():GetDefaultViewport():GetCameraPointer():SetZoom( game.Vector( zoom, zoom ) )
end

function DeleteEntity()
	local entID = OWNER:GetString( "selectedEntity" )
	local toDel
	local lastEnt
	
	if string.find( entID, "rotator" ) ~= nil then
		toDel = "rotator" .. ( OWNER:GetInt( "numRotators" ) - 1 )
		lastEnt = GAME:GetGameState():GetEntityManager():GetEntity( "rotator" .. OWNER:GetInt( "numRotators" ) - 1 )
		OWNER:SetInt( "numRotators", OWNER:GetInt( "numRotators" ) - 1 )
	elseif string.find( entID, "checkpoint" ) ~= nil then
		toDel = "checkpoint" .. ( OWNER:GetInt( "numCheckpoints" ) - 1 )
		lastEnt = GAME:GetGameState():GetEntityManager():GetEntity( "checkpoint" .. OWNER:GetInt( "numCheckpoints" ) - 1 )
		OWNER:SetInt( "numCheckpoints", OWNER:GetInt( "numCheckpoints" ) - 1 )
	elseif string.find( entID, "deathZone" ) ~= nil then
		toDel = "deathZone" .. ( OWNER:GetInt( "numDeathZones" ) - 1 )
		lastEnt = GAME:GetGameState():GetEntityManager():GetEntity( "deathZone" .. OWNER:GetInt( "numDeathZones" ) - 1 )
		OWNER:SetInt( "numDeathZones", OWNER:GetInt( "numDeathZones" ) - 1 )
	elseif string.find( entID, "goal" ) ~= nil then
		toDel = "goal" .. ( OWNER:GetInt( "numGoals" ) - 1 )
		lastEnt = GAME:GetGameState():GetEntityManager():GetEntity( "goal" .. OWNER:GetInt( "numGoals" ) - 1 )
		OWNER:SetInt( "numGoals", OWNER:GetInt( "numGoals" ) - 1 )
	elseif string.find( entID, "wall" ) ~= nil then
		toDel = "wall" .. ( OWNER:GetInt( "numWalls" ) - 1 )
		lastEnt = GAME:GetGameState():GetEntityManager():GetEntity( "wall" .. OWNER:GetInt( "numWalls" ) - 1 )
		OWNER:SetInt( "numWalls", OWNER:GetInt( "numWalls" ) - 1 )
	end
	
	GAME:GetGameState():GetEntityManager():GetEntity( entID ):GetNode():Set( lastEnt:GetNode():GetPosition(), lastEnt:GetNode():GetOrientation(), lastEnt:GetNode():GetScale() )
	GAME:GetGameState():GetEntityManager():RemoveEntity( toDel );
	
	OWNER:SetString( "selectedEntity", "" )
end

function LoadLevel()
	local file = io.open( OWNER:GetString( "filename" ), "r" )
	if file ~= nil then
		local reader = game.XMLEntityReader()
		GAME:GetGameState():GetEntityFactory():CreateEntities( reader:ReadEntitiesFromXMLFile( OWNER:GetString( "filename" ) ) ,true )
		
		local entManager = GAME:GetGameState():GetEntityManager()
		local val = 0
		ent = entManager:GetEntity( "rotator0" )
		while entManager:HasEntity( "rotator" .. val ) do
			val = val + 1
		end
		OWNER:SetInt( "numRotators", val )
		
		val = 0
		while entManager:HasEntity( "wall" .. val ) do
			val = val + 1
		end
		OWNER:SetInt( "numWalls", val )
		
		val = 0
		while entManager:HasEntity( "checkpoint" .. val ) do
			val = val + 1
		end
		OWNER:SetInt( "numCheckpoints", val )
		
		val = 0
		while entManager:HasEntity( "deathZone" .. val ) do
			val = val + 1
		end
		OWNER:SetInt( "numDeathZones", val )
		
		val = 0
		while entManager:HasEntity( "goal" .. val ) do
			val = val + 1
		end
		OWNER:SetInt( "numGoals", val )
	end
end

function Save()
	if OWNER:GetString( "lastAction" ) == "save" then
		return
	end
	
	local file = io.open( OWNER:GetString( "filename" ) , "w+" )
	file:write( "<level>\n" )
	
	for i = 0, OWNER:GetInt( "numRotators" ) - 1 do
		SaveEntity( file, "rotator", i )
	end
	
	for i = 0, OWNER:GetInt( "numDeathZones" ) - 1 do
		SaveEntity( file, "deathZone", i )
	end
	
	for i = 0, OWNER:GetInt( "numGoals" ) - 1 do
		SaveEntity( file, "goal", i )
	end
	
	for i = 0, OWNER:GetInt( "numWalls" ) - 1 do
		SaveEntity( file, "wall", i )
	end
	
	for i = 0, OWNER:GetInt( "numCheckpoints" ) - 1 do
		SaveEntity( file, "checkpoint", i )
	end
	
	file:write( "</level>\n" )
	file:close()
	OWNER:SetString( "lastAction", "save" )
	print( "save complete" )
end

function SaveEntity( file, entType, nr )
	node = GAME:GetGameState():GetEntityManager():GetEntity( entType .. nr ):GetNode2D()
	
	file:write( "\t<entity id=\"" .. entType .. nr .. "\" parent=\"" .. string.upper( string.sub( entType, 0, 1 ) ) .. string.sub( entType, 2 ) .."\" >\n" )
	file:write( "\t\t<node type=\"2D\">\n" )
	file:write( "\t\t\t<position>\n" )
	file:write( "\t\t\t\t<x>" .. node:GetPosition().m_x .. "</x>\n" )
	file:write( "\t\t\t\t<y>" .. node:GetPosition().m_y .. "</y>\n" )
	file:write( "\t\t\t\t<z>" .. node:GetPosition().m_z .. "</z>\n" )
	file:write( "\t\t\t</position>\n" )
	file:write( "\t\t\t<orientation>\n" )
	file:write( "\t\t\t\t<angle>" .. node:GetAngle():ToFloat() .. "</angle>\n" )
	file:write( "\t\t\t</orientation>\n" )
	file:write( "\t\t\t<scale>\n" )
	file:write( "\t\t\t\t<x>" .. node:GetScale().m_x .. "</x>\n" )
	file:write( "\t\t\t\t<y>" .. node:GetScale().m_y .. "</y>\n" )
	file:write( "\t\t\t\t<z>" .. node:GetScale().m_z .. "</z>\n" )
	file:write( "\t\t\t</scale>\n" )
	file:write( "\t\t</node>\n" )
	file:write( "\t</entity>\n" )
end