local isEditMode = ... or false

-- a bit of an inaccurate variable name now, but...
local roomForBar = isEditMode or GAMESTATE:GetNumPlayersEnabled() <= 1

local isEx = ShouldUseEXGraphics()
local fileAppend = isEx and "ex_" or ""

--local meterWidth = _screen.cx / 1.2
local meterWidth = roomForBar and 306-40 or 150
local songLabels
local bpmChanges
local nonstopLabels = {}

local lastLabel = 0
local lastBPMChange = 0

local function SetUpLabels()
	local song = GAMESTATE:GetCurrentSong() or (GAMESTATE:GetCurrentCourse() and GAMESTATE:GetCurrentCourse():GetCourseEntry(1):GetSong())
	if not song then return end
	return song:GetTimingData():GetLabels(true)
end

local function CreateFrameWithBarParts()
	local ret = Def.ActorFrame{
		Name = "LabelHolder",
		OnCommand=function(self)
			if roomForBar then
				self:skewx(GAMESTATE:GetMasterPlayerNumber() == PLAYER_1 and 0.45 or -0.45)
			else
				self:y(28):diffusealpha(0.75)
			end
		end,
		
		-- TODO: HOW DO WE DEAL WITH NONSTOP MODE
		-- HOW???
		CurrentSongChangedMessageCommand=function(self)
			--self:RemoveAllChildren()
			if GAMESTATE:GetCurrentCourse() and GAMESTATE:GetCurrentSong() then
				songLabels = SetUpLabels()
				songTiming = GAMESTATE:GetCurrentSong():GetTimingData()
				bpmChanges = songTiming:GetBPMsAndTimes(true)
				lastLabel = 0
				lastBPMChange = 0
			end
		end
		
		
	}
	
	local song = GAMESTATE:GetCurrentSong() or (GAMESTATE:GetCurrentCourse() and GAMESTATE:GetCurrentCourse():GetCourseEntry(1):GetSong())
	if not song then return ret end
	
	-- Set up the labels here.
	songLabels = SetUpLabels()
	local songTiming = song:GetTimingData()
	bpmChanges = songTiming:GetBPMsAndTimes(true)
	
	if GAMESTATE:GetCurrentCourse() then
		-- Okay, I don't know how to make the progress bar dump all its bar pieces and re-stock them,
		-- so we're going to try something different.
		for i, entry in ipairs(GAMESTATE:GetCurrentCourse():GetCourseEntries()) do
			local eSong = entry:GetSong()
			local songLengthSec = eSong:GetLastSecond()
			nonstopLabels[i] = {songLengthSec, tostring(i)}
			
			--local labelLength = i == #GAMESTATE:GetCurrentCourse():GetCourseEntries() and 
		end
	else
		for i, labTab in ipairs(songLabels) do
			-- Use some HARDCORE MATHS (well... code) to determine the length of a label,
			-- which we'll then scale to figure out how long the quad representing the label should be.
			
			--local songLengthBeats = songTiming:GetBeatFromElapsedTime(song:GetLastSecond())
			local songLengthSec = song:GetLastSecond()
			
			--local labelLength = i == #songLabels and songLengthBeats - labTab[1] or songLabels[i+1][1] - labTab[1]
			local labelLength = i == #songLabels and songLengthSec - songTiming:GetElapsedTimeFromBeat(labTab[1]) or songTiming:GetElapsedTimeFromBeat(songLabels[i+1][1]) - songTiming:GetElapsedTimeFromBeat(labTab[1])
			--local quadLength = scale(labelLength, 0, songLengthBeats, 0, meterWidth)
			local quadLength = scale(labelLength, 0, songLengthSec, 0, meterWidth)
			--local quadX = scale(labTab[1], 0, songLengthBeats, -meterWidth/2, meterWidth/2)
			local quadX = scale(songTiming:GetElapsedTimeFromBeat(labTab[1]), 0, songLengthSec, -meterWidth/2, meterWidth/2)
			
			-- Get the label name for hard-coded string-to-color nonsense.
			local theLabel = labTab[2]
			
			ret[#ret+1] = Def.Quad{
				Name = tostring(i),
				OnCommand=function(self)
					self:horizalign(left):x(quadX):zoomto(quadLength,16):diffuse(SongLabelColor(theLabel)):diffuserightedge(lerp_color(0.4, SongLabelColor(theLabel), Color.Black))
					--diffuse(i % 2 == 0 and lerp_color(0.3, theColor, Color.White) or theColor)
				end
			}
		end
	end
	
	return ret
end

local function UpdateMe(self, deltaTime)
	-- 1: Handle the progress blip.
	-- More hardcore maths...
	local curPos = GAMESTATE:GetSongPosition():GetSongBeat()
	local curPosSec = GAMESTATE:GetSongPosition():GetMusicSecondsVisible()
	local songLengthBeats = GAMESTATE:GetCurrentSong():GetTimingData():GetBeatFromElapsedTime(GAMESTATE:GetCurrentSong():GetLastSecond())
	local songLengthSec = GAMESTATE:GetCurrentSong():GetLastSecond()
	--local progBarPosition = scale(curPos, 0, songLengthBeats, -meterWidth/2, meterWidth/2)
	local progBarPosition = scale(curPosSec, 0, songLengthSec, -meterWidth/2, meterWidth/2)
	
	--if roomForBar then
		-- ...for the sake of progress.
		self:GetChild("Progress"):x( clamp(progBarPosition, -meterWidth/2, meterWidth/2) )
	--end
	
	-- let's try and not blow anything up
	if songLabels then
		-- 2: Label display handling.
		local labelIndex
		
		for i, labTab in ipairs(songLabels) do
			-- 
			if curPos < labTab[1] then
				labelIndex = i == 1 and i or i-1
				break
			end
			-- End of song?
			labelIndex = i
		end
		
		if #songLabels == 1 then 
			-- No song labels? Turn this into a time display then
			self:GetChild("Segment"):settext( SecondsToMSS(GAMESTATE:GetSongPosition():GetMusicSecondsVisible()) )
		elseif labelIndex ~= lastLabel then
			-- A thingy to stop the segment display from updating EVERY FRAME,
			-- which might be a little superfluous but?
			lastLabel = labelIndex
			local theLabel = songLabels[labelIndex][2]
			
			-- Color and format/replace text, if possible.
			-- Also add extra flashing for segments labelled with "Freestyle".
			self:GetChild("Segment"):settext(SongLabelString(theLabel, true)):diffuse(isEx and SongLabelColor(theLabel) or ColorBlend(SongLabelColor(theLabel), Color.White))
			if string.lower(string.gsub(theLabel, "%A", "")) == "freestyle" then
				self:GetChild("Segment"):glowblink():effectcolor1(Color.Stealth):effectcolor2(Color.White):
					effecttiming(0.1,0.1,0.1,0.1,0.6):effectclock("bgm")
			else
				self:GetChild("Segment"):stopeffect()
			end
		end
		
		-- 3: Handle the label (segment) change count-in.
		-- Re-use hardcore maths!
		local theCount = labelIndex == #songLabels and 9999 or songLabels[labelIndex+1][1] - songLabels[labelIndex][1]
		local theActualCount = math.ceil(theCount - (curPos - songLabels[labelIndex][1]) )
		self:GetChild("BeatCount"):settext( tostring(theActualCount) )
		if theActualCount < 5 and roomForBar then
			self:GetChild("BeatCount"):visible(true)
		else
			self:GetChild("BeatCount"):visible(false)
		end
	end
	
	-- 4: Handle the BPM change count-in.
	if bpmChanges then
		local bpmIndex
		
		for i, bpmTab in ipairs(bpmChanges) do
			-- 
			if curPos < bpmTab[1] then
				bpmIndex = i == 1 and i or i-1
				break
			end
			-- End of song?
			bpmIndex = i
		end
		
		local theBPMCount = bpmIndex == #bpmChanges and 99999 or bpmChanges[bpmIndex+1][1] - bpmChanges[bpmIndex][1]
		local actualBPMCount = math.ceil(theBPMCount - (curPos - bpmChanges[bpmIndex][1]) )
		
		local isSlower = bpmIndex ~= #bpmChanges and bpmChanges[bpmIndex][2] > bpmChanges[bpmIndex+1][2] or false
		local arrO = isSlower and "&DOWN;" or "&UP;"
		self:GetChild("BPMCount"):settext( arrO .. tostring(actualBPMCount) )
		if actualBPMCount < 5 and roomForBar then
			self:GetChild("BPMCount"):visible(true):diffuse(isSlower and NeonColor.Cyan or NeonColor.Yellow)
		else
			self:GetChild("BPMCount"):visible(false)
		end
	end
end

local t = Def.ActorFrame{
	OnCommand=function(self)
		self:SetUpdateFunction(UpdateMe)
	end,
	-- Backing behind everything else.
	LoadActor(fileAppend .. "progressback") .. {
		-- Again, no room in two player.
		Condition = roomForBar and not isEditMode,
		OnCommand=function(self)
			self:y(10):zoomy(GAMESTATE:GetMasterPlayerNumber() == PLAYER_1 and 1 or -1)
		end
	},
	-- Frame/base for all the progress bar stuff to go on.
	LoadActor(fileAppend .. "bprogress") .. {
		-- Again, no room in two player.
		Condition = roomForBar,
		OnCommand=function(self)
			self:x(GAMESTATE:GetMasterPlayerNumber() == PLAYER_1 and -4 or 4):zoomx(GAMESTATE:GetMasterPlayerNumber() == PLAYER_1 and 1 or -1)
		end
	},
	
	-- *Finally* call that function that's taken up over half of this file
	CreateFrameWithBarParts(),
	-- Progress marker!
	LoadActor("blip") .. {
		Name = "Progress",
		OnCommand=function(self)
			self:zoomto(6,26):diffuse(roomForBar and Color.White or Color.Alpha(Color.White,0.5)):y(roomForBar and 0 or 28)
			if roomForBar then
				self:skewx(GAMESTATE:GetMasterPlayerNumber() == PLAYER_1 and 0.7 or -0.7)
			end
		end
	},
	-- Current segment name.
	Def.BitmapText{
		Font = "Common Normal",
		Name = "Segment",
		Text = "hi :)",
		OnCommand=function(self)
			self:y(roomForBar and 25 or 26):zoom(0.6):strokecolor(Color.Black):maxwidth(meterWidth/0.55)
		end
	},
	-- Count-in to next segment.
	Def.BitmapText{
		Font = "Common Normal",
		Name = "BeatCount",
		Text = ":)",
		OnCommand=function(self)
			self:horizalign(right):xy(meterWidth/2,26):zoom(0.6):strokecolor(Color.Black):heartbeat():effectclock('beatnooffset')
			--SM(GAMESTATE:GetCurrentSong():GetTimingData():GetBPMsAndTimes(true))
		end
	},
	-- Ditto, but for BPM changes.
	Def.BitmapText{
		Font = "Common Normal",
		Name = "BPMCount",
		Text = ":)",
		OnCommand=function(self)
			self:horizalign(left):xy((-meterWidth/2)+4,26):zoom(0.6):strokecolor(Color.Black):heartbeat():effectclock('beatnooffset')
			--SM(GAMESTATE:GetCurrentSong():GetTimingData():GetBPMsAndTimes(true))
		end
	},
}

return t
