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:spring(0.3);
		self:addy(64);
	end;
};

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

local X = {
	[PLAYER_1] = SCREEN_CENTER_X-320+32+(256-232)-4,
	[PLAYER_2] = SCREEN_CENTER_X+320-32-(256-232)+4,	
--[[ 	[PLAYER_1] = SCREEN_CENTER_X-160,
	[PLAYER_2] = SCREEN_CENTER_X+160, --]]
};

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 filled") .. {
			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(diffuse,0,0,0,1;diffusetopedge,0.25,0.25,0.25,1;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 = 2;

			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, 0, 0.75, 1 );
-- 		c.Filled:SetCustomImageRect( 0.25 - fDist, 0, 0.75 + fDist, 1 );
	end

	TopFrame[#TopFrame+1] = Def.ActorFrame {
		LoadActor("meter grad") .. { Name = "Grad"; };
		LoadActor("meter filled") .. { Name = "Danger"; };
-- 		LoadActor("meter filled") .. { Name = "Filled";  };
		LoadActor("306_JumpBack_NTSC_DV") .. { Name = "Filled"; OnCommand=cmd(scaletoclipped,232,30); };
		LoadActor("meter tip") .. { Name = "Tip"; };
-- 		LoadActor("meter filled") .. { Name = "Filled"; OnCommand=cmd(diffuse,cRed); };
		LoadActor("meter tick") .. { Name = "Tick"; InitCommand=cmd(zoomtoheight,30); };
		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;NoStroke;);
			};
		]]
		--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];
-- 				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 fScreenWidth = 640;
			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(cRed);
			c.Danger:effectcolor2(DarkColor(cRed));			
--[[ 			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(2.000);
			c.Filled:effectcolor1(color("#FFFFFF00"));
			c.Filled:effectcolor2(color("#FFFFFF90"));

			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;sleep,2.0;glow,1,1,1,0.4;diffusealpha,1;linear,0.3;glow,1,1,1,0;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;diffusealpha,0;linear,0.1;glow,1,1,1,1;decelerate,0.2;glow,1,1,1,0))(c.Tick);
		end;
	};
end



TopFrame[#TopFrame+1] = LoadActor("life frame") .. {
	InitCommand=cmd(player,PLAYER_1;x,SCREEN_CENTER_X-160;y,SCREEN_TOP+30);
};
TopFrame[#TopFrame+1] = LoadFont("Common Normal") .. {
	Text="HP";
	InitCommand=cmd(player,PLAYER_1;NoStroke;x,SCREEN_CENTER_X-160-128+10;y,SCREEN_TOP+30;rotationz,-90;shadowlength,1;zoom,0.5);
	OnCommand=cmd(linear,0.4;diffuse,PlayerColor(PLAYER_1);diffusetopedge,LightColor(PlayerColor(PLAYER_1)));
};
--[[ TopFrame[#TopFrame+1] = LoadFont("Common Normal") .. {
	Text=GAMESTATE:GetPlayerDisplayName(PLAYER_1);
	InitCommand=cmd(x,SCREEN_CENTER_X-160-128+10.5;y,SCREEN_TOP+30+20;NoStroke;shadowlength,1;zoom,0.65);	
	OnCommand=cmd(horizalign,left;skewx,-0.25;linear,0.4;diffuse,PlayerColor(PLAYER_1);diffusetopedge,LightColor(PlayerColor(PLAYER_1)));
}; --]]
TopFrame[#TopFrame+1] = LoadActor("life frame") .. {
	InitCommand=cmd(player,PLAYER_2;x,SCREEN_CENTER_X+160;y,SCREEN_TOP+30;zoomx,-1);
};
TopFrame[#TopFrame+1] = LoadFont("Common Normal") .. {
	Text="HP";
	InitCommand=cmd(player,PLAYER_2;x,SCREEN_CENTER_X+160+128-10;y,SCREEN_TOP+30;rotationz,90;NoStroke;shadowlength,1;zoom,0.5);
	OnCommand=cmd(linear,0.4;diffuse,PlayerColor(PLAYER_2);diffusetopedge,LightColor(PlayerColor(PLAYER_2)));
};
--[[ TopFrame[#TopFrame+1] = LoadActor("life frame") .. {
	InitCommand=cmd(x,X[PLAYER_2]/2;y,SCREEN_TOP+30);
}; --]]

local function Difficulty(pn)
	local r = Def.ActorFrame{};
	
	r[#r+1] = Def.Quad{
		InitCommand=function(self)
			local fadeAmt = 0.25;
			
			if pn == PLAYER_1 then
				self:addx(-4);
				self:horizalign(left);
				self:faderight(fadeAmt);
				self:fadeleft(0.1);
			else
				self:horizalign(right);
				self:addx(4);
				self:fadeleft(fadeAmt);
				self:faderight(0.1);
			end;
			
			self:addy(1);
			
			self:zoomx(96+10);
			self:zoomy(18);
			if pn then
				self:diffuse( DarkColor( DifficultyColor( GAMESTATE:GetCurrentSteps(pn):GetDifficulty() ) ) );
			end;
			self:diffusealpha(0.5);
		end;
		BeginCommand=function(self)
			if GAMESTATE:IsSideJoined(pn) or GAMESTATE:IsPlayerEnabled(pn) or GAMESTATE:IsDemonstration() then
				self:visible(true)
			else self:visible(false);
			end;
		end;
	};
	
	r[#r+1] = LoadFont("Common Normal")..{
		Name="Difficulty"..pn;
		InitCommand=cmd(zoom,0.6;NoStroke;shadowlength,1);
		BeginCommand=function(self)
			if GAMESTATE:IsSideJoined(pn) or GAMESTATE:IsPlayerEnabled(pn) or GAMESTATE:IsDemonstration() then
				self:visible(true)
			else self:visible(false);
			end;
			
			if pn == PLAYER_1 then self:horizalign(left);
			else self:horizalign(right);
			end;
			
		end;
		OnCommand=function(self)
			if not self:GetVisible() then return; end;
			-- get difficulty
			local steps = GAMESTATE:GetCurrentSteps(pn);
			local difficulty = steps:GetDifficulty();
			local diffString = ( string.sub(difficulty,12) );
			self:diffuse( DifficultyColor(difficulty) );
			self:settext(diffString .. " [" ..steps:GetMeter().."]");
			self:diffusetopedge( color("#FFFFFF") );
		end;
	};
	
	return r;
end;
local function PlayerScoreDP(pn)
	return LoadFont("_ScoreDisplayNormal percentage") .. {
		Text=string.format("%.2f%%",0);
		InitCommand=cmd(NoStroke;shadowlength,0;playcommand,"JudgmentMessage");
--[[ 		JudgmentMessageCommand=function(self,params)
			if(params.Player == pn) then
				local dpNow = STATSMAN:GetCurStageStats():GetPlayerStageStats(pn):GetActualDancePoints();
				local dpTotal = STATSMAN:GetCurStageStats():GetPlayerStageStats(pn):GetPossibleDancePoints();
				
				self:settext(string.format("%04d",dpNow) .. "%" .. string.format("%04d",dpTotal));
			else
				self:settext("0000%0000");
			end
		end		 --]]
		JudgmentMessageCommand=function(self,params)
			local dpNow = STATSMAN:GetCurStageStats():GetPlayerStageStats(pn):GetActualDancePoints();
			local dpPerc = STATSMAN:GetCurStageStats():GetPlayerStageStats(pn):GetPercentDancePoints();
			local dpTotal = STATSMAN:GetCurStageStats():GetPlayerStageStats(pn):GetPossibleDancePoints();
			if(params.Player == pn) then
				self:settext(string.format("%.2f%%", dpPerc*100.0));
			else
				return
			end
		end
	};
end

local Overlay = Def.ActorFrame {
	FOV=90;
	TopFrame,
-- 	Def.ActorFrame {
-- 	 InitCommand=cmd(rotationy,-12);
	LoadActor( THEME:GetPathG("_frame", "1D"),{ 1/3, 1/3, 1/3 },LoadActor(THEME:GetPathG("_1d","frames/transparent"))) .. {
		InitCommand=cmd(playcommand,"SetSize",{ Width=(228); tween=cmd(player,PLAYER_1;x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y-13;diffuse,PlayerColor(PLAYER_1);diffusealpha,0); });
		OnCommand=cmd(playcommand,"SetSize",{ Width=(228); tween=cmd(linear,0.3;diffusealpha,1); };draworder,85);
	};
-- 	};
-- 	Def.ActorFrame {
-- 	 InitCommand=cmd(rotationy,12);
	LoadActor( THEME:GetPathG("_frame", "1D"),{ 1/3, 1/3, 1/3 },LoadActor(THEME:GetPathG("_1d","frames/transparent"))) .. {
		InitCommand=cmd(playcommand,"SetSize",{ Width=(228); tween=cmd(player,PLAYER_2;x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y-13;diffuse,PlayerColor(PLAYER_2);diffusealpha,0); });
		OnCommand=cmd(playcommand,"SetSize",{ Width=(228); tween=cmd(linear,0.3;diffusealpha,1); };draworder,85);
	};
-- 	};

	Difficulty(PLAYER_1)..{
		Name="P1Difficulty";
		InitCommand=cmd(x,SCREEN_CENTER_X-160-90;y,SCREEN_BOTTOM-56);
		OffCommand=cmd(linear,0.2;diffusealpha,0);
	};
	Difficulty(PLAYER_2)..{
		Name="P2Difficulty";
		InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_BOTTOM-56);
		OffCommand=cmd(linear,0.2;diffusealpha,0);
	};
	PlayerScoreDP(PLAYER_1) .. {
		InitCommand=cmd(player,PLAYER_1;x,THEME:GetMetric(Var "LoadingScreen","ScoreP1X");y,THEME:GetMetric(Var "LoadingScreen","ScoreP1Y");zoom,0.95;);
	};
	PlayerScoreDP(PLAYER_2) .. {
		InitCommand=cmd(player,PLAYER_2;x,THEME:GetMetric(Var "LoadingScreen","ScoreP2X");y,THEME:GetMetric(Var "LoadingScreen","ScoreP2Y");zoom,0.95;);
	};
--[[ 	LoadActor(THEME:GetPathG("ScreenSelectStyle","scroll/small margin")) .. {
		InitCommand=cmd(x,SCREEN_CENTER_X-160-(104/1.25);y,SCREEN_BOTTOM-30);
		JudgmentMessageCommand=function(self, params)
			if params.TapNoteScore then
				self:finishtweening();
				self:diffuse(JudgeColor(params.TapNoteScore));
				self:linear(0.3);
				self:diffuse(1,1,1,1);
			else
				return
			end
		end
	}; --]]
	LoadActor(THEME:GetPathG("ScreenWithMenuElements","Stage")) .. {
		InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_TOP+30);
	};
	LoadFont("Common Normal") .. {
		Text="BPM";
		InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_BOTTOM-30-8;zoom,0.5;NoStroke;shadowlength,1);
	};
	Def.SongBPMDisplay {
		File=THEME:GetPathF("Common","Normal");
		Name="BPMDisplay";
		InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_BOTTOM-30+8;NoStroke;shadowlength,1;);
		SetCommand=function(self) self:SetFromGameState() end;
		CurrentSongChangedMessageCommand=cmd(playcommand,"Set");
		CurrentCourseChangedMessageCommand=cmd(playcommand,"Set");
	};
};

return Overlay;
