-- This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
-- To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
-- or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.

local MereHealingFrames, privateVars = ...

MereHealingFrames.HealingBar = {
	Height = nil,
	Width = nil,
	Max = 100,
	CurrentValue = 100,
	ParentFrame = nil,
	TextAnchor = "BOTTOMRIGHT",
	showText = true,
	Frame = nil,
	Bar = nil,
	Text = nil,
	barMode = "health",
	isActive = true,
    framesLoaded = false,
    currentRounder = "none",
    textFormatter = "full",
    LayoutOffset = 0,
    topLeftX = nil,
    topLeftY = nil,
    borderedText = true,
    fontSize = 10
	}

function MereHealingFrames.HealingBar:new (settings)
	local this = settings or {}

	setmetatable(this, self)
	self.__index = self
	return this
end

function MereHealingFrames.HealingBar.Create(settings, ParentFrame)
	local healingBar = MereHealingFrames.HealingBar:new (settings)

	healingBar.ParentFrame = ParentFrame

    local framesRequest = {
        Frame = 2,
        Texture = 1,
    }

    Library.LibAsyncFrames.AyncLoadFrames(framesRequest,
        function (...) MereHealingFrames.HealingBar.FramesLoadedCallback(healingBar, ...) end,
        ParentFrame, "MereHealingFrames")

	return healingBar
end

function MereHealingFrames.HealingBar:FramesLoadedCallback(frames)
    self.Frame = frames:CreateFrame("Frame", "Background", self.ParentFrame)
    self.Texture = frames:CreateFrame("Texture", "Background", self.Frame)
    self.Bar = frames:CreateFrame("Frame", "Background", self.Frame)
    self.Text = MereHealingFrames.UI.Widget.ShadowedText:new("Value", self.Frame)

    self.Texture:SetPoint("TOPLEFT", self.Frame, "TOPLEFT")
    self.Texture:SetPoint("BOTTOMRIGHT", self.Frame, "BOTTOMRIGHT")

    self.Frame:SetLayer(MereHealingFrames.Layers.CalculateLayer(self.LayoutOffset, "HealingBarBase"))
    self.Frame:SetBackgroundColor(0,0,0,1)
    self.Frame:SetPoint("TOPLEFT", self.ParentFrame, "TOPLEFT")

    self.Bar:SetBackgroundColor(0,0,0,1)
    self.Bar:SetPoint("TOPLEFT", self.Frame, "TOPLEFT")
    self.Bar:SetLayer(MereHealingFrames.Layers.CalculateLayer(self.LayoutOffset, "HealingBarBar"))

    self.Text:SetVisible(self.showText)
    self.Text:SetText("-/-(-%)")
    self.Text:SetFontColor(MereHealingFrames.Colours.FetchRGB("HealthBarText"))
    self.Text:SetShadowColor(MereHealingFrames.Colours.FetchRGB("HealthBarTextShadow"))
    self.Text:SetLayer(MereHealingFrames.Layers.CalculateLayer(self.LayoutOffset, "HealingBarText"))
    self.Text:SetPoint(self.TextAnchor, self.Frame, self.TextAnchor, 0, 3)
    self.Text:ShadowedText(self.borderedText)
    self.Text:SetFontSize(self.fontSize)

    self.UpdateBarDisplay = self.UpdateBarDisplayFramesLoaded
    self.framesLoaded = true

    self:SetVisible(self.isActive)

    self:Move(self.topLeftX, self.topLeftY, true)
    self:Resize(self.Width, self.Height, true)
    self:SetBarMode(self.barMode)
    self:UpdateBar(self.CurrentValue, self.Max)
end

function MereHealingFrames.HealingBar:Initialize(LayoutOffset, barMode)
	if not LayoutOffset then
		error("no LayoutOffset")
	end

    self.LayoutOffset = LayoutOffset
	self:SetBarMode(barMode)
end

function MereHealingFrames.HealingBar:SetFontSize(fontSize)
    self.fontSize = fontSize
    if not self.framesLoaded then
        return
    end

    self.Text:SetFontSize(fontSize)
end

function MereHealingFrames.HealingBar:Resize(width, height, internalCall)
    if (not internalCall and self.Width == width and self.Height == height) then
        return
    end
	self.Width = width
	self.Height = height

    if not self.framesLoaded then
        return
    end

	self.Frame:SetWidth(width)
	self.Frame:SetHeight(height)

	self:UpdateBar(nil, nil)
	self.Bar:SetHeight(height)
end

function MereHealingFrames.HealingBar:Move(topLeftX, topLeftY, internalCall)
    if (not internalCall and self.topLeftX == topLeftX and self.topLeftY == topLeftY) then
        return
    end
    self.topLeftX = topLeftX
    self.topLeftY = topLeftY

    if not self.framesLoaded then
        return
    end
	self.Frame:SetPoint("TOPLEFT", self.ParentFrame, "TOPLEFT", topLeftX, topLeftY)
end

local function donothing()
    return
end

function MereHealingFrames.HealingBar:ActivateBar(activate)
    if (activate) then
        -- clearing these should revert to the default values
        self.UpdateBar = nil
        self.UpdateValue = nil
        self.UpdateMax = nil
    else
        self.UpdateBar = donothing
        self.UpdateValue = donothing
        self.UpdateMax = donothing
    end
end

function MereHealingFrames.HealingBar:UpdateBar(value, maxValue)
	if (value) then
		self.CurrentValue = value
	end
	if (maxValue) then
		self.Max = maxValue
	end

    return self:UpdateBarDisplay()
end

function MereHealingFrames.HealingBar:UpdateValue(value)
    self.CurrentValue = value
    return self:UpdateBarDisplay()
end

function MereHealingFrames.HealingBar:UpdateMax(maxValue)
    self.Max = maxValue
    return self:UpdateBarDisplay()
end

function MereHealingFrames.HealingBar:UpdateBarDisplayFramesLoaded()
	local percentage = (self.CurrentValue / self.Max)
	local newWidth = self.Width * percentage
	self.Bar:SetWidth(newWidth)

	return self:UpdateText(percentage)
end

function MereHealingFrames.HealingBar:UpdateBarDisplayNoFrames()
    return
end
MereHealingFrames.HealingBar.UpdateBarDisplay = MereHealingFrames.HealingBar.UpdateBarDisplayNoFrames


local function nullRounder(value)
	return value
end

local function thousandsRounder(value)
	return math.floor(value/1000) .. "k"
end

local function thousandpointRounder(value)
	return math.floor(value/1000) .. "." .. math.floor((value%1000)/100) .. "k"
end

local roundingFuncs = {
	none = nullRounder,
	thousands = thousandsRounder,
	thousandspoint = thousandpointRounder,
}

local function nulltext(roundingFunc, current, maxValue, percentage)
	return ""
end

local function percentageText(roundingFunc, current, maxValue, percentage)
	return string.format("(%d%%)", percentage)
end

local function currentMaxText(roundingFunc, current, maxValue, percentage)
	return string.format("%s/%s", roundingFunc(current), roundingFunc(maxValue))
end

local function fullText(roundingFunc, current, maxValue, percentage)
	return string.format("%s/%s (%d%%)", roundingFunc(current), roundingFunc(maxValue), percentage)
end

local function missingText(roundingFunc, current, maxValue, percentage)
	local missingHealth = maxValue - current
	if missingHealth == 0 then
		return ""
	else
		return string.format("-%s", roundingFunc(missingHealth))
	end
end

function MereHealingFrames.HealingBar:UpdateText(percentage)
    local newText = self.textFormatter(self.currentRounder, self.CurrentValue, self.Max, (percentage*100))
    return self.Text:SetText(newText)
end

local textingFuncs = {
	none = nulltext,
	percentage = percentageText,
	currentMax = currentMaxText,
	full = fullText,
	missing = missingText
}

MereHealingFrames.HealingBar.currentRounder = nullRounder
MereHealingFrames.HealingBar.textFormatter = fullText

function MereHealingFrames.HealingBar:SetTextlayout(formatter, rounding)
	self.currentRounder = roundingFuncs[rounding] or nullRounder
	self.textFormatter = textingFuncs[formatter] or nulltext
    self.showText = self.textFormatter  ~= nulltext

    if (self.showText) then
        self.UpdateText = nil
    else
        self.UpdateText = donothing
    end

    MereHealingFrames.Debug(6, "SetTextLayout: mode: %s format %s rounding: %s", self.barMode, formatter, rounding)

    if not self.framesLoaded then
        return
    end
	self.Text:SetVisible(self.showText)
	self:UpdateBar(self.CurrentValue, self.Max)
end

function MereHealingFrames.HealingBar:SetVisible(isVisible)
    self.isActive = isVisible
    self:ActivateBar(self.isActive)

    if not self.framesLoaded then return end

	self.Frame:SetVisible(isVisible)
	if (isVisible) then
		self.Text:SetVisible(self.showText)
    end
end

function MereHealingFrames.HealingBar:ChangeColour(colour)
    if not self.framesLoaded then return end
	self.Bar:SetBackgroundColor(colour.r, colour.g, colour.b, colour.a)
end

function MereHealingFrames.HealingBar:SetBarMode(barMode)
	self.barMode = barMode

    if not self.framesLoaded then
        return
    end

    if barMode == "rogue" then
		self:ChangeColour(MereHealingFrames.Colours.FetchColour("BarRogue"))
        self.Text:SetFontColor(MereHealingFrames.Colours.FetchRGB("EnergyBarText"))
        self.Text:SetShadowColor(MereHealingFrames.Colours.FetchRGB("EnergyBarTextShadow"))
	elseif barMode == "warrior" then
		self:ChangeColour(MereHealingFrames.Colours.FetchColour("BarWarrior"))
        self.Text:SetFontColor(MereHealingFrames.Colours.FetchRGB("PowerBarText"))
        self.Text:SetShadowColor(MereHealingFrames.Colours.FetchRGB("PowerBarTextShadow"))
	elseif barMode == "mana" then
		self:ChangeColour(MereHealingFrames.Colours.FetchColour("BarMana"))
        self.Text:SetFontColor(MereHealingFrames.Colours.FetchRGB("ManaBarText"))
        self.Text:SetShadowColor(MereHealingFrames.Colours.FetchRGB("ManaBarTextShadow"))
	elseif barMode == "health" then
		self:UpdateHealthBarColour()
        self.Text:SetFontColor(MereHealingFrames.Colours.FetchRGB("HealthBarText"))
        self.Text:SetShadowColor(MereHealingFrames.Colours.FetchRGB("HealthBarTextShadow"))
	else
		error("Unknown bar mode: " .. barMode)
    end
end

function MereHealingFrames.HealingBar:SetCallingMode(callingMode, callingName)
	self.callingMode = callingMode
	self.callingName = callingName
	self:UpdateHealthBarColour()
end

function MereHealingFrames.HealingBar:SetRoleMode(roleMode, roleName)
    self.roleMode = roleMode
    self.roleName = roleName
    self:UpdateHealthBarColour()
end

function MereHealingFrames.HealingBar:UpdateHealthBarColour()
	if self.barMode == "health" then
		local barColour = "BarHealth"
        if self.roleMode then
            local roleName = self.roleName
            if roleName == "tank" then
                barColour = "RoleTank"
            elseif roleName == "dps" then
                barColour = "RoleDps"
            elseif roleName == "heal" then
                barColour = "RoleHealer"
            elseif roleName == "support" then
                barColour = "RoleSupport"
            end
		elseif self.callingMode then
			local callingName = self.callingName
			if callingName == "warrior" then
				barColour = "WarriorColour"
			elseif callingName == "mage" then
				barColour = "MageColour"
			elseif callingName == "cleric" then
				barColour = "ClericColour"
			elseif callingName == "rogue" then
				barColour = "RogueColour"
			end
		end
		self:ChangeColour(MereHealingFrames.Colours.FetchColour(barColour))
	end
end

function MereHealingFrames.HealingBar:SetBorderedText(borderedText)
    self.borderedText = borderedText
    if not self.framesLoaded then return end
	self.Text:ShadowedText(self.borderedText)
end