-- Customization Block. I hope you can just slam these in metrics ( yay for malleability without responsibilty )
-- Master Meter Definitions
local MasterMeterWidth = SCREEN_WIDTH
local MasterMeterX = SCREEN_LEFT+MasterMeterWidth/2
local MasterMeterLifeX = MasterMeterX - MasterMeterWidth/2
local MasterMeterFrameX = MasterMeterX - MasterMeterWidth/4 - 7
-- Offsets
local MeterCutBuffer = 32
local DistanceFromEdge = 16
-- Positions
local P1LifeX = SCREEN_LEFT+DistanceFromEdge
local P2LifeX = SCREEN_RIGHT-DistanceFromEdge
local MeterYOffset = 30
-- Widths
--[[ local iOnePlayerMeterWidth = MasterMeterWidth-MeterCutBuffer
local iTwoPlayerMeterWidth = MasterMeterWidth/2-MeterCutBuffer --]]
local iOnePlayerMeterWidth = 274/2
local iTwoPlayerMeterWidth = 272

local function SingleLifeMeter()
	local style = GAMESTATE:GetCurrentStyle();
	return style and style:GetStyleType() == "StyleType_OnePlayerTwoSides";
end
local function Shown()
    if not GAMESTATE:IsHumanPlayer(PLAYER_1) or not GAMESTATE:IsHumanPlayer(PLAYER_2) then
        return false;
    end

    if PlayerStats[1]:GetPossibleDancePoints() ~= PlayerStats[2]:GetPossibleDancePoints() then
        return false;
    end

    if GAMESTATE:IsCourseMode() then
        if GAMESTATE:GetCurrentTrail(PLAYER_1) ~= GAMESTATE:GetCurrentTrail(PLAYER_2) then
            return false;
        end
    else
        if GAMESTATE:GetCurrentSteps(PLAYER_1) ~= GAMESTATE:GetCurrentSteps(PLAYER_1) then
            return false;
        end
    end
    return true;
end
local TopFrame = Def.ActorFrame {
};

local function LifeMeterWidth()
	return SingleLifeMeter() and iOnePlayerMeterWidth or iTwoPlayerMeterWidth
end

local X = {
	[PLAYER_1] = P1LifeX,
	[PLAYER_2] = P2LifeX,
};

for pn in ivalues(PlayerNumber) do
	TopFrame[#TopFrame+1] = Def.ActorFrame {
		InitCommand=cmd(x,X[pn]);
		LoadActor("meter under") .. {
			Name = "Under"; 
			InitCommand=cmd(
				y,MeterYOffset;
				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,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.
        -- Lifescaled events here
		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";
		};
		
		InitCommand = function(self)
			self:SetUpdateFunction( Update ); -- All The Marbles.
			c = self:GetChildren();
			local f = cmd(
				x,X[pn]+LifeMeterWidth()/2 * (pn == PLAYER_1 and 1 or -1);
				y,MeterYOffset;
				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( MeterYOffset );
			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;
            
            -- Begin Animation Block
			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.05);
			c.Danger:diffusealpha(bDanger and 1 or 0);
		end;

		OnCommand=function(self)
			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
--Midiman: TOP FRAME ( VERSUS )
--~ TopFrame[#TopFrame+1] = LoadLifeMeterFramePart("top frame 1") .. { OnCommand = cmd(x,MasterMeterFrameX); };
--Midiman: TOP FRAME ( DOUBLE )
--~ TopFrame[#TopFrame+1] = LoadLifeMeterFramePart("top frame 2") .. { OnCommand = cmd(visible,false); };

local Overlay = Def.ActorFrame {
	TopFrame,
    LoadActor("Ghost-LifeBar") .. {
        InitCommand=cmd(x,MasterMeterFrameX;y,MeterYOffset);
        JudgmentMessageCommand=function(self,params)
            self:finishtweening();
            self:diffuse(JudgeColor(params.TapNoteScore) or color(1,1,1,1))
            self:decelerate(0.3)
            self:diffuse(1,1,1,1)
        end;
    };
    LoadFont("System") .. {
        InitCommand=cmd(x,MasterMeterFrameX;y,MeterYOffset);
        JudgmentMessageCommand=function(self,params)
--[[             -- test funk!
            local fJudgeColor = { 1,1,1,1 }
            local AdditiveJudgeColor = JudgeColor(params.TapNoteScore)
            local TapNoteOffset = params.TapNoteOffset
            local function ReturningJudgeColor(color) 
                local c = color
	            return { c[1]*TapNoteOffset, c[2]*TapNoteOffset, c[3]*TapNoteOffset, 1 };
            end
            local fJudgeColor = ( fJudgeColor / fJudgeColor ) + ReturningJudgeColor(AddititveJudgeColor); --]]
            local Stats = STATSMAN:GetCurStageStats():GetPlayerStageStats(PLAYER_1);
            local fScore = FormatPercentScore( Stats:GetPercentDancePoints() );
            self:settext(fScore);
--~             self:diffuse(fJudgeColor)
        end
    };
};
return Overlay;
 