local FrameStretchOnCommand = function(self, ...)
	self:stoptweening();
	self:playcommand( "SetSize", { Width=200 } );

	self:RunCommandsRecursively( cmd(sleep,1.5) );
	self:RunCommandsRecursively( cmd(linear,0.1) );
	self:playcommand( "SetSize", { Width=SCREEN_WIDTH, tween = cmd(linear,0.1); } );
end

local function LoadLifeMeterFramePart(f)
	return LoadActor( THEME:GetPathG("_frame", "1D"),
		{ 34/168, 4/168, 92/168, 4/168, 34/168 },
		LoadActor( f )
	) .. {
		InitCommand = cmd(x,SCREEN_CENTER_X;y,SCREEN_TOP+32);
		OnCommand = FrameStretchOnCommand;
	};
end

local function SingleLifeMeter()
	local style = GAMESTATE:GetCurrentStyle();
	return style and style:GetStyleType() == "StyleType_OnePlayerTwoSides";
end

local TopFrame = Def.ActorFrame {
	OnCommand = function(self, ...)
		self:addy(-64);
		self:sleep(1.0);
		self:linear(0.3);
		self:addy(64);
	end;
};

local function LifeMeterWidth()
	return ((SCREEN_WIDTH/2)-16)
-- 	return SingleLifeMeter() and ((SCREEN_WIDTH)-32) or ((SCREEN_WIDTH/2)-16)
end

local X = {
	[PLAYER_1] = SCREEN_LEFT+16,
	[PLAYER_2] = SCREEN_RIGHT-16,
};

local function BothSides()
	return (GAMESTATE:GetCurrentStyle() and GAMESTATE:GetCurrentStyle():GetStyleType() == "StyleType_OnePlayerTwoSides");
end

TopFrame[#TopFrame+1] = LoadActor( THEME:GetPathS(Var "LoadingScreen", "player failed") ) .. {
	SupportPan = true;

	PlayerFailedMessageCommand=function(self, params)
		self:playforplayer(params.PlayerNumber);
	end;
};

for pn in ivalues(PlayerNumber) do
	TopFrame[#TopFrame+1] = Def.ActorFrame {
		InitCommand=cmd(x,X[pn]);
		LoadActor("meter under") .. {
			Name = "Under"; 
			InitCommand=cmd(
				y,SCREEN_TOP+30;
				zoomx,pn == PLAYER_1 and 1 or -1
			);
			BeginCommand=cmd(
				zoomtowidth,LifeMeterWidth();
				x,LifeMeterWidth()/2 * (pn == PLAYER_1 and 1 or -1);
				visible,GAMESTATE:IsHumanPlayer(pn)
				);
			OnCommand=cmd(diffusealpha,0;sleep,1.7;linear,0.2;diffusealpha,1);
			OffCommand=cmd(zoomx,1;linear,0.3;zoomx,0);
		};
	};
end

	local function Quantize( f, fRoundInterval ) return math.floor( (f + fRoundInterval/2)/fRoundInterval ) * fRoundInterval end

for pn in ivalues(PlayerNumber) do
	local c;
	local meter;
	local fMeterWidth;
	local fMeterRatio;
	local function Update(self)
		if not meter then
			return;
		end

		local life = meter:GetLife();

		if c.TweenHelper:GetTweenTimeLeft() ~= 0 then
			life = c.TweenHelper:getaux();
		end;

		local fBeat = GAMESTATE:GetSongBeatVisible();
		local fBeatFract = fBeat % 1;

		if c.Grad:GetTweenTimeLeft() == 0 then
			-- Each section in the texture is 8 texels wide, including 2 pixels
			-- of separator on the right edge.  The whole life meter is ideally
			-- LifeMeterWidth wide, and exactly fMeterWidth wide (fMeterWidth*fMeterRatio
			-- pixels).  full width (no crop) = fMeterWidth; 
			local fSectionWidth = 8*fMeterRatio;
			local fSeparatorWidth = 2*fMeterRatio;
			local fPulseSections = 4;

			local fPos = life * fMeterWidth;
			fPos = Quantize(fPos, fSectionWidth);
			fPos = fPos - fSeparatorWidth;
			local fPulseDistance = (fPulseSections * fSectionWidth);
			fPulseDistance = fPulseDistance / fMeterWidth;
			fPos = fPos / fMeterWidth;

			local fTipPos = math.min(life, 1.0) * fMeterWidth;
			fTipPos = Quantize(fTipPos, fSectionWidth);
			fTipPos = fTipPos - fSeparatorWidth/2;
			fTipPos = fTipPos;

			local fPulse = scale( fBeatFract, 0.0, 0.25, 0, fPulseDistance );
			fPulse = clamp( fPulse, 0, fPulseDistance );
			if c.TweenHelper:GetTweenTimeLeft() ~= 0 then
				fPulse = fPulseDistance;
			end;
			fPos = fPos - fPulse;

			c.Grad:cropright( 1-fPos );

			local fFlip = (pn == PLAYER_1 and 1 or -1 );
			c.Tip:x( X[pn] + (fTipPos * fFlip) );
			c.Tip:visible( fTipPos >= 0.01 );
			local fVisible = scale( life, 0.95, 1.00, 1, 0 );
			c.Tip:basealpha(fVisible);
		end

		-- This doesn't follow aux.
		local life = meter:GetLife();
		local fVisible = scale( life, 0.80, 1.00, 0, 1 );
		c.Filled:diffusealpha(fVisible);

		local fDist;
		fDist = scale( fBeatFract, 0.0, 1.00, 0, 0.25 );
		fDist = clamp( fDist, 0, 0.25 );
		c.Filled:SetCustomImageRect( 0.25 - fDist, 0, 0.75 + fDist, 1 );
	end

	TopFrame[#TopFrame+1] = Def.ActorFrame {
		LoadActor("meter grad") .. { Name = "Grad"; };
		LoadActor("meter danger") .. { Name = "Danger"; };
		LoadActor("meter tip") .. { Name = "Tip"; };
		LoadActor("meter filled") .. { Name = "Filled"; };
		LoadActor("meter tick") .. { Name = "Tick"; };
		Def.Actor {
			Name = "TweenHelper";
		};

		-- sort of ugly
		--[[	LoadFont("_venacti shadow 15px normal") .. {
				Name = "PlayerName";
				InitCommand=cmd(x,X[pn]);
				BeginCommand=function(self)
					self:player(pn);
					local profile = PROFILEMAN:GetProfile( pn );
					local name = profile:GetDisplayName();
					self:settext( name );
					self:shadowlength(0);
				end;

				OnCommand=cmd(x,140 * (pn == PLAYER_1 and 1 or -1);y,32);
			};
		]]
		--OnCommand=cmd(zoomx,0;sleep,2.2;linear,0.3;zoomx,1);
		--OffCommand=cmd(zoomx,1;linear,0.3;zoomx,0);
		
		InitCommand = function(self)
			self:SetUpdateFunction( Update );

			c = self:GetChildren();
			local f = cmd(
				x,X[pn]+LifeMeterWidth()/2 * (pn == PLAYER_1 and 1 or -1);
				y,SCREEN_TOP+30;
				zoomx,pn == PLAYER_1 and 1 or -1
			);
			f(c.Grad);
			f(c.Danger);
			f(c.Tick);
			f(c.Filled);
		--	f(c.PlayerName);
		end;

		BeginCommand=function(self)
			self:player(pn);
			if not GAMESTATE:IsHumanPlayer(pn) then
				return;
			end

			meter = SCREENMAN:GetTopScreen():GetLifeMeter(pn);

			c.Tick:player(pn);
			c.Tick:halign(0);
			c.Tick:SetTextureFiltering(false);
			c.Tick:x( X[pn] );
			c.Tick:y( SCREEN_TOP+30 );
			c.Tick:diffusealpha(0.4);
			local fFlip = (pn == PLAYER_1 and 1 or -1 );

			local fDisplayWidth = DISPLAY:GetDisplayWidth();
			local fScreenWidth = SCREEN_WIDTH;
			local fRatio = fScreenWidth/fDisplayWidth;
			-- 1/4 -> *4 is fine (== 1)
			-- 1/3 -> *3
			-- 2/3 -> *2 -> 4/3
			local fAdjusted = math.floor( 1/fRatio + 0.5 );
			if fAdjusted > 0.001 then
				fRatio = fRatio*fAdjusted;
			end;
			c.Tick:zoomx(fRatio * fFlip);

			local fTicksWidth = LifeMeterWidth();
			fTicksWidth = fTicksWidth/fRatio;
			fTicksWidth = math.ceil(fTicksWidth / 8) * 8;
			c.Tick:SetCustomImageRect( 0, 0, fTicksWidth/8, 1 );
			c.Tick:SetWidth( fTicksWidth );
			fMeterWidth = fTicksWidth*fRatio;
			fMeterRatio = fRatio;

			c.Grad:halign(0);
			c.Grad:x( X[pn] );
			c.Grad:SetWidth( fMeterWidth );
			c.Grad:zoomx(fFlip);
			c.Grad:diffusealpha(1);
			c.Danger:halign(0);
			c.Danger:x( X[pn] );
			c.Danger:SetWidth( fMeterWidth );
			c.Danger:zoomx(fFlip);
			c.Danger:diffuseshift();
			c.Danger:effectcolor1(color("#FFFFFF40"));
			c.Danger:effectcolor2(color("#FFFFFFC0"));
			c.Danger:diffusealpha(0);
			c.Filled:halign(0);
			c.Filled:x( X[pn] );
			c.Filled:SetWidth( fMeterWidth );
			c.Filled:zoomx(fFlip);
			c.Filled:glowshift();
			c.Filled:effectclock("beat");
			c.Filled:effectperiod(1.000);
			c.Filled:effectcolor1(color("#FFFFFF00"));
			c.Filled:effectcolor2(color("#FFFFFF40"));

			c.Tip:zoomx(fRatio);
			c.Tip:y( SCREEN_TOP+30 );

			c.Tick:x( math.floor( c.Tick:GetX()/fRatio )*fRatio );
		end;
		HealthStateChangedMessageCommand = function(self, params)
			if params.PlayerNumber ~= pn then return; end
			local bDanger = params.HealthState == "HealthState_Danger" or
				params.HealthState == "HealthState_Dead";
			c.Danger:stoptweening();
			c.Danger:linear(0.3);
			c.Danger:diffusealpha(bDanger and 1 or 0);
		end;

		OnCommand=function(self)
			(cmd(finishtweening;diffusealpha,1;fadeleft,0.25;cropleft,1;sleep,2.0;linear,0.3;cropleft,-0.25;
			     linear,0.2;diffusealpha,0.4))(c.Tick);

			c.TweenHelper:aux(0.0);
			c.TweenHelper:sleep(2.0);
			c.TweenHelper:decelerate(0.3);
			c.TweenHelper:aux(0.5);
		end;

		PlayerFailedMessageCommand=function(self, params)
			if params.PlayerNumber ~= pn then return; end

			c.TweenHelper:aux(0.0);
			c.TweenHelper:decelerate(0.3);
			c.TweenHelper:aux(1.0);
			c.Grad:diffusealpha(0);
			c.Danger:effectcolor1(color("#FFFFFFC0"));
			c.Danger:effectcolor2(color("#FFFFFFC0"));
			(cmd(finishtweening;fadeleft,0;cropleft,0;decelerate,0.3;cropleft,1))(c.Tick);
		end;
	};
end



local Overlay = Def.ActorFrame {
	TopFrame,
};

if Var "LoadingScreen" ~= "ScreenDemonstration" then
	local LastCoins = 0;
	local CreditsString = THEME:GetString("ScreenSystemLayer", "CreditsCredits");

	CreditsText = LoadFont("_venacti 26px bold diffuse") .. {
		InitCommand=cmd(
			shadowlength,1;NoStroke;
			visible,GAMESTATE:GetCoinMode() == "CoinMode_Pay";
			x,SCREEN_CENTER_X;y,SCREEN_BOTTOM-10;zoom,0.5;
			playcommand,"Update";
		);

		CoinInsertedMessageCommand=cmd(playcommand,"Update");
		UpdateCommand=function(self)
			local Coins = GAMESTATE:GetCoins();
			if Coins == 0 then
				self:settext( "" );
				return;
			end
			if LastCoins == 0 then
				self:addy(30);
				self:smooth(0.3);
				self:addy(-30);
			end
			LastCoins = Coins;

			local CoinsPerCredit = PREFSMAN:GetPreference("CoinsPerCredit");
			local Credits = math.floor(Coins / CoinsPerCredit);
			local RemainingCoins = Coins % CoinsPerCredit;
			local s = CreditsString .. ": ";
			if Credits > 0 or CoinsPerCredit == 1 then
				s = s .. tostring(Credits);
			end
			
			if CoinsPerCredit > 1 then
				s = s .. "  " .. tostring(RemainingCoins) .. "/" .. tostring(CoinsPerCredit);
			end
			self:settext( s );
		end;
	};
	Overlay[#Overlay+1] = CreditsText;
end

return Overlay;
