local dialogs = require("dialogs")
local class = require("class")
local async_util = require("async_util")

local CreditsController = class()

local creditsImage = {}

local fadeOut = {
	active = false,
	current = 0
}

local fadeIn = {
	active = false,
	current = 255
}

local musicInfo = {}

function CreditsController:init()
	--hide the mouse
	io.setCursorHidden(true)
end

function CreditsController:initialize(document)
    self.document = document
	self.scroll = 0
	
	ba.setDiscordPresence("Watching Credits")
	self:hideHelp(self.document:GetElementById("escape_help"))
	
	if not ScpuiSystem.ForceCredits then
		ui.MainHall.stopAmbientSound()
	end
	
	---Load background choice
    self.document:GetElementById("main_background"):SetClass(ScpuiSystem:getBackgroundClass(), true)

	---Load the desired font size from the save file
	self.document:GetElementById("main_background"):SetClass(("base_font" .. ScpuiSystem:getFontPixelSize()), true)
	
	ui.TechRoom.buildCredits()
	
	if ScpuiSystem.ForceCredits then
		self.campaignfilename = ba.getCurrentPlayer():getCampaignFilename()
	else
		self.campaignfilename = nil
	end
	
	--THIS IS TEMPORARY FOR TESTING
	--self.campaignfilename = "bta2_m"
	
	if self.campaignfilename == "bta1_m" then
		self.textColor = "cred_orange"
		self.title = ba.XSTR("Slaves of Chaos", -1)
		musicInfo.music_files = {"ThisTooShallPass.ogg"}
	elseif self.campaignfilename == "bta2_m" then
		self.textColor = "cred_green"
		self.title = ba.XSTR("The Growing Silence", -1)
		--musicInfo.music_files = {"Legacy.ogg"}
		musicInfo.music_files = {"RiseUp.ogg", "Terminus.ogg"}
	elseif self.campaignfilename == "bta3_m" then
		self.textColor = "cred_purple"
		self.title = ba.XSTR("Edge of a Legacy", -1)
		musicInfo.music_files = {"Goliath.ogg"}
	else
		ba.print("Credits couldn't find a valid campaign!\n")
		self.textColor = "cred_red"
		self.title = ba.XSTR("", -1)
		musicInfo.music_files = {"FaithExt.ogg"}
	end
	
	self:initMusic()
	self:beginFadeIn()
	
	local wrapper_el = self.document:GetElementById("credits_text")
	
	local CompleteCredits = ui.TechRoom.Credits.Complete
	
	--Split credit items into left and right sides
	CompleteCredits = CompleteCredits:gsub(
		"([^~\n]*[^~\n%s])(%s*~%s*)([^\n]*)",
		"<span class=\"left\">%1</span>%2<span class=\"right\">%3</span>"
	)
	
	--Replace new lines with break tags
	CompleteCredits = CompleteCredits:gsub("\n","<br></br>")
	
	self:LoadFooter()
	--Add the opening divs to the top and the footer at the bottom
	CompleteCredits = "<div class=\"group\">" .. CompleteCredits .. self.creditsFooter
	
	--Now add the group divs throughout
	CompleteCredits = CompleteCredits:gsub("<br></br>", "<br></br><div style=\"clear: both;\"></div></div><div class=\"group\">")
	
	--Add the closing divs to the bottom
	CompleteCredits = CompleteCredits .. "<div style=\"clear: both;\"></div></div>"
	
	--Replace /// with break tags
	CompleteCredits = CompleteCredits:gsub("///", "<br></br>")
	
	--Do some coloring!
	local replacement = "<div class=\"group\"><span class=\"italic " .. self.textColor .. "\">%-"
	CompleteCredits = CompleteCredits:gsub("<div class=\"group\">%-", replacement)
	CompleteCredits = CompleteCredits:gsub("%-<br></br>", "%-</span><br></br>")
	local split = "<span class=\"" .. self.textColor .. " dash\"> - </span>"
	CompleteCredits = CompleteCredits:gsub(" ~ ", split)
	
	--Now create the SCP built-in credits colors
	local scpHeader = "<span class=\"" .. self.textColor .. "\">----------------------------------<br></br></span>SOURCE CODE PROJECT STAFF<br></br><span class=\"" .. self.textColor .. "\">----------------------------------</span>"
	local scpProjectLeader = "<span class=\"italic " .. self.textColor .. "\">%-Project Leader%-</span>"
	local scpSeniorAdvisors = "<span class=\"italic " .. self.textColor .. "\">%-Senior Advisors%-</span>"
	local scpProgrammers = "<span class=\"italic " .. self.textColor .. "\">%-Programmers%-</span>"
	local scpWebSupport = "<span class=\"italic " .. self.textColor .. "\">%-Web Support%-</span>"
	local scpSpecialThanks = "<span class=\"italic " .. self.textColor .. "\">%-Special thanks to%-</span>"
	local scpVerySpecialThanks = "<span class=\"italic " .. self.textColor .. "\">%-Very special thanks to%-</span>"
	local scpTechnologies = "<span class=\"italic " .. self.textColor .. "\">%-FS2_Open makes use of the following technologies%-</span>"
	local scpLinkHardLight = "<span class =\"cred_link\">http://www%.hard%-light%.net/</span>"
	local scpLinkSCPIndieGames = "<span class =\"cred_link\">http://scp%.indiegames%.us/</span>"
	
	--Now actually do the SCP credits replacements
	CompleteCredits = CompleteCredits:gsub("SOURCE CODE PROJECT STAFF:", scpHeader)
	CompleteCredits = CompleteCredits:gsub("Project Leader:", scpProjectLeader)
	CompleteCredits = CompleteCredits:gsub("Senior Advisors:", scpSeniorAdvisors)
	CompleteCredits = CompleteCredits:gsub("Programmers:", scpProgrammers)
	CompleteCredits = CompleteCredits:gsub("Web Support:", scpWebSupport)
	CompleteCredits = CompleteCredits:gsub("Special thanks to:", scpSpecialThanks)
	CompleteCredits = CompleteCredits:gsub("Very special thanks to:", scpVerySpecialThanks)
	CompleteCredits = CompleteCredits:gsub("FS2_Open makes use of the following technologies:", scpTechnologies)
	CompleteCredits = CompleteCredits:gsub("http://www%.hard%-light%.net/", scpLinkHardLight)
	CompleteCredits = CompleteCredits:gsub("http://scp%.indiegames%.us/", scpLinkSCPIndieGames)
	
	--ba.print(CompleteCredits .. "\n")
	
	--We need to calculate how much empty space to add before and after the credits
	--so that we can cleanly loop the text. Get the height of the div, the height of
	--a line, and do some math. Add that number of line breaks before and after!
	local creditsHeight = wrapper_el.offset_height
	local lineHeight = self.document:GetElementById("text_size_temp").offset_height
	local numBreaks = (math.ceil((creditsHeight / lineHeight) + ((4 - ScpuiSystem:getFontPixelSize()) * 1.3)))
	local creditsBookend = ""
	
	--This is the point at which we stop scrolling to show the logo then fade out
	self.scrollFadeHeight = lineHeight * numBreaks
	
	while(numBreaks > 0) do
		creditsBookend = creditsBookend .. "<br></br>"
		numBreaks = numBreaks - 1
	end
	
	self.document:GetElementById("text_size_temp"):SetClass("hidden", true)
	
	--Append new lines to the top and bottom of Credits so we can loop it later seamlessly
	CompleteCredits = creditsBookend .. CompleteCredits .. creditsBookend
	 --Add a few more breaks to the top to make sure it starts offscreen after the fade in
	CompleteCredits = "<br></br><br></br><br></br><br></br><br></br><br></br><br></br><br></br><br></br><br></br>" .. CompleteCredits
	
	--Now create a div to put all the text in
	local textEl = self.document:CreateElement("div")
	textEl.id = "credits_text_inner"
	textEl.inner_rml = CompleteCredits
	wrapper_el:AppendChild(textEl)
	
	--Add the BtA logo to the scroll
	--local imgEl = self.document:CreateElement("img")
	--imgEl:SetAttribute("src", self.file)
	--wrapper_el:AppendChild(imgEl)
	local titleEl = self.document:CreateElement("div")
	titleEl.id = "credits_title_footer"
	titleEl.inner_rml = ba.XSTR("Between the Ashes", -1)
	titleEl:SetClass("h3", true)
	wrapper_el:AppendChild(titleEl)
	
	local subtitleEl = self.document:CreateElement("div")
	subtitleEl.id = "credits_subtitle_footer"
	subtitleEl.inner_rml = self.title
	subtitleEl:SetClass("h1", true)
	wrapper_el:AppendChild(subtitleEl)
	
	self.creditsElement = wrapper_el
	
	--Total scroll height
	self.scrollHeight = self.creditsElement.scroll_height - self.scrollFadeHeight
	
	self.increment = (self.scrollHeight / self.creditsTime) * 17 -- I don't know why this magic number works! #MATH YALL
	ba.print("CREDITS INCREMENT RATE IS " ..  self.increment .. "\n")
	
	self:ScrollCredits()
	
	local image_el = self.document:GetElementById("credits_image")
	local image_x1 = image_el.offset_left + image_el.parent_node.offset_left
	local image_y1 = image_el.offset_top + image_el.parent_node.offset_top
	
	creditsImage = {
		x1 = image_x1,
		y1 = image_y1,
		x2 = image_x1 + image_el.offset_width,
		y2 = image_y1 + image_el.offset_height,
		index = ui.TechRoom.Credits.StartIndex,
		alpha = 0,
		fadeAmount = 0.01 / ui.TechRoom.Credits.FadeTime,
		timer = ui.TechRoom.Credits.DisplayTime,
		fadeTimer = ui.TechRoom.Credits.FadeTime,
		imageFile1 = nil,
		imageFile2 = nil
	}
	
	--self:chooseImage()
	--self:timeImages()
	
end

function CreditsController:LoadFooter()

	if not parse.readFileText("credits-footer.tbl", "data/tables") then
		return
	end
	
	local text = "<br></br><br></br>"
	
	while(not parse.optionalString("#end")) do
		local thisString = parse.getString()
		
		text = text .. thisString .. "<br></br>"
	end

	self.creditsFooter = text
	
	parse.stop()
	
end

function CreditsController:chooseImage()
	local imageIndex = creditsImage.index
	
	if creditsImage.timer <= 0 then
		if not creditsImage.imageFile2 then
			creditsImage.index = creditsImage.index + 1
			creditsImage.imageFile2 = creditsImage.imageFile1
			creditsImage.alpha = 1.0
		end
		if creditsImage.fadeTimer > 0 then
			creditsImage.fadeTimer = creditsImage.fadeTimer - 0.01
			creditsImage.alpha = creditsImage.alpha - creditsImage.fadeAmount
		else
			creditsImage.fadeTimer = ui.TechRoom.Credits.FadeTime
			creditsImage.timer = ui.TechRoom.Credits.DisplayTime
			creditsImage.imageFile2 = nil
			creditsImage.alpha = 0
		end
	end
	
	if creditsImage.index >= ui.TechRoom.Credits.NumImages then
		creditsImage.index = 0
	end
	
	if creditsImage.index < 10 then
		imageIndex = "0" .. creditsImage.index
	end
	
	creditsImage.imageFile1 = "2_Crim" .. imageIndex .. ".png"
end

function CreditsController:timeImages()
	async.run(function()
        async.await(async_util.wait_for(0.01))
        creditsImage.timer = creditsImage.timer - 0.01
		self:chooseImage()
		self:timeImages()
    end, async.OnFrameExecutor)
end

function CreditsController:drawImage()
	--Disabled for now. Needs to draw to a texture and that texture printed to the background instead of drawing on top of everything

	--[[if creditsImage.imageFile2 then
		gr.drawImage(creditsImage.imageFile2, creditsImage.x1, creditsImage.y1, creditsImage.x2, creditsImage.y2, 0, 0 , 1, 1, creditsImage.alpha)
	end
	if creditsImage.imageFile1 then
		gr.drawImage(creditsImage.imageFile1, creditsImage.x1, creditsImage.y1, creditsImage.x2, creditsImage.y2, 0, 0 , 1, 1, (1.0 - creditsImage.alpha))
	end]]--
end

function CreditsController:initMusic()
	self.track_lengths = {}
	self.creditsTime = 0
	for i = 1, #musicInfo.music_files do
		local handle = ad.openAudioStream(musicInfo.music_files[i], AUDIOSTREAM_MENUMUSIC)
		self.track_lengths[i] = handle:getDuration() * 1000
		self.creditsTime = self.creditsTime + self.track_lengths[i]
		handle:close(false)
	end
	ba.print("Total credits scroll time is " .. self.creditsTime .. "\n")
	musicInfo.currentTrack = 0
end

function CreditsController:maybePlayTrack()

	--music isn't initialized yet, so bail
	if musicInfo.currentTrack == nil then
		return
	end

	if musicInfo.music_handle ~= nil then
		if musicInfo.music_handle:isPlaying() then
			return
		else
			if musicInfo.waiting then
				return
			else
				musicInfo.music_handle:close(false)
				musicInfo.music_handle = nil
			end
		end
	else
		if musicInfo.currentTrack < #musicInfo.music_files then
			musicInfo.currentTrack = musicInfo.currentTrack + 1
			CreditsController:startMusic(musicInfo.currentTrack)
		end
	end
end

function CreditsController:startMusic(track)
	musicInfo.music_handle = ad.openAudioStream(musicInfo.music_files[track], AUDIOSTREAM_MENUMUSIC)
	musicInfo.waiting = true
	async.run(function()
        async.await(async_util.wait_for(0.5))
		musicInfo.waiting = false
        musicInfo.music_handle:play(ad.MasterEventMusicVolume, false)
    end, async.OnFrameExecutor)
end

function CreditsController:beginFadeIn()

	if fadeIn.active == true then
		return
	end
	
	fadeIn.current = 255
	fadeIn.active = true
	fadeIn.timing = 2
	
	self:calcFadeIn()
end

function CreditsController:calcFadeIn()

	if fadeIn.current <= 0 then
		fadeIn.active = false
		return
	end

	local diffPerSecond = math.floor(255 / fadeIn.timing)
	local diffPerMS = math.ceil(diffPerSecond / 1000)
	
	fadeIn.current = fadeIn.current - diffPerMS
	
	async.run(function()
        async.await(async_util.wait_for(0.001))
        self:calcFadeIn()
    end, async.OnFrameExecutor)
end

function CreditsController:FadeIn()

	if fadeIn.active == false then
		return
	end
	
	local r, g, b, a = gr.getColor()
	local width = gr.getScreenWidth()
	local height = gr.getScreenHeight()
	
	gr.setColor(0,0,0, fadeIn.current)
	gr.drawRectangle(0,0,width, height)
	
	--reset the color back to what it was
	gr.setColor(r, g, b, a)

end

function CreditsController:showHelp()
	helpEl = self.document:GetElementById("escape_help")
	
	CreditsController.help_visible = true
	helpEl:SetClass("hidden", false)
	
	async.run(function()
        async.await(async_util.wait_for(5))
		if CreditsController.help_visible then
			CreditsController:hideHelp(helpEl)
		end
    end, async.OnFrameExecutor)
end

function CreditsController:hideHelp(helpEl)
	CreditsController.help_visible = false
	helpEl:SetClass("hidden", true)
end

function CreditsController:beginFadeOut()

	if fadeOut.active == true then
		return
	end
	
	fadeOut.current = 0
	fadeOut.active = true
	fadeOut.timing = 3
	
	self:calcFadeOut()
	
	async.run(function()
        async.await(async_util.wait_for(2.5))
		if musicInfo.music_handle ~= nil then
			musicInfo.music_handle:close(true)
		end
    end, async.OnFrameExecutor)
end

function CreditsController:calcFadeOut()

	if fadeOut.current >= 255 then
		return
	end

	local diffPerSecond = math.floor(255 / fadeOut.timing)
	local diffPerMS = math.ceil(diffPerSecond / 1000)
	
	fadeOut.current = fadeOut.current + diffPerMS
	
	async.run(function()
        async.await(async_util.wait_for(0.001))
        self:calcFadeOut()
    end, async.OnFrameExecutor)
end

function CreditsController:FadeOut()

	if fadeOut.active == false then
		return
	end
	
	local r, g, b, a = gr.getColor()
	local width = gr.getScreenWidth()
	local height = gr.getScreenHeight()
	
	gr.setColor(0,0,0, fadeOut.current)
	gr.drawRectangle(0,0,width, height)
	
	--reset the color back to what it was
	gr.setColor(r, g, b, a)
	
	if fadeOut.current >= 255 then
		if ScpuiSystem.ForceCredits then
			ba.postGameEvent(ba.GameEvents["GS_EVENT_MAIN_MENU"])
		else
			ba.postGameEvent(ba.GameEvents["GS_EVENT_INITIAL_PLAYER_SELECT"])
			ScpuiSystem.MainMenuReturn = true
		end
		fadeOut.active = false
		fadeOut.current = 0
		return
	end
end

function CreditsController:ScrollCredits()
	if self.scroll >= self.scrollHeight then
		if fadeOut.active == false then
			async.run(function()
				async.await(async_util.wait_for(3))
				self:beginFadeOut()
			end, async.OnFrameExecutor)
		end
	else
		self.scroll = self.scroll + self.increment
	end
	self.creditsElement.scroll_top = self.scroll
	
	async.run(function()
        async.await(async_util.wait_for(0.01))
        self:ScrollCredits()
    end, async.OnFrameExecutor)
end

function CreditsController:global_keydown(element, event)
    if event.parameters.key_identifier == rocket.key_identifier.ESCAPE then
		if CreditsController.help_visible then
			self:hideHelp(self.document:GetElementById("escape_help"))
			self:beginFadeOut()
		else
			self:showHelp()
		end
	end
end

function CreditsController:unload()
	if ScpuiSystem.ForceCredits then
		--ui.Debriefing.acceptMission()
		--mn.unloadMission(true)
		ScpuiSystem.ForceCredits = nil
	end
	
	if musicInfo.music_handle ~= nil and musicInfo.music_handle:isValid() then
		musicInfo.music_handle:close(false)
	end
	
	--reveal the mouse
	io.setCursorHidden(false)
end

engine.addHook("On Frame", function()
	if ba.getCurrentGameState().Name == "GS_STATE_SCRIPTING" then
		--CreditsController:drawImage()
		CreditsController:FadeOut()
		CreditsController:FadeIn()
		CreditsController:maybePlayTrack()
	end
end, {}, function()
    return false
end)

return CreditsController
