-- Basically derived from previous eval screens I wrote, except even LESS advanced.
-- ...and with this.
local JudgeLines = LoadModule("Options.SmartTapNoteScore.lua")()
table.sort(JudgeLines)
JudgeLines[#JudgeLines+1] = "Miss"
if not MergeHNSWithTNS() then JudgeLines[#JudgeLines+1] = "Holds" end
JudgeLines[#JudgeLines+1] = "MaxCombo"

-- EZ stats! ... Yay!
local function StageStats(isAccumulated)
	if THEME:GetMetric( Var "LoadingScreen","Summary" ) or isAccumulated then
		return STATSMAN:GetAccumPlayedStageStats()
	else
		return STATSMAN:GetCurStageStats()
	end
end

-- And a function to make even better use out of the table.
local function GetJLineValue(line, pl)
	local playerStats = StageStats():GetPlayerStageStats(pl)
	local playerRadar = playerStats:GetRadarActual()
	local chartRadar = playerStats:GetRadarPossible()
	
	if line == "Holds" or line == "Mines" or line == "Rolls" then
		return playerRadar:GetValue("RadarCategory_" .. line) .. " / " .. chartRadar:GetValue("RadarCategory_" .. line)
	elseif line == "MaxCombo" then
		return playerStats:MaxCombo()
	end
	
	local coun = playerStats:GetTapNoteScores("TapNoteScore_" .. line)
	
	if MergeHNSWithTNS() then
		if line == JudgeLines[1] then 
			coun = coun + playerStats:GetHoldNoteScores("HoldNoteScore_Held")
		elseif line == "Miss" then
			coun = coun + playerStats:GetHoldNoteScores("HoldNoteScore_LetGo")
		end
	end
	
	return coun
end

local function GetPercentageOfTNS(line, pl)
	local playerStats = StageStats():GetPlayerStageStats(pl)
	local perCent = playerStats:GetPercentageOfTaps("TapNoteScore_" .. line)
	-- TODO: holds when MergeHNSWithTNS, though?
	return perCent
end

-- You know what, we'll deal with getting the overall scores with a function too
-- even though it's not strictly necessary to do so without long form/percent score separation.
local function GetPlScore(pl)
	--
	local primary_score = commify(math.floor(STATSMAN:GetCurStageStats():GetPlayerStageStats(pl):GetPercentDancePoints()*100000))

	return primary_score
end

-- #################################################
-- Enough functions. Let's start with non-player specific stuff.

local t = Def.ActorFrame{
	-- Something to fill in for unjoined players, I guess.
	Def.Quad {
		OnCommand=function(self)
			self:vertalign(bottom):xy(_screen.cx,_screen.h):diffuse(Color.Outline):zoomto(_screen.w,_screen.cy+42)
		end
	},
	-- Backing behind song name.
	Def.Quad {
		OnCommand=function(self)
			self:vertalign(top):x(_screen.cx):zoomto(_screen.w,54):diffuse(LocalBlueColor(0))
		end
	},
	-- Song name...
	Def.BitmapText {
		Font = "Common Normal",
		OnCommand=function(self)
			self:xy(_screen.cx,42):strokecolor(Color.Black):zoom(0.5):maxwidth((_screen.w*0.8)/0.5)
			local target = GAMESTATE:IsCourseMode() and GAMESTATE:GetCurrentCourse() or GAMESTATE:GetCurrentSong()
			
			if target then
				if GAMESTATE:IsCourseMode() then
					self:settext(target:GetDisplayFullTitle())
				else
					self:settext(target:GetDisplayFullTitle() .. " / " .. target:GetDisplayArtist())
				end
			end
		end
	},
	-- and song jacket (if available).
	Def.Quad {
		OnCommand=function(self)
			self:xy(_screen.cx,126):diffuse(LocalGoldColor(1)):zoomto(145,145)
		end
	},
	Def.Sprite {
		OnCommand=function(self)
			local target = GAMESTATE:IsCourseMode() and GAMESTATE:GetCurrentCourse() or GAMESTATE:GetCurrentSong()
			self:LoadBanner(target:GetJacketOrSubstitutePath())
			self:scaletoclipped(140,140):xy(_screen.cx,126)
		end
	},
	-- Let's talk about your rate mods.
	Def.BitmapText {
		Font = "Common Normal",
		OnCommand=function(self)
			self:settext(GAMESTATE:GetSongOptionsString() ~= "" and "Stage mods: " .. GAMESTATE:GetSongOptionsString() or "")
			self:vertalign(bottom):xy(_screen.cx,194):zoom(0.3):maxwidth(140 / 0.3):wrapwidthpixels(140 / 0.3):strokecolor(Color.Black)
		end
	}
}

-- #################################################
-- Player-specific stuff time.
for ip, pn in ipairs(GAMESTATE:GetHumanPlayers()) do
	local chart = GAMESTATE:IsCourseMode() and GAMESTATE:GetCurrentTrail(pn) or GAMESTATE:GetCurrentSteps(pn)
	local playerStats = StageStats():GetPlayerStageStats(pn)
	
	local page = Def.ActorFrame{
		OnCommand=function(self)
			self:x(pn == PLAYER_1 and _screen.w*0.25 or _screen.w*0.75)
		end,
		
		-- Page base...
		Def.Quad {
			OnCommand=function(self)
				self:vertalign(bottom):y(_screen.h):diffuse(LocalBlueColor(0)):zoomto(_screen.cx,_screen.cy)
			end
		},
		
		-- life graph...
		Def.GraphDisplay{
			OnCommand=function(self)
				self:Load("GraphDisplay"..ToEnumShortString(pn))
				self:Set(StageStats(), playerStats)
				self:GetChild("Line"):diffuse(PlayerColor(pn))
				self:xy(pn == PLAYER_1 and -36 or 36,(145/2)+54):visible(getenv("LifeBarType" .. ToEnumShortString(pn)) ~= "training")
			end,
		},
		
		-- and a handy indicator on the life graph for passmarks.
		LoadActor(THEME:GetPathG("_common", "smallneon")) .. {
			Condition = GAMESTATE:GetPlayerState(pn):GetPlayerOptions("ModsLevel_Current"):Passmark() > 0,
			OnCommand=function(self)
				--BodyWidth=(_screen.w-145)/2 BodyHeight=145
				local passMark = GAMESTATE:GetPlayerState(pn):GetPlayerOptions("ModsLevel_Current"):Passmark()
				local yPos = scale(passMark, 0, 1, 72.5, -72.5)
				
				self:xy(pn == PLAYER_1 and -36 or 36,((145/2)+54)+yPos):zoomto((_screen.w-145)/2,6):blend(Blend.Add):diffuse(Color.Stealth):glow(LocalGoldColor(1))
			end
		},
		
		-- Score area...
		Def.Quad {
			OnCommand=function(self)
				self:vertalign(top):y(_screen.cy-22):diffuse(Color.Black):zoomto(_screen.cx,26)
			end
		},
		-- and some kind of percentage meter thing to go over it.
		LoadActor(THEME:GetPathG("_common", "bigneon")) .. {
			OnCommand=function(self)
				local plPerc = playerStats:GetPercentDancePoints()
				self:horizalign(left):vertalign(top):xy(-_screen.cx/2,_screen.cy-22):zoomto(_screen.cx*plPerc,26):faderight(0.01)
				
				self:diffuse(CustomDifficultyToColor(chart:GetDifficulty(), chart:Title())):diffusealpha(0.4):blend(Blend.Add)
				
				--diffuse(LocalBlueColor(0.5)):diffuserightedge(lerp_color(plPerc, LocalBlueColor(0.5), PlayerColor(pn)) ):
			end
		},
		-- Overlay graphic.
		LoadActor("scoreFrame") .. {
			OnCommand=function(self)
				self:horizalign(left):vertalign(top):xy(-_screen.cx/2,_screen.cy-42):diffuse(LocalBlueColor(1))
			end
		},
		
		-- Chart rating...
		LoadActor("difficultyLight") .. {
			OnCommand=function(self)
				self:horizalign(left):vertalign(top):xy(-_screen.cx/2,_screen.cy-42):diffuse(CustomDifficultyToColor(chart:GetDifficulty(), chart:Title()))
			end
		},
		Def.BitmapText {
			Font = "Common Normal",
			OnCommand=function(self)
				if not THEME:GetMetric( Var "LoadingScreen","Summary" ) then
					self:settext(chart:GetMeter())
					
					self:zoom(0.5):xy((-_screen.cx/2)+16,_screen.cy-33):strokecolor(Color.Black)
				end
			end
		},
		
		-- Score...
		Def.BitmapText {
			Font = "Common Small",
			Text = GetPlScore(pn),
			OnCommand=function(self)
				self:horizalign(left):zoom(0.7):xy((-_screen.cx/2)+12,_screen.cy-9):strokecolor(Color.Black)
			end
		},
		-- and chart name.
		Def.BitmapText {
			Font = "Common Normal",
			OnCommand=function(self)
				if not THEME:GetMetric( Var "LoadingScreen","Summary" ) then
					self:settext(chart:Title())
					
					self:horizalign(left):zoom(0.45):xy((-_screen.cx/2)+38,_screen.cy-32):maxwidth(_screen.cx/0.4):
						DifficultyColoring(CustomDifficultyToColor(chart:GetDifficulty(), chart:Title()), chart:IsAutogen())
				end
			end
		},
				
		-- Grade!
		Def.Sprite {
			OnCommand=function(self)
				if THEME:GetMetric( Var "LoadingScreen","Summary" ) then
					self:Load(THEME:GetPathG("GradeDisplay Grade", STATSMAN:GetFinalGrade(pn)))
				else
					self:Load(THEME:GetPathG("GradeDisplay Grade", playerStats:GetGrade()))
				end
				
				if playerStats:GetGrade() == "Grade_Tier01" then
					self:rainbow():effectperiod(7)
				end
				
				self:horizalign(pn == PLAYER_1 and left or right):xy(pn == PLAYER_1 and (-_screen.cx/2)+12 or (_screen.cx/2)-12,_screen.cy-78):zoom(0.9)
			end
		},
		
		-- Personal best?
		Def.BitmapText {
			Condition = not THEME:GetMetric( Var "LoadingScreen","Summary" ),
			Font = "Common Normal",
			OnCommand=function(self)
				self:horizalign(pn == PLAYER_1 and left or right):xy(pn == PLAYER_1 and (-_screen.cx/2)+12 or (_screen.cx/2)-12,_screen.cy-136):
					strokecolor(Color.Black):zoom(0.4)
				
				if playerStats:GetPersonalHighScoreIndex() > -1 then
					if playerStats:GetPersonalHighScoreIndex() == 0 then
						self:settext( THEME:GetString("ScreenEvaluation","PBPersonal1") )
					else
						self:settextf( THEME:GetString("ScreenEvaluation","PBPersonal2"), playerStats:GetPersonalHighScoreIndex()+1 )
					end
				elseif playerStats:GetMachineHighScoreIndex() >-1 then
					if playerStats:GetMachineHighScoreIndex() == 0 then
						self:settext( THEME:GetString("ScreenEvaluation","PBMachine1") )
					else
						self:settextf( THEME:GetString("ScreenEvaluation","PBMachine2"), playerStats:GetMachineHighScoreIndex()+1 )
					end
				end
			end
		},
		
		-- What was this player's life % at the end of the song?
		-- TODO: fix incorrect life % if player failed
		-- If not playing on PPP life settings, then if this player failed, when?
		Def.BitmapText {
			Condition = not THEME:GetMetric( Var "LoadingScreen","Summary" ),
			Font = "Common Normal",
			OnCommand=function(self)
				local pMark = GAMESTATE:GetPlayerState(pn):GetPlayerOptions("ModsLevel_Current"):Passmark()
				
				self:horizalign(pn == PLAYER_1 and left or right):xy(pn == PLAYER_1 and (-_screen.cx/2)+12 or (_screen.cx/2)-12,_screen.cy-120):
					strokecolor(Color.Black):zoom(0.4)
					
				if pMark > 0 then
					local lengthMeas = GAMESTATE:IsCourseMode() and chart:GetLengthSeconds() or GAMESTATE:GetCurrentSong():GetStepsSeconds()
					local life = STATSMAN:GetCurStageStats():GetPlayerStageStats(pn):GetLifeRecord(lengthMeas, 20)
					local actualLife = life[#life]
					self:settextf(THEME:GetString("ScreenEvaluation","LifeAtEnd"), tostring(math.floor(actualLife*100)) .. "%")
				elseif playerStats:GetFailed() then
					self:settextf(THEME:GetString("ScreenEvaluation","FailedAt"), SecondsToMMSSMsMs(playerStats:GetSurvivalSeconds()))
				else
					self:settext("")
				end
			end
		},
		
		-- Mods are kinda important, let's show them.
		Def.BitmapText {
			Font = "Common Normal",
			OnCommand=function(self)
				self:strokecolor(Color.Outline):zoom(0.3):horizalign(left):vertalign(top):maxwidth((_screen.cx - 12) / 0.3):wrapwidthpixels((_screen.cx - 12) / 0.3):xy((-_screen.cx/2)+6,_screen.cy+6)
				self:settext("Mods: " .. GAMESTATE:GetPlayerState(pn):GetPlayerOptionsString("ModsLevel_Current"))
			end
		}
	}
	
	-- Why cant I, hold all these judgments??
	local j = Def.ActorFrame{
		OnCommand=function(self)
			self:xy((-_screen.cx/2)+26,_screen.h*0.7)
		end,
	}
	
	for i, line in ipairs(JudgeLines) do
		-- "real index" AKA making positioning less of a pain for myself lol
		local rI = i - (#JudgeLines/2)
		
		j[#j+1] = Def.ActorFrame{
			OnCommand=function(self)
				self:xy(0,rI*22)
				if line ~= "Holds" and GetJLineValue(line, pn) == 0 then
					self:diffusealpha(0.5)
				end
			end,
			
			-- Backing.
			Def.Quad {
				OnCommand=function(self)
					self:horizalign(left):x(-4):zoomto(290,20):diffuse(Color.Black)
				end
			},
			-- Def.Quad {
				-- OnCommand=function(self)
					-- self:horizalign(left):x(-4):zoomto(140,20):diffuse(i % 2 == 0 and LocalBlueColor(0.2) or LocalBlueColor(0.4))
				-- end
			-- },
			LoadActor("jFrame") .. {
				OnCommand=function(self)
					self:horizalign(left):x(-18):diffuse(i % 2 == 0 and LocalBlueColor(0.2) or LocalBlueColor(0.4))
				end
			},
			LoadActor("jGlow") .. {
				OnCommand=function(self)
					self:horizalign(left):x(-18):diffuse(GameColor.Judgment[line])
				end
			},
			
			-- What's the judgment name...
			Def.BitmapText {
				Font = "Common Normal",
				Text = string.upper(LoadModule("Gameplay.AutoJudgeNames.lua")(line)),
				OnCommand=function(self)
					self:horizalign(left):zoom(0.55):maxwidth(140/0.6):diffuse(GameColor.Judgment[line]):strokecolor(Color.Black)
				end
			},
			-- and what's the damage?
			Def.BitmapText {
				Font = "Common Small",
				Text = GetJLineValue(line, pn),
				OnCommand=function(self)
					self:horizalign(left):x(150):zoom(0.6):strokecolor(Color.Black)
					if not THEME:GetMetric( Var "LoadingScreen","Summary" ) and line == "MaxCombo" and playerStats:FullCombo() then
						self:diffuseblink():effectcolor1(Color.White):effectcolor2(NeonColor.Yellow):effectperiod(0.1)
					end
				end
			},
			-- A percentage? How classy.
			Def.BitmapText {
				Font = "Common Small",
				OnCommand=function(self)
					self:horizalign(right):x(284):zoom(0.4):diffuse(GameColor.Judgment[line]):strokecolor(Color.Black):textglowmode("TextGlowMode_Inner")
					if line ~= "MaxCombo" and line ~= "Holds" then
						local perc = GetPercentageOfTNS(line, pn)
						self:settext(FormatPercentScore(GetPercentageOfTNS(line, pn)))
						if GetPercentageOfTNS(line, pn) == 1 then
							self:glowblink():effectcolor1(Color.White):effectcolor2(Color.Stealth):effectperiod(0.1)
						end
					end
				end
			}
		}
	end
	
	page[#page+1] = j
	
	t[#t+1] = page
end

-- Let's top it off with a divider.
t[#t+1] = LoadActor(THEME:GetPathG("_common", "smallneon")) .. {
	OnCommand=function(self)
		self:xy(_screen.cx,_screen.cy-42):horizalign(left):zoomto(_screen.cy*1.2,20):rotationz(90)
	end
}

t[#t+1] = LoadFallbackB()

return t
