local _, addon = ...

local IsSpecializationActivateSpell = IsSpecializationActivateSpell;

local function IsTalentChaningSpell(spellID)
    return spellID and IsSpecializationActivateSpell(spellID) or (spellID == 384255);   --COMMIT_COMBAT_TRAIT_CONFIG_CHANGES_SPELL_ID
end

local PIXEL;
local FONT_PIXEL_HEIGHT = 16;
local BAR_PIXEL_HEIGHT_SMALL = 28;
local BAR_PIXEL_WDITH_SMALL = 192;

local LoadingBar;

local TalentTreeLoadingBarUtil = {};
addon.TalentTreeLoadingBarUtil = TalentTreeLoadingBarUtil;


function TalentTreeLoadingBarUtil:Init()
    if not LoadingBar then
        LoadingBar = CreateFrame("Frame", nil, NarciMiniTalentTree, "NarciTalentTreeLoadingBarTemplate");
        local pixel = NarciAPI.GetPixelForWidget(NarciMiniTalentTree);
        LoadingBar:UpdatePixel(pixel);
    end
end

function TalentTreeLoadingBarUtil:SetFromSpecButton(specButton)
    self:Init();

    LoadingBar:SetParentObject(specButton, "spec");
    LoadingBar.ClipFrame.Name:SetText(specButton.Name:GetText());
    LoadingBar:OnInitiateCasting();
end

function TalentTreeLoadingBarUtil:SetFromLoadoutToggle(toggle)
    self:Init();

    LoadingBar:SetParentObject(toggle, "loadout");
    LoadingBar.ClipFrame.Name:SetText("Activating");
    LoadingBar:OnInitiateCasting();
end

function TalentTreeLoadingBarUtil:IsBarVisible()
    return LoadingBar and LoadingBar:IsShown()
end

function TalentTreeLoadingBarUtil:HideBar()
    if LoadingBar then
        LoadingBar:Hide();
    end
end


NarciTalentTreeLoadingBarMixin = {};

function NarciTalentTreeLoadingBarMixin:UpdatePixel(px)
    PIXEL = px;

    local font = self.ClipFrame.Name:GetFont();
    self.ClipFrame.Name:SetFont(font, FONT_PIXEL_HEIGHT * px, "");

    self.ClipFrame.BlackLine:SetWidth(2*px);
    self.ClipFrame.BlackLine:SetPoint("TOPRIGHT", self.ClipFrame, "TOPRIGHT", -2*px, 0);
    self.ClipFrame.BlackLine:SetPoint("BOTTOMRIGHT", self.ClipFrame, "BOTTOMRIGHT", -2*px, 0);
    self.FinishingLine:SetWidth(2*px);
end

function NarciTalentTreeLoadingBarMixin:SetParentObject(anchorTo, mode)
    if mode == "spec" then
        self:ClearAllPoints();
        self:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", 0, 0);
        self:SetPoint("BOTTOMRIGHT", anchorTo, "BOTTOMRIGHT", 0, 0);
        if mode ~= self.mode then
            self.mode = mode;
            self:SetFullWidth( anchorTo:GetWidth(), anchorTo:GetHeight() );
            self.FinishingLine:Hide();
            self.ClipFrame.Name:ClearAllPoints();
            self.ClipFrame.Name:SetPoint("LEFT", self, "LEFT", 10, 0);
            self.ClipFrame.Name:SetJustifyH("LEFT");
        end
    elseif mode == "loadout" then
        self:ClearAllPoints();
        self:SetPoint("CENTER", anchorTo, "CENTER", 0, 0);
        if mode ~= self.mode then
            self.mode = mode;
            self:SetFullWidth(BAR_PIXEL_WDITH_SMALL, BAR_PIXEL_HEIGHT_SMALL, true);
            self.FinishingLine:Show();
            self.ClipFrame.Name:ClearAllPoints();
            self.ClipFrame.Name:SetPoint("CENTER", self, "CENTER", 0, 0);
            self.ClipFrame.Name:SetJustifyH("CENTER");
        end
    end
    self:SetFrameLevel(anchorTo:GetFrameLevel() + 10);
end

function NarciTalentTreeLoadingBarMixin:SetFullWidth(width, height, isPixelSize)
    local barWidth, barHeight;
    local pixelW, pixelH;

    if isPixelSize then
        barWidth = width * PIXEL;
        barHeight = height * PIXEL;
        pixelW = width;
        pixelH = height;
    else
        barWidth = width;
        barHeight = height;
        pixelW = width / PIXEL;
        pixelH = height / PIXEL;
    end

    self:SetSize(barWidth, barHeight);

    self.barPixelWidth = pixelW;
    self.translationRange = pixelW - 256;
    if self.translationRange < 0 then
        self.translationRange = 0;
    end

    self.fullWidth = barWidth;
    self.coordTop = (1 - (pixelH / 64))/2;
    self.ClipFrame.Background:SetTexCoord((256 - pixelW)/256, 1, self.coordTop, 1-self.coordTop);
end

function NarciTalentTreeLoadingBarMixin:ListenEvents(state)
    if state then
        self:RegisterUnitEvent("UNIT_SPELLCAST_START", "player");
        self:RegisterUnitEvent("UNIT_SPELLCAST_FAILED", "player");
        self:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED", "player");
    else
        self:UnregisterEvent("UNIT_SPELLCAST_START");
        self:UnregisterEvent("UNIT_SPELLCAST_FAILED");
        self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED");
    end
end

function NarciTalentTreeLoadingBarMixin:OnHide()
    self:ListenEvents(false);
    self:Hide();
    self:SetScript("OnUpdate", nil);
end

function NarciTalentTreeLoadingBarMixin:OnInitiateCasting()
    self:ListenEvents(true);
    self:SetAlpha(0);
    self:SetScript("OnUpdate", nil);
    self:Show();
    self.ClipFrame.Background:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\TalentTree\\ProgressBarBackground");
end

local function SetBarTexCoord(texture, progress, translationRange, barPixelWidth, coordTop)
    texture:SetTexCoord(translationRange*(1-progress)/256, (256*(1-progress) + progress * barPixelWidth)/256, coordTop, 1-coordTop);
end

local function LoadingBar_OnUpdate(self, elapsed)
    self.t = self.t + elapsed;
    self.p = self.t / self.d;
    if self.p > 1 then
        self.p = 1;
        self:SetScript("OnUpdate", nil);
    end
    self.ClipFrame:SetWidth( self.p * self.fullWidth );
    SetBarTexCoord(self.ClipFrame.Background, self.p, self.translationRange, self.barPixelWidth, self.coordTop);
end

local function LoadingBar_Interrupted_OnUpdate(self, elapsed)
    self.t = self.t + elapsed;

    self.p = self.p + elapsed*8;
    if self.p > 1 then
        self.p = 1;
    end
    self.ClipFrame:SetWidth( self.p * self.fullWidth );
    SetBarTexCoord(self.ClipFrame.Background, 1, self.translationRange, self.barPixelWidth, self.coordTop);

    if self.t > 0 then
        local a = 1 - 5*self.t;
        if a < 0 then
            self:SetScript("OnUpdate", nil);
            self:Hide();
        else
            self:SetAlpha(a);
        end
    end
end

function NarciTalentTreeLoadingBarMixin:OnInterrupted()
    self.ClipFrame.Background:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\TalentTree\\ProgressBarBackgroundRed");
    SetBarTexCoord(self.ClipFrame.Background, 1, 0, self.barPixelWidth, self.coordTop);
    self.ClipFrame:SetWidth(self.fullWidth);
    self.ClipFrame.Name:SetText(INTERRUPTED);
    self.t = -0.5;
    self:SetScript("OnUpdate", LoadingBar_Interrupted_OnUpdate);
end


function NarciTalentTreeLoadingBarMixin:OnEvent(event, ...)
    if event == "UNIT_SPELLCAST_START" then
        local spellID = select(3, ...);
        if IsTalentChaningSpell(spellID) then
            self:UnregisterEvent(event);
            local _, _, _, startTime, endTime = UnitCastingInfo("player");
            local duration = (endTime - startTime)/1000;
            if duration ~= 0 then
                self.t = 0;
                self.d = duration;
                self:SetAlpha(1);
                self:SetScript("OnUpdate", LoadingBar_OnUpdate);
            end
        end

    elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
        local cancelledSpellID = select(3, ...);
        if IsTalentChaningSpell(cancelledSpellID) then
            self:OnInterrupted();
        end
    end
end