local utils = require("utils")
local tblUtil = utils.table
local dialogs = require("dialogs")
local class = require("class")
local async_util = require("async_util")

local md = require("debugFunctions")

local SystemMapController = class()

function SystemMapController:init()

	self.mouse = {
		mx = 0,
		my = 0,
		threshold = 25,
		speed = 7,
		active = false
	}
	
	self.scale = 1
	self.closeup = false
	self.mouseScrollDisabled = false
	self.zoom = 0
	self.focalWidth = 0.5
	self.focalHeight = 0.5

end

function SystemMapController:initialize(document)

    self.document = document
	
	---Load the desired font size from the save file
	self.document:GetElementById("main_background"):SetClass(("p1-" .. ScpuiSystem:getFontSize()), true)
	
	self.mainMap = self.document:GetElementById("map")
	self.back_el = self.document:GetElementById("top_panel_wrapper")
	
	self:DoInitialLoad()
	
end

function SystemMapController:DoInitialLoad()

	local filename = "sysview_objects.cfg"
	
	if cf.fileExists(filename, "data/config", true) then
		self.Objects = utils.loadConfig(filename)
	end
	
	self:LoadConfig()
	
	self:LoadNewSystem(self:AutoLoadSystem())
	
	--hide the closeup div by default
	self.document:GetElementById("closeup_container"):SetClass("hidden", true)
	
end


--load the config file based on the current campaign
function SystemMapController:LoadConfig()

	local filename = "sysview_" .. ba.getCurrentPlayer():getCampaignFilename() .. "_config.cfg"

	md.print("System Viewer got current campaign file as " .. filename)

	if cf.fileExists(filename, "data/config", true) then
		self.Config = utils.loadConfig(filename)
		self.Systems = utils.loadConfig(self.Config.File)
	end

	--self:ProcessJsonData(self.Systems)

end

--[[function SystemMapController:ProcessJsonData(data)
	
	local objects = self.Objects
	
	for _, v in pairs(data) do
		for _, e in pairs(v.Elements) do
			local o_name = e.Name[1]
			--if objects[o_name] ~= nil then
			--	o_name = o_name .. "copy"
			--end
			
			objects[o_name] = {
				Name = e.Name,
				Bitmap = e.Bitmap,
				LargeBitmap = e.LargeBitmap,
				ShipClass = e.ShipClass,
				Description = e.Description
			}
			e.ObjectName = o_name
			e.Name = nil
			
			e.Bitmap = nil
			e.LargeBitmap = nil
			e.ShipClass = nil
			e.Description = nil
		end
	end
	
	local json = require('dkjson')
	
	file = cf.openFile('00_json_temp.cfg', 'w', 'data/players')
	file:write(json.encode(data))
	file:close()
	
	file = cf.openFile('01_json_temp.cfg', 'w', 'data/players')
	file:write(json.encode(objects))
	file:close()
end]]--

--Function to calculate the scale factor
function SystemMapController:calculateScaleFactor(screenWidth, imageWidth)
    --Ensure both inputs are positive numbers
    if screenWidth <= 0 or imageWidth <= 0 then
		ba.warning("Screen width or image with was <= 0! Using scale factor of 1!")
        return 1
    end

    local scaleFactor = screenWidth / imageWidth

	--Add 7 percent because they are designed as 2048w images on a 1920w screen
	--which is basically 7% bigger than the screen. This ensures the way these are designed
	--is recreated on all screen sizes very closely.
    return scaleFactor * 1.07
end

--Load a new system. This is the money right here. It does it all.
function SystemMapController:LoadNewSystem(systemname, zoomOnly)

	self.mouseScrollDisabled = false

	if systemname and self.Systems[systemname] then
	
		--first we try to clean up
		if self.texture ~= nil then
			self:CleanupBackground()
		end

		md.printAlways("System Viewer loading system " .. systemname)
		
		if not zoomOnly then
			self.focalWidth = 0.5
			self.focalHeight = 0.5
			self.doZoom = nil
		end

		self.CurrentSystem = self.Systems[systemname]
		self.CurrentSystem.Key = systemname
		
		--Get the system size
		local sys_w = gr.getImageWidth(self.CurrentSystem.Background)
		local sys_h = gr.getImageHeight(self.CurrentSystem.Background)
		
		--Get the screen size
		local screen_w = gr.getScreenWidth()
		local screen_h = gr.getScreenHeight()

		--Get the scale factor
		if screen_w > screen_h then
			self.scale = self:calculateScaleFactor(screen_w, sys_w) + self.zoom
		else
			self.scale = self:calculateScaleFactor(screen_h, sys_h) + self.zoom
		end
		
		--Get important information about the background (and by extension the view)
		self.CurrentSystem.w = sys_w * self.scale
		self.CurrentSystem.h = sys_h * self.scale
		
		self.texture = gr.createTexture(self.CurrentSystem.w, self.CurrentSystem.h)
		self.url = ui.linkTexture(self.texture)
		
		--Initialize any data
		self:InitializeObjectData(self.CurrentSystem.Elements)
		
		--Set the background and titles
		self:SetupSystem()
		
		--Generate the icon buttons
		self:GenerateIconButtons(self.CurrentSystem.Elements)
		
		--Handle the Back button
		if self.CurrentSystem.ZoomOutTo then
			self.back_el:SetClass("hidden", false)
		else
			self.back_el:SetClass("hidden", true)
		end
		
	else
		md.warning("No system with name " .. systemname .. " was found!")
		local mapEl = self.document:CreateElement("div")
		mapEl.inner_rml = utils.xstr("No System Loaded", -1)
		mapEl.id = "no_system_warning"
		self.mainMap:AppendChild(mapEl)
		self.back_el:SetClass("hidden", true)
	end

end

--Look through the config file stuff to see what we should load, first by mission name, then by "Default", if nothing then its nil
function SystemMapController:AutoLoadSystem()

	local systemname
	local missionname
	
	--Get current mission
	local oldState = ""
	if hv.OldState ~= nil then
		oldState = hv.OldState.Name
	end
	if mn.getMissionFilename() ~= "" and oldState ~= "GS_STATE_MAIN_MENU" then
		missionname = mn.getMissionFilename() .. ".fs2"
	else
		missionname = ca.getNextMissionFilename()
	end
	
	if missionname ~= nil then
		md.print("System Viewer detected next mission as " .. missionname)
	else
		--It's possible to get here at the end of the campaign.. so for BtA, let's check if that's the case
        --If so we'll force load the last map because we're cool like that
        local prevMission = ca.getPrevMissionFilename()
        if string.sub(prevMission, -9) == "m4_01.fs2" then
            missionname = prevMission
            md.print("System Viewer detected next mission as " .. missionname)
        else
            md.print("System Viewer could not detect the next mission. Loading default!")
        end
	end
	
	--Find a match
	if missionname ~= "" then
		for key, value in pairs(self.Config) do
			if missionname == key then
				systemname = value
			end	
		end
	end
	
	--Or just default
	if not systemname and self.Config.Default then
		systemname = self.Config.Default
	end
	
	return systemname

end

--Iterates through all map objects and sets up any data that's necessary
function SystemMapController:InitializeObjectData(iconTable)
	for key, value in pairs(iconTable) do
		
		--Do we have any visibility override data?
		require("sysmap_utils")
		local vis = sysmap_utils:GetIconVisibility(value.ObjectName)
		
		if vis ~= nil then
			value.Visible = vis
		end
		
		if value.ZoomTo then
			value.Seen = not sysmap_utils:CheckNew(value.ZoomTo)
		else
			if value.ShowNew == true or value.ShowNewPersist == true then
				value.Seen = sysmap_utils:GetIconSeen(self.CurrentSystem.Key, value)
			else
				value.Seen = true
			end
		end
	
		--Do we have object data? If so use that.
		if self.Objects ~= nil then
			if value.ObjectName then
				local obj = self.Objects[value.ObjectName]
				
				if obj ~= nil then
					value.Name = obj.Name
					value.Bitmap = obj.Bitmap
					value.LargeBitmap = obj.LargeBitmap
					value.ShipClass = obj.ShipClass
					value.Description = obj.Description
					value.UseTechDescription = obj.UseTechDescription
				end
			end
		end
		
		--Do we have an icon override? If so use that.
		if value.IconOverride then
			value.Bitmap = value.IconOverride
		end
		
		--Same for name override
		if value.NameOverride then
			value.Name = value.NameOverride
		end
	
		--Do we have a parent orbit? We should intialize it even if we don't.
		if not value.ParentOrbit then
			value.ParentOrbit = {}
			value.ParentOrbit.Distance = nil
			value.ParentOrbit.Angle = nil
		end
		
		--Specify a parent orbit
		if value.Orbits then
			value.ParentOrbit.Distance = iconTable[value.Orbits].Orbit.Distance
			value.ParentOrbit.Angle = iconTable[value.Orbits].Orbit.Angle
		end
		
		--If orbit is missing, we should slap in some dumb settings
		if not value.Orbit then
			value.Orbit = {}
			value.Orbit.Distance = 0
			value.Orbit.Angle = 0
		end
		
		if not value.Orbit.Color then --If there's no color set up, make one
			value.Orbit.Color = {128, 128, 128, 255}
		end
		
		--Same here
		if not value.Offset then
			value.Offset = {}
			value.Offset.X = 0
			value.Offset.Y = 0
		end
	end
end

function SystemMapController:SetupSystem()

	--Set the background	
	self:UpdateBackground()
	
	local mapEl = self.document:CreateElement("img")
	mapEl:SetAttribute("src", self.url)
	self.mainMap:AppendChild(mapEl)
	
	self.totalWidth = self.CurrentSystem.w - gr.getScreenWidth()
	self.totalHeight = self.CurrentSystem.h - gr.getScreenHeight()
	
	self.mainMap.scroll_left = self.totalWidth * self.focalWidth
	self.mainMap.scroll_top = self.totalHeight * self.focalHeight
	
	local title_el = self.document:GetElementById("system_title")
	
	--clean out any old titles
	while title_el:HasChildNodes() do
		title_el:RemoveChild(title_el.first_child)
	end
	
	--create new titles
	self.name_el = self.document:CreateElement("p")
	self.desc_el = self.document:CreateElement("p")
	
	self.name_el.inner_rml = utils.xstr(self.CurrentSystem.Name)
	self.desc_el.inner_rml = utils.xstr(self.CurrentSystem.Description)
	self.desc_el:SetClass("title_desc", true)
	
	self.name_el:SetClass(("h1-" .. ScpuiSystem:getFontSize()), true)
	self.desc_el:SetClass(("p2-" .. ScpuiSystem:getFontSize()), true)
	
	title_el:AppendChild(self.name_el)
	title_el:AppendChild(self.desc_el)
	
end

function SystemMapController:UpdateBackground()

	gr.setTarget(self.texture)
	
	gr.clearScreen(0,0,0,255)
	gr.drawImage(self.CurrentSystem.Background, 0, 0, self.CurrentSystem.w, self.CurrentSystem.h)
	
	self:DrawOrbits()
	
	gr.setTarget()
	
end

function SystemMapController:CleanupBackground()

	while self.mainMap:HasChildNodes() do
		self.mainMap:RemoveChild(self.mainMap.first_child)
	end
	
	self.texture:unload()
	self.texture = nil
	
end

function SystemMapController:DrawOrbits()
	--Draw all the orbits first, sure its an additional for loop but it prevents bad drawing
	for key, value in pairs(self.CurrentSystem.Elements) do
		if value.ShowOrbit and value.Visible then
			
			--Let's set the color and width
			if value.Orbit.Color == nil then
				value.Orbit.Color = {128, 128, 128, 255}
			end
			if value.Orbit.Width == nil then
				value.Orbit.Width = 3
			end
			gr.setColor(value.Orbit.Color[1], value.Orbit.Color[2], value.Orbit.Color[3], value.Orbit.Color[4])
			gr.setLineWidth(value.Orbit.Width)
			
			--Is the center in the middle of the system or...
			local x, y = self.CurrentSystem.w/2, self.CurrentSystem.h/2
			
			--Do we have a parent orbit?
			if value.ParentOrbit then
				if value.ParentOrbit.Distance and value.ParentOrbit.Angle then
					x, y = self:PolarToXY(value.ParentOrbit.Distance * self.scale, value.ParentOrbit.Angle, nil, nil)
				end
			end
			
			gr.drawCircle(value.Orbit.Distance * self.scale, x, y, false)
			gr.setLineWidth(1)
			
		end
	end
end

--Convert polar coordinates to rectangular coordinates. By default uses the middle of the background as an origin point.
function SystemMapController:PolarToXY(r, theta, origin_x, origin_y)

	theta = math.rad(theta)
	
	if not origin_x or not origin_y then
		origin_x = self.CurrentSystem.w/2
		origin_y = self.CurrentSystem.h/2
	end
	
	local x, y = (r * math.cos(theta)) + origin_x, (r * math.sin(theta)) + origin_y
		
	return x, y

end

--Sets coordinates for a button according to its specified polar coordinates
function SystemMapController:SetupButton(button)

	local px, py = nil, nil
	
	--If we have a parent orbit, calculate its coordinates first
	if button.ParentOrbit.Distance and button.ParentOrbit.Angle then
		px, py = self:PolarToXY(button.ParentOrbit.Distance * self.scale, button.ParentOrbit.Angle, nil, nil)
	end
	
	--Its ok if px and py are nil. Don't worry, I'm a doctor.
	local x, y = self:PolarToXY(button.Orbit.Distance * self.scale, button.Orbit.Angle, px, py)
	
	--Set up the bitmap and text positions
	button.BitmapX = x - ((gr.getImageWidth(button.Bitmap)/2) * self.scale) + (button.Offset.X * self.scale)
	button.BitmapY = y - ((gr.getImageHeight(button.Bitmap)/2) * self.scale)  + (button.Offset.Y * self.scale)

end

--Look through the Icons Table and generate buttons
function SystemMapController:GenerateIconButtons(iconTable)
	
	local parent_el = self.mainMap
			
	for key, value in pairs(iconTable) do
	
		if value.Visible then
	
			local button_el = nil
			if value.Selectable then
				button_el = self.document:CreateElement("button")
				button_el:SetClass("button_1", true)
			else
				button_el = self.document:CreateElement("div")
			end
			button_el:SetClass("icon", true)
			button_el:SetClass("icon_button", true)
			
			local span_el = self.document:CreateElement("span")
			span_el:SetClass("icon")
			
			local img_el = self.document:CreateElement("img")
			img_el:SetClass("pseudo_img")
			if not value.Bitmap then
				ba.warning("Icon '" .. value.ObjectName .. "' has no bitmap defined!")
			end
			img_el:SetAttribute("src", value.Bitmap)
			img_el.style.width = math.floor(gr.getImageWidth(value.Bitmap) * self.scale) .. "px"
			
			local seen_el = nil
			if value.Seen == false then
				seen_el = self.document:CreateElement("div")
				seen_el:SetClass("icon", true)
				seen_el:SetClass("exclamation", true)
				
				local seen_img_el = self.document:CreateElement("img")
				seen_img_el:SetClass("pseudo_img")
				seen_img_el:SetAttribute("src", "nav_new.png")
				seen_img_el.style.width = math.floor(gr.getImageWidth("nav_new.png") * self.scale) .. "px"
				
				seen_el:AppendChild(seen_img_el)
				
				value.Seen_el = seen_el
			end
			
			span_el:AppendChild(img_el)
			button_el:AppendChild(span_el)
			parent_el:AppendChild(button_el)
			
			if seen_el ~= nil then
				button_el:AppendChild(seen_el)
			end
			
			if value.Selectable then
			
				button_el:AddEventListener("mouseover", function(_, _, _)
					img_el:SetAttribute("src", value.Bitmap .. "_h")
				end)
				
				button_el:AddEventListener("mouseout", function(_, _, _)
					img_el:SetAttribute("src", value.Bitmap)
				end)
				
				button_el:AddEventListener("mousedown", function(_, _, _)
					img_el:SetAttribute("src", value.Bitmap .. "_c")
				end)
				
				button_el:AddEventListener("mouseup", function(_, _, _)
					img_el:SetAttribute("src", value.Bitmap .. "_h")
				end)
				
				button_el:AddEventListener("click", function(_, _, _)
					self:DisplayObjectInfo(value)
				end)
				
				button_el:SetClass("select", true)
				
			else
				button_el:SetClass("noselect", true)
				if value.ShowNew == true or value.ShowNewPersist == true then
					sysmap_utils:SetIconSeen(self.CurrentSystem.Key, value, true)
				end
			end
			
			--Set the text
			if value.Name then
				value.Text = utils.xstr(value.Name)
			else
				value.Text = ""
			end
			
			local text_el = self.document:CreateElement("span")
			text_el:SetClass("button_text_bottom", true)
			text_el:SetClass("pos", true)
			text_el:SetClass("icon_text", true)
			text_el.inner_rml = "<p>" .. value.Text .. "</p>"
			button_el:AppendChild(text_el)
			
			--Setup the button position
			self:SetupButton(value)
			button_el.style.top = value.BitmapY .. "px"
			button_el.style.left = value.BitmapX .. "px"
			button_el.style.width = math.floor(gr.getImageWidth(value.Bitmap) * self.scale) .. "px"
		end
	end

end

--Display a large image, across the entire screen and centered
function SystemMapController:DisplayObjectInfo(object)

	local closeup_el = self.document:GetElementById("closeup_container")
	
	if object == nil then
		return
	end
	
	closeup_el:SetClass("hidden", false)
	
	self.closeup = true
	
	--create the visible object
	local object_el = self.document:GetElementById("object_view")
	
	if object.LargeBitmap then
		local imgEl = self.document:CreateElement("img")
		imgEl:SetAttribute("src", object.LargeBitmap)
		object_el:AppendChild(imgEl)
	elseif object.ShipClass then
		ScpuiSystem.SysMap = {}
		
		ScpuiSystem.SysMap.Ship = object.ShipClass
		
		if object.ModelOrientation then
			ScpuiSystem.SysMap.TechModelOri = ba.createOrientation(math.rad(object.ModelOrientation[1]),math.rad(object.ModelOrientation[2]), math.rad(object.ModelOrientation[3]))
		else
			ScpuiSystem.SysMap.TechModelOri = ba.createOrientation(0.3,0,math.pi)
		end

		if object.RotationSpeed then
			ScpuiSystem.SysMap.RotationRate = math.rad(object.RotationSpeed)
		else
			ScpuiSystem.SysMap.RotationRate = 0.5
		end
		
		if object.ZoomLevel then
			ScpuiSystem.SysMap.z = object.ZoomLevel
		else
			ScpuiSystem.SysMap.z = 0.8
		end
		
		ScpuiSystem.SysMap.x = object_el.offset_left
		ScpuiSystem.SysMap.y = object_el.offset_top
		ScpuiSystem.SysMap.w = object_el.offset_width
		ScpuiSystem.SysMap.h = object_el.offset_height
	end
		
	
	--Maybe show the zoom in button
	local zoom_el = self.document:GetElementById("zoom_panel")
	if object.ZoomTo then
		zoom_el:SetClass("hidden", false)
		self.ZoomInTo = object.ZoomTo
	else
		zoom_el:SetClass("hidden", true)
	end
		
	--Now set the description text
	local desc_el = self.document:GetElementById("desc_text_wrapper")
	
	local text = nil
	if object.UseTechDescription == true then
		text = string.upper(utils.xstr(object.Name)) .. ": " .. tb.ShipClasses[object.ShipClass].TechDescription
	else
		text = utils.xstr(object.Description)
	end
	
	desc_el.inner_rml = text
	desc_el.scroll_top = 0
	
	if object.Seen == false then
		if not object.ZoomTo then
			sysmap_utils:SetIconSeen(self.CurrentSystem.Key, object, true)
			object.Seen_el.inner_rml = ""
		end
	end

end

function SystemMapController:CloseObjectInfo()

	if self.closeup == false then
		return
	end

	local closeup_el = self.document:GetElementById("closeup_container")
	
	--clear the object info
	self.ZoomInTo = nil
	local desc_el = self.document:GetElementById("desc_text_wrapper")
	desc_el.inner_rml = ""
	local object_el = self.document:GetElementById("object_view")
	while object_el:HasChildNodes() do
		object_el:RemoveChild(object_el.first_child)
	end
	
	ScpuiSystem.SysMap = nil
	
	--hide the closeup container
	closeup_el:SetClass("hidden", true)
	
	self.closeup = false

end

function SystemMapController:close_pressed(element)

	self:CloseObjectInfo()
	
end

function SystemMapController:zoom_pressed(element)

	if self.ZoomInTo ~= nil then
		
		local zoom = self.ZoomInTo
		
		self:CloseObjectInfo()
		
		self:LoadNewSystem(zoom)
	end

end

function SystemMapController:Reload()
	
	self:CloseObjectInfo()
	self:DoInitialLoad()
	
end

function SystemMapController:back_pressed(element)

	self:CloseObjectInfo()
	self:LoadNewSystem(self.CurrentSystem.ZoomOutTo)
				
end

function SystemMapController:accept_pressed(element)

    ui.playElementSound(element, "click", "success")
	self:Exit()

end

function SystemMapController:ScrollUp()
	if self.closeup == true then
		return
	end
	self.mainMap.scroll_top = self.mainMap.scroll_top - self.mouse.speed
end

function SystemMapController:ScrollDown()
	if self.closeup == true then
		return
	end
	self.mainMap.scroll_top = self.mainMap.scroll_top + self.mouse.speed
end

function SystemMapController:ScrollLeft()
	if self.closeup == true then
		return
	end
	self.mainMap.scroll_left = self.mainMap.scroll_left - self.mouse.speed
end

function SystemMapController:ScrollRight()
	if self.closeup == true then
		return
	end
	self.mainMap.scroll_left = self.mainMap.scroll_left + self.mouse.speed
end

function SystemMapController:CheckMouse()

	--Mouse scrolling is disabled if the mouse is over the Back button.
	if self.mouseScrollDisabled == false then
		if self.mouse.mx <= self.mouse.threshold then
			self:ScrollLeft()
		end
		
		if self.mouse.mx >= gr.getScreenWidth() - self.mouse.threshold then
			self:ScrollRight()
		end
		
		if self.mouse.my <= self.mouse.threshold then
			self:ScrollUp()
		end
		
		if self.mouse.my >= gr.getScreenHeight() - self.mouse.threshold then
			self:ScrollDown()
		end
	end
	
	async.run(function()
        async.await(async_util.wait_for(0.01))
        self:CheckMouse()
    end, async.OnFrameExecutor)

end

function SystemMapController:toggle_mouse_scroll(val)
	self.mouseScrollDisabled = val
end

function SystemMapController:mouse_move(element, event)
	if self.drag ~= nil then
		
		local xdiff = self.drag.x - event.parameters.mouse_x
		local ydiff = self.drag.y - event.parameters.mouse_y
		
		self.mainMap.scroll_left = self.mainMap.scroll_left + xdiff
		self.mainMap.scroll_top = self.mainMap.scroll_top + ydiff
		
		self.drag = {
			x = event.parameters.mouse_x,
			y = event.parameters.mouse_y
		}
	else

		self.mouse.mx = event.parameters.mouse_x
		self.mouse.my = event.parameters.mouse_y
		
		if not self.mouse.active then
			self:CheckMouse()
			self.mouse.active = true
		end
		
	end
	
end

function SystemMapController:mouse_scroll(element, event)
	if self.closeup == true then return end
	if event.parameters.wheel_delta < 0 then
		self.zoom = self.zoom + 0.02
		if self.zoom > 0.7 then
			self.zoom = 0.7
		else
			self.focalWidth = self.mainMap.scroll_left / self.totalWidth
			self.focalHeight = self.mainMap.scroll_top / self.totalHeight
		end
	else
		self.zoom = self.zoom - 0.02
		if self.zoom < -0.04 then
			self.zoom = -0.04
		else
			self.focalWidth = self.mainMap.scroll_left / self.totalWidth
			self.focalHeight = self.mainMap.scroll_top / self.totalHeight
		end
	end
	self:LoadNewSystem(self.CurrentSystem.Key, true)
end

function SystemMapController:mouse_down(element, event)
	if self.closeup == true then return end
	self.drag = {
		x = event.parameters.mouse_x,
		y = event.parameters.mouse_y
	}
end

function SystemMapController:mouse_up(element, event)
	self.drag = nil
end

function SystemMapController:Exit()
	ScpuiSystem:ReturnToState(ScpuiSystem.lastState)
	if self.texture ~= nil then
		self.texture:destroyRenderTarget()
		self.texture:unload()
	end
	self.document:Close()
end

function SystemMapController:global_keydown(_, event)
    if event.parameters.key_identifier == rocket.key_identifier.ESCAPE then
		if self.closeup == true then
			self:CloseObjectInfo()
		elseif self.CurrentSystem ~= nil then
			if self.CurrentSystem.ZoomOutTo then
				self:CloseObjectInfo()
				self:LoadNewSystem(self.CurrentSystem.ZoomOutTo)
			else
				event:StopPropagation()
				self:Exit()
			end
		else
			event:StopPropagation()
			self:Exit()
		end
    elseif event.parameters.key_identifier == rocket.key_identifier.UP then
		self:ScrollUp()
	elseif event.parameters.key_identifier == rocket.key_identifier.DOWN then
		self:ScrollDown()
	elseif event.parameters.key_identifier == rocket.key_identifier.LEFT then
		self:ScrollLeft()
	elseif event.parameters.key_identifier == rocket.key_identifier.RIGHT then
		self:ScrollRight()
	elseif event.parameters.key_identifier == rocket.key_identifier.P and event.parameters.ctrl_key == 1 and event.parameters.shift_key == 1 then
		self:Reload()
	elseif event.parameters.key_identifier == rocket.key_identifier.Z then
		if event.parameters.shift_key == 1 then
			self.zoom = self.zoom + 0.02
			if self.zoom > 0.7 then
				self.zoom = 0.7
			else
				self.focalWidth = self.mainMap.scroll_left / self.totalWidth
				self.focalHeight = self.mainMap.scroll_top / self.totalHeight
				self:LoadNewSystem(self.CurrentSystem.Key, true)
			end
		else
			self.zoom = self.zoom - 0.02
			if self.zoom < -0.04 then
				self.zoom = -0.04
			else
				self:LoadNewSystem(self.CurrentSystem.Key, true)
			end
		end
	end
end

function SystemMapController:DrawModel()
	
	if ScpuiSystem.SysMap ~= nil then
		local thisShipClass = tb.ShipClasses[ScpuiSystem.SysMap.Ship]
		
		ScpuiSystem.SysMap.TechModelOri = SystemMapController:ChangeTechModelOri(ScpuiSystem.SysMap.TechModelOri)

		thisShipClass:renderTechModel2(ScpuiSystem.SysMap.x, ScpuiSystem.SysMap.y, ScpuiSystem.SysMap.x + ScpuiSystem.SysMap.w, ScpuiSystem.SysMap.y + ScpuiSystem.SysMap.h, ScpuiSystem.SysMap.TechModelOri, ScpuiSystem.SysMap.z)
	end
end

--And here's where we change the rotation
function SystemMapController:ChangeTechModelOri(orientation)

	return ba.createOrientation(orientation.p, orientation.b, orientation.h + (ba.getRealFrametime() * ScpuiSystem.SysMap.RotationRate * -1))

end

function SystemMapController:unload()
	ScpuiSystem:freeAllModels()
end

engine.addHook("On Frame", function()
	if (ba.getCurrentGameState().Name == "GS_STATE_SCRIPTING") and (ScpuiSystem.substate == "SystemMap") then
		SystemMapController:DrawModel()
	end
end, {}, function()
	return false
end)

return SystemMapController
