local XP = {}
local L = ShadowUF.L
ShadowUF:RegisterModule(XP, "xpBar", L["XP/Rep bar"], true)

local function OnEnter(self)
	if( self.tooltip ) then
		GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT")
		GameTooltip:SetText(self.tooltip)
	end
end

local function OnLeave(self)
	GameTooltip:Hide()
end

function XP:OnEnable(frame)
	if( not frame.xpBar ) then
		frame.xpBar = CreateFrame("Frame", nil, frame)
		frame.xpBar:SetScript("OnEnter", OnEnter)
		frame.xpBar:SetScript("OnLeave", OnLeave)
		frame.xpBar:EnableMouse(true)
		
		frame.xpBar.xp = ShadowUF.Units:CreateBar(frame.xpBar)
		frame.xpBar.xp:SetPoint("BOTTOMLEFT", frame.xpBar)
		frame.xpBar.xp:SetPoint("BOTTOMRIGHT", frame.xpBar)
				
		if( frame.unitType == "player" ) then
			frame.xpBar.rep = ShadowUF.Units:CreateBar(frame.xpBar)
			frame.xpBar.rep:SetPoint("TOPLEFT", frame.xpBar)
			frame.xpBar.rep:SetPoint("TOPRIGHT", frame.xpBar)
		end
		
		frame.xpBar.rested = CreateFrame("StatusBar", nil, frame.xpBar.xp)
		frame.xpBar.rested:SetFrameLevel(frame.xpBar.xp:GetFrameLevel() - 1)
		frame.xpBar.rested:SetAllPoints(frame.xpBar.xp)
	end
	
	frame:RegisterNormalEvent("ENABLE_XP_GAIN", self, "Update")
	frame:RegisterNormalEvent("DISABLE_XP_GAIN", self, "Update")

	if( frame.unitType == "player" ) then
		frame:RegisterNormalEvent("PLAYER_XP_UPDATE", self, "Update")
		frame:RegisterNormalEvent("UPDATE_EXHAUSTION", self, "Update")
		frame:RegisterNormalEvent("PLAYER_LEVEL_UP", self, "Update")
		frame:RegisterNormalEvent("UPDATE_FACTION", self, "Update")
	else
		frame:RegisterNormalEvent("UNIT_PET_EXPERIENCE", self, "Update")
		frame:RegisterUnitEvent("UNIT_LEVEL", self, "Update")
	end

	frame:RegisterUpdateFunc(self, "Update")
end

function XP:OnDisable(frame)
	frame:UnregisterAll(self)
end

function XP:OnLayoutApplied(frame)
	if( frame.visibility.xpBar ) then
		frame.xpBar.xp:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
		frame.xpBar.xp:SetStatusBarColor(ShadowUF.db.profile.xpColors.normal.r, ShadowUF.db.profile.xpColors.normal.g, ShadowUF.db.profile.xpColors.normal.b, ShadowUF.db.profile.bars.alpha)
		
		frame.xpBar.xp.background:SetVertexColor(ShadowUF.db.profile.xpColors.normal.r, ShadowUF.db.profile.xpColors.normal.g, ShadowUF.db.profile.xpColors.normal.b, ShadowUF.db.profile.bars.backgroundAlpha)
		frame.xpBar.xp.background:SetTexture(ShadowUF.Layout.mediaPath.statusbar)
		
		frame.xpBar.rested:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
		frame.xpBar.rested:SetStatusBarColor(ShadowUF.db.profile.xpColors.rested.r, ShadowUF.db.profile.xpColors.rested.g, ShadowUF.db.profile.xpColors.rested.b, ShadowUF.db.profile.bars.alpha)

		if( frame.xpBar.rep ) then
			frame.xpBar.rep:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
			frame.xpBar.rep.background:SetTexture(ShadowUF.Layout.mediaPath.statusbar)
		end
	end
end

-- Format 5000 into 5,000
local function formatNumber(number)
	local found
	while( true ) do
		number, found = string.gsub(number, "^(-?%d+)(%d%d%d)", "%1,%2")
		if( found == 0 ) then break end
	end
	
	return number
end

function XP:UpdateRep(frame)
	if( not frame.xpBar.rep ) then return end
	local name, reaction, min, max, current = GetWatchedFactionInfo()
	if( not name ) then
		frame.xpBar.rep:Hide()
		return
	end
	
	-- Blizzard stores faction info related to Exalted, not your current level, so get more mathier to find the current reputation using the current standing tier
	current = math.abs(min - current)
	max = math.abs(min - max)
		
	local color = FACTION_BAR_COLORS[reaction]
	frame.xpBar.rep:SetMinMaxValues(0, max)
	frame.xpBar.rep:SetValue(current)
	frame.xpBar.rep.tooltip = string.format(L["%s (%s): %s/%s (%.2f%% done)"], name, GetText("FACTION_STANDING_LABEL" .. reaction, UnitSex("player")), formatNumber(current), formatNumber(max), (max > 0 and current / max or 0) * 100)
	frame.xpBar.rep:SetStatusBarColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
	frame.xpBar.rep.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
	frame.xpBar.rep:Show()
end

function XP:UpdateXP(frame)
	-- At the level cap or XP is disabled, or the pet is actually a vehicle right now, swap to reputation bar (or hide it)
	if( UnitLevel(frame.unitOwner) == MAX_PLAYER_LEVEL or IsXPUserDisabled() or ( frame.unitOwner == "pet" and UnitExists("vehicle") ) ) then
		frame.xpBar.xp:Hide()
		return
	end
	
	local current, max
	if( frame.unitOwner == "player" ) then
		current, max = UnitXP(frame.unitOwner), UnitXPMax(frame.unitOwner)
	else
		current, max = GetPetExperience()
	end
	
	local min = math.min(0, current)
	frame.xpBar.xp:SetMinMaxValues(min, max)
	frame.xpBar.xp:SetValue(current)
	frame.xpBar.xp:Show()
	
	if( frame.unitOwner == "player" and GetXPExhaustion() ) then
		frame.xpBar.rested:SetMinMaxValues(min, max)
		frame.xpBar.rested:SetValue(math.min(current + GetXPExhaustion(), max))
		frame.xpBar.rested:Show()
		frame.xpBar.xp.tooltip = string.format(L["Level %s - %s: %s/%s (%.2f%% done), %s rested."], UnitLevel(frame.unitOwner), UnitLevel(frame.unitOwner) + 1, formatNumber(current), formatNumber(max), (max > 0 and current / max or 0) * 100, formatNumber(GetXPExhaustion()))
	else
		frame.xpBar.rested:Hide()
		frame.xpBar.xp.tooltip = string.format(L["Level %s - %s: %s/%s (%.2f%% done)"], UnitLevel(frame.unitOwner), UnitLevel(frame.unitOwner) + 1, formatNumber(current), formatNumber(max), (max > 0 and current / max or 0) * 100)
	end
end

function XP:Update(frame)
	self:UpdateRep(frame)
	self:UpdateXP(frame)

	if( ( not frame.xpBar.rep or not frame.xpBar.rep:IsShown() ) and not frame.xpBar.xp:IsShown() ) then
		ShadowUF.Layout:SetBarVisibility(frame, "xpBar", false)
		return
	end
	
	ShadowUF.Layout:SetBarVisibility(frame, "xpBar", true)
	if( frame.xpBar.rep and frame.xpBar.rep:IsVisible() and frame.xpBar.xp:IsVisible() ) then
		frame.xpBar.rep:SetHeight(frame.xpBar:GetHeight() * 0.48)
		frame.xpBar.xp:SetHeight(frame.xpBar:GetHeight() * 0.48)
		frame.xpBar.tooltip = frame.xpBar.rep.tooltip .. "\n" .. frame.xpBar.xp.tooltip

	elseif( frame.xpBar.rep and frame.xpBar.rep:IsVisible() ) then
		frame.xpBar.rep:SetHeight(frame.xpBar:GetHeight())
		frame.xpBar.tooltip = frame.xpBar.rep.tooltip

	elseif( frame.xpBar.xp:IsVisible() ) then
		frame.xpBar.xp:SetHeight(frame.xpBar:GetHeight())
		frame.xpBar.tooltip = frame.xpBar.xp.tooltip
	end
end
