local numPlayers = GAMESTATE:GetNumPlayersEnabled()
local numSides = GAMESTATE:GetNumSidesJoined();
local bDoubles = (numPlayers == 1 and numSides == 2);
local bUsingCenter1P = PREFSMAN:GetPreference('Center1Player')
local font = IsHighDefinition() and fontAliases['frutiger'].Hires or fontAliases['frutiger'].Lores

local function UpdateSingleBPM(self)
	local bpmDisplay = self:GetChild("BPMDisplay")
	local pn = GAMESTATE:GetMasterPlayerNumber()
	local pState = GAMESTATE:GetPlayerState(pn);
	local songPosition = pState:GetSongPosition()
	local bpm = songPosition:GetCurBPS() * 60
	bpmDisplay:settext( string.format("%03.2f",bpm) )
end

local t = Def.ActorFrame{
	Name="BottomFrame";
	InitCommand=cmd(CenterX;y,SCREEN_BOTTOM-12;valign,1);
	BeginCommand=function(self)
		-- If someone has Center1P on, we'd like to move the BPMDisplay out of
		-- the way of the arrows. However, there are a number of conditions that
		-- need to be taken care of before this can be done properly.
		-- In addition, the differing timing displays depend on being in the
		-- center for their positioning.
		--self:CenterX();
	end;
	OffCommand=cmd(bouncebegin,0.35;y,SCREEN_BOTTOM*1.5);

	Def.Quad{
		InitCommand=cmd(y,16;zoomx,SCREEN_WIDTH*0.225;valign,1;diffuse,color("0,0,0,0.25"));
		BeginCommand=function(self)
			-- bpmdisplay + song option
			if GAMESTATE:GetSongOptionsString() ~= "" and GetUserPrefB("SongBPMDisplay") then
				self:zoomy(60);
			-- bpmdisplay by itself
			elseif GetUserPref("SongBPMDisplay") == "true" then
				self:zoomy(44);
			-- song option by itself
			elseif GAMESTATE:GetSongOptionsString() ~= "" and not GetUserPrefB("SongBPMDisplay") then
				self:zoomy(20);
			else
				self:zoomy(0);
			end;
		end;
	};

	Def.ActorFrame{
		Name="BPMFrame";
		BeginCommand=function(self)
			-- write fallback
			if GetUserPref("SongBPMDisplay") == nil then
				SetUserPref("SongBPMDisplay",true);
			end;

			self:visible(GetUserPrefB("SongBPMDisplay"))
			-- if song options are enabled, move the bpm display up
			if GAMESTATE:GetSongOptionsString() ~= "" then
				self:y(-30); -- raised position (bg = 64px)
			else
				self:y(-13); -- normal position (bg = 44px):
			end;
		end;

		AutoText("frutiger",true)..{
			Name="Label";
			InitCommand=cmd(y,-5;shadowlength,1;NoStroke;zoom,0.6;settext,"BPM");
			OnCommand=cmd(linear,0.2;diffusealpha,1);
			OffCommand=cmd(linear,0.2;diffusealpha,0);
		};
	};
};

local displaySingle = Def.ActorFrame{
	LoadFont(font)..{
		Name="BPMDisplay";
		InitCommand=cmd(zoom,0.675;shadowlength,1;NoStroke;);
	};
};
displaySingle.InitCommand=cmd(SetUpdateFunction,UpdateSingleBPM);

if numPlayers == 1 then
	t[#t+1] = displaySingle
else
	-- check if both players are playing the same steps
	local stepsP1 = GAMESTATE:GetCurrentSteps(PLAYER_1)
	local stepsP2 = GAMESTATE:GetCurrentSteps(PLAYER_2)

	local stP1 = stepsP1:GetStepsType()
	local stP2 = stepsP2:GetStepsType()

	local diffP1 = stepsP1:GetDifficulty()
	local diffP2 = stepsP2:GetDifficulty()

	-- get timing data...
	local timingP1 = stepsP1:GetTimingData()
	local timingP2 = stepsP2:GetTimingData()

	--if stP1 == stP2 and diffP1 == diffP2 then
	if timingP1 == timingP2 then
		-- both players are steps with the same TimingData; only need one.
		t[#t+1] = displaySingle
		return t
	end

	-- otherwise, we have some more work to do.

	local function Update2PBPM(self)
		local dispP1 = self:GetChild("DisplayP1")
		local dispP2 = self:GetChild("DisplayP2")

		-- needs current bpm for p1 and p2
		for pn in ivalues(PlayerNumber) do
			local bpmDisplay = (pn == PLAYER_1) and dispP1 or dispP2
			local pState = GAMESTATE:GetPlayerState(pn);
			local songPosition = pState:GetSongPosition()
			local bpm = songPosition:GetCurBPS() * 60
			bpmDisplay:settext( string.format("%03.2f",bpm) )
		end
	end

	local displayTwoPlayers = Def.ActorFrame{
		-- manual bpm displays
		LoadFont(font)..{
			Name="DisplayP1";
			InitCommand=cmd(x,-32;zoom,0.6;shadowlength,1;NoStroke;);
		};
		LoadFont(font)..{
			Name="DisplayP2";
			InitCommand=cmd(x,32;zoom,0.6;shadowlength,1;NoStroke;);
		};
	};

	displayTwoPlayers.InitCommand=cmd(SetUpdateFunction,Update2PBPM);

	t[#t+1] = displayTwoPlayers
end

return t