local Srendarr = _G['Srendarr']

local ICON_SIZE         = Srendarr.ICON_SIZE
local UPDATE_THRESHOLD  = Srendarr.UPDATE_THRESHOLD
local round             = zo_round
local strfind           = zo_plainstrfind
local tsort             = table.sort
local tremove           = table.remove
local tinsert           = table.insert

local Aura              = Srendarr.Aura
local AuraFrame         = {}

local function SortByTime(a, b)
    if (a.k_type < 3 and b.k_type < 3) then -- timed, sort by time
        return a.k_finish > b.k_finish
    elseif (a.k_type == b.k_type) then -- non-timed, same type, sort by name
        return a.k_name > b.k_name
    else -- non-timed, different types, sort by type
        return a.k_type > b.k_type
    end
end

local function SortByName(a, b)
    return a.k_name > b.k_name
end

local function UpdateDisplayCentered(self)
    tsort(self.k_auraSorted, self.k_sortFunc)

    self.k_offsetI = self.k_offsetX * ((#self.k_auraSorted - 1) / 2)

    for i, aura in pairs(self.k_auraSorted) do
        aura:ClearAnchors()
        aura:SetAnchor(CENTER, self, CENTER, self.k_offsetI, 0)
        self.k_offsetI = self.k_offsetI - self.k_offsetX
    end
end

local function UpdateDisplayDirection(self)
    tsort(self.k_auraSorted, self.k_sortFunc)

    for i, aura in ipairs(self.k_auraSorted) do
        aura:ClearAnchors()
        aura:SetAnchor(self.k_point, self, self.k_point, self.k_offsetX * (i - 1), self.k_offsetY * (i - 1))
    end
end

local function ConfigureUpdateDisplay(self)
    local db = self.k_db

    if (db.auraSort == 'NAME') then
        self.k_sortFunc = SortByName
    else
        self.k_sortFunc = SortByTime
    end

    if (db.auraGrowth == 'LEFTCENTER' or db.auraGrowth == 'RIGHTCENTER') then
        self.k_offsetX = round((db.auraPadding + ICON_SIZE) * db.scale * ((db.auraGrowth == 'LEFTCENTER') and 1 or -1))
        self['UpdateDisplay'] = UpdateDisplayCentered
    else
        if (db.auraGrowth == 'UP') then
            self.k_point, self.k_offsetX, self.k_offsetY = BOTTOM, 0, round(-1 * (db.auraPadding + ICON_SIZE) * db.scale)
        elseif (db.auraGrowth == 'DOWN') then
            self.k_point, self.k_offsetX, self.k_offsetY = TOP, 0, round((db.auraPadding + ICON_SIZE) * db.scale)
        elseif (db.auraGrowth == 'LEFT') then
            self.k_point, self.k_offsetX, self.k_offsetY = RIGHT, round(-1 * (db.auraPadding + ICON_SIZE) * db.scale), 0
        else -- RIGHT
            self.k_point, self.k_offsetX, self.k_offsetY = LEFT, round((db.auraPadding + ICON_SIZE) * db.scale), 0
        end

        self['UpdateDisplay'] = UpdateDisplayDirection
    end
end

local function AddAura(self, aType, tType, name, icon, start, finish, isShield, abilityType, buff, abilityId, effectType)
    local existingAura = self.k_auraActive[name] or nil

    --vampirism stage check, should be working for all 3 language versions
    if strfind(name, 'Vampirism') then
        if strfind(name, '1') then
            icon = 'Srendarr/Icons/Stage1.dds'
        elseif strfind(name, '2') then
            icon = 'Srendarr/Icons/Stage2.dds'
        elseif strfind(name, '3') then
            icon = 'Srendarr/Icons/Stage3.dds'
        elseif strfind(name, '4') then
            icon = 'Srendarr/Icons/Stage4.dds'
        end
    end

    -- Skip Minor Buffs
    if (Srendarr.db.hideMinorBuffs and Srendarr.MinorBuffs[abilityId] ~= nil) then
        return
    end

    -- Skip Major Buffs
    if (Srendarr.db.hideMajorBuffs and Srendarr.MajorBuffs[abilityId] ~= nil) then
        return
    end

    if (aType < 3) then -- timed
        if (existingAura) then -- existingAura, update it
            if (finish > (existingAura.k_finish + UPDATE_THRESHOLD)) then -- finish time changed enough to potentially need to alter display list
                existingAura.k_start, existingAura.k_finish = start, finish
                self:UpdateDisplay()
            else -- minor change in timing (probably from hook), update data but don't alter display list
                existingAura.k_start, existingAura.k_finish = start, finish
            end

            if (existingAura.k_isGhost) then -- was ghosting, set to full visibility
                existingAura.icon:SetDesaturation(0)
                existingAura:SetAlpha(1)
                existingAura.k_isGhost = false
            end
        else
            local newAura = Aura:New(self, aType, tType, name, icon, start, finish, isShield, abilityType, buff, abilityId)
            Srendarr:AddTimer(tType, name, newAura)
            tinsert(self.k_auraSorted, newAura)
            self:UpdateDisplay()
        end
    else -- toggle or passive
        if (existingAura) then return end -- existing aura, nothing to do, abort

        local newAura = Aura:New(self, aType, tType, name, icon, start, finish, isShield, abilityType, buff, abilityId)
        tinsert(self.k_auraSorted, newAura)
        self:UpdateDisplay()
    end
end

local function RemoveAura(self, name)
    local remAura = self.k_auraActive[name] or nil

    if (remAura) then -- aura exists, remove
        Srendarr:RemoveTimer(remAura.k_timerType, name)
        remAura:Release()

        for i, aura in pairs(self.k_auraSorted) do
            if (aura.k_name == name) then
                tremove(self.k_auraSorted, i)
                break
            end
        end

        self:UpdateDisplay()
    end
end

local function RemoveAllAuras(self)
    for _, aura in pairs(self.k_auraActive) do
        aura:Release()
    end

    while (#self.k_auraSorted > 0) do
        tremove(self.k_auraSorted, 1)
    end
end

local function ConfigureAllAuras(self)
    for _, aura in pairs(self.k_auraActive) do
        aura:Configure()
    end

    for _, aura in pairs(self.k_auraPool) do
        aura:Configure()
    end
end

local function SetAurasNonInteractive(self)
    for _, aura in pairs(self.k_auraActive) do
        aura:SetMouseEnabled(false)
    end

    for _, aura in pairs(self.k_auraPool) do
        aura:SetMouseEnabled(false)
    end
end

function AuraFrame:New(id, alpha)
    local frame = WINDOW_MANAGER:CreateControl(nil, Srendarr.auraAnchors[id], CT_CONTROL)
    frame:SetKeyboardEnabled(false)
    frame:SetMouseEnabled(false)
    frame:SetMovable(false)
    frame:SetDimensions(ICON_SIZE, ICON_SIZE)
    frame:SetAnchor(CENTER)
    frame:SetAlpha(alpha)

    frame.k_auraPool    = {}
    frame.k_auraActive  = {}
    frame.k_auraSorted  = {}
    frame.k_db          = Srendarr.db.frames[id]
    frame.k_id          = id

    frame['ConfigureUpdateDisplay'] = ConfigureUpdateDisplay
    frame['AddAura']                = AddAura
    frame['RemoveAura']             = RemoveAura
    frame['RemoveAllAuras']         = RemoveAllAuras
    frame['ConfigureAllAuras']      = ConfigureAllAuras
    frame['SetAurasNonInteractive'] = SetAurasNonInteractive

    frame:ConfigureUpdateDisplay()

    return frame
end

Srendarr.AuraFrame = AuraFrame