local addon, ns = ...
local cargBags = ns.cargBags

local _
local L = cBnivL


local itemSlotSize = ns.options.itemSlotSize
------------------------------------------
-- MyContainer specific
------------------------------------------
local cbNivaya = cargBags:GetImplementation("Nivaya")
local MyContainer = cbNivaya:GetContainerClass()

local function GetClassColor(class)
    if not RAID_CLASS_COLORS[class] then return {1, 1, 1} end
    local classColors = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class]
    return {classColors.r, classColors.g, classColors.b}
end

local GetNumFreeSlots = function(bagType)
    local free, max = 0, 0
    if bagType == "bag" then
        for i = 0,4 do
            free = free + GetContainerNumFreeSlots(i)
            max = max + GetContainerNumSlots(i)
        end
    elseif bagType == "bankReagent" then
        free = GetContainerNumFreeSlots(-3)
        max = GetContainerNumSlots(-3)
    else
        local containerIDs = {-1,5,6,7,8,9,10,11}
        for _,i in next, containerIDs do    
            free = free + GetContainerNumFreeSlots(i)
            max = max + GetContainerNumSlots(i)
        end
    end
    return free, max
end

local QuickSort;
do
    local func = function(v1, v2)
        if (v1 == nil) or (v2 == nil) then return (v1 and true or false) end
        if v1[1] == -1 or v2[1] == -1 then
            return v1[1] > v2[1] -- empty slots last
        elseif v1[2] ~= v2[2] then
            if v1[2] and v2[2] then
                return v1[2] > v2[2] -- higher quality first
            elseif (v1[2] == nil) or (v2[2] == nil) then
                return (v1[2] and true or false)
            else
                return false
            end
        elseif v1[1] ~= v2[1] then
            return v1[1] > v2[1] -- group identical item ids
        else
            return v1[4] > v2[4] -- full/larger stacks first
        end
    end;
    QuickSort = function(tbl) table.sort(tbl, func) end
end

function MyContainer:OnContentsChanged()

    local col, row = 0, 0
    local yPosOffs = self.Caption and 20 or 0
    local isEmpty = true

    local tName = self.name
    local tBankBags = string.find(tName, "cBniv_Bank%a+")
    local tBank = tBankBags or (tName == "cBniv_Bank")
    local tReagent = (tName == "cBniv_BankReagent")

    local buttonIDs = {}
    for i, button in pairs(self.buttons) do
        local item = cbNivaya:GetItemInfo(button.bagID, button.slotID)
        if item.link then
            buttonIDs[i] = { item.id, item.rarity, button, item.count }
        else
            buttonIDs[i] = { -1, -2, button, -1 }
        end
    end
    if ((tBank or tReagent) and cBnivCfg.SortBank) or (not (tBank or tReagent) and cBnivCfg.SortBags) then QuickSort(buttonIDs) end

    for _,v in ipairs(buttonIDs) do
        local button = v[3]
        button:ClearAllPoints()
      
        local xPos = col * (itemSlotSize + 2) + 2
        local yPos = (-1 * row * (itemSlotSize + 2)) - yPosOffs

        button:SetPoint("TOPLEFT", self, "TOPLEFT", xPos, yPos)
        if(col >= self.Columns-1) then
            col = 0
            row = row + 1
        else
            col = col + 1
        end
        isEmpty = false
    end

    if cBnivCfg.CompressEmpty then
        local xPos = col * (itemSlotSize + 2) + 2
        local yPos = (-1 * row * (itemSlotSize + 2)) - yPosOffs

        local tDrop = self.DropTarget
        if tDrop then
            tDrop:ClearAllPoints()
            tDrop:SetPoint("TOPLEFT", self, "TOPLEFT", xPos, yPos)
            if(col >= self.Columns-1) then
                col = 0
                row = row + 1
            else
                col = col + 1
            end
        end
        
        cB_Bags.main.EmptySlotCounter:SetText(GetNumFreeSlots("bag"))
        cB_Bags.bank.EmptySlotCounter:SetText(GetNumFreeSlots("bank"))
        cB_Bags.bankReagent.EmptySlotCounter:SetText(GetNumFreeSlots("bankReagent"))
    end
    
    -- This variable stores the size of the item button container
    self.ContainerHeight = (row + (col > 0 and 1 or 0)) * (itemSlotSize + 4)

    if (self.UpdateDimensions) then self:UpdateDimensions() end -- Update the bag's height
    local t = (tName == "cBniv_Bag") or (tName == "cBniv_Bank") or (tName == "cBniv_BankReagent")
    local tAS = (tName == "cBniv_Ammo") or (tName == "cBniv_Soulshards")
    if (not tBankBags and cB_Bags.main:IsShown() and not (t or tAS)) or (tBankBags and cB_Bags.bank:IsShown()) then 
        if isEmpty then self:Hide() else self:Show() end 
    end

    cB_BagHidden[tName] = (not t) and isEmpty or false
    cbNivaya:UpdateAnchors(self)
end

-- Restack Items
local restackItems = function(self)
    local tBag, tBank = (self.name == "cBniv_Bag"), (self.name == "cBniv_Bank")
    --local loc = tBank and "bank" or "bags"
    if tBank then
        SortBankBags()
        SortReagentBankBags()
    elseif tBag then
        SortBags()
    end
end

-- Reset New
local resetNewItems = function(self)
    cB_KnownItems = cB_KnownItems or {}
    for bag = 0, 4 do
        local tNumSlots = GetContainerNumSlots(bag)
        if tNumSlots > 0 then
            for slot = 1, tNumSlots do
                local item = cbNivaya:GetItemInfo(bag, slot)
                --print("resetNewItems", item.id)
                item.id = item.id or 0
                if cB_KnownItems[item.id] then
                    cB_KnownItems[item.id] = cB_KnownItems[item.id] + (item.stackCount and item.stackCount or 0)
                else
                    cB_KnownItems[item.id] = item.stackCount and item.stackCount or 0
                end
            end 
        end
    end
    cbNivaya:UpdateBags()
end
function cbNivResetNew()
    resetNewItems()
end

local UpdateDimensions = function(self)
    local height = 0            -- Normal margin space
    if self.BagBar and self.BagBar:IsShown() then
        height = height + 43    -- Bag button space
    end
    if self.Space then
        height = height + 16    -- additional info display space
    end
    if self.bagToggle then
        local tBag = (self.name == "cBniv_Bag")
        local fheight = ns.options.fonts.standard[2] + 4
        local extraHeight = (tBag and self.hintShown) and (fheight + 4) or 0
        height = height + 24 + extraHeight
    end
    if self.Caption then        -- Space for captions
        local fheight = ns.options.fonts.standard[2] + 12
        height = height + fheight
    end
    self:SetHeight(self.ContainerHeight + height)
end

local SetFrameMovable = function(f, v)
    f:SetMovable(true)
    f:SetUserPlaced(true)
    f:RegisterForClicks("LeftButton", "RightButton")
    if v then 
        f:SetScript("OnMouseDown", function() 
            f:ClearAllPoints() 
            f:StartMoving() 
        end)
        f:SetScript("OnMouseUp",  f.StopMovingOrSizing)
    else
        f:SetScript("OnMouseDown", nil)
        f:SetScript("OnMouseUp", nil)
    end
end

local classColor
local function IconButton_OnEnter(self)
    self.mouseover = true
    
    if not classColor then
        classColor = GetClassColor(select(2, UnitClass("player")))
    end
    self.icon:SetVertexColor(classColor[1], classColor[2], classColor[3])
    if self.tooltip then
        self.tooltip:Show()
        self.tooltipIcon:Show()
    end
end
    
local function IconButton_OnLeave(self)
    self.mouseover = false
            self.icon:SetVertexColor(0.8, 0.8, 0.8)

    if self.tooltip then
        self.tooltip:Hide()
        self.tooltipIcon:Hide()
    end
end

local createTextButton = function (name, parent, width, height)
    local button = CreateFrame("Button", nil, parent)
    button:SetNormalFontObject(GameFontHighlightSmall)
    button:SetText(name)
    
    button:SetWidth(width)
    button:SetHeight(height)
    
    button:SetScript("OnEnter", buttonEnter)
    button:SetScript("OnLeave", buttonLeave)
    

    button:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
    button:SetBackdrop({
        bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 16,
        insets = {left = 4, right = 4, top = 4, bottom = 4},
    })
    button:SetBackdropColor(.3, .3, .3, .9)
    button:SetBackdropBorderColor(.5, .5, .5, .7)
    return button
end


local GetFirstFreeSlot = function(bagtype)
    if bagtype == "bag" then
        for i = 0,4 do
            local t = GetContainerNumFreeSlots(i)
            if t > 0 then
                local tNumSlots = GetContainerNumSlots(i)
                for j = 1,tNumSlots do
                    local tLink = GetContainerItemLink(i,j)
                    if not tLink then return i,j end
                end
            end
        end
    elseif bagtype == "bankReagent" then
        local bagID = -3
        local t = GetContainerNumFreeSlots(bagID)
        if t > 0 then
            local tNumSlots = GetContainerNumSlots(bagID)
            for j = 1,tNumSlots do
                local tLink = GetContainerItemLink(bagID,j)
                if not tLink then return bagID,j end
            end
        end
    else
        local containerIDs = {-1,5,6,7,8,9,10,11}
        for _,i in next, containerIDs do
            local t = GetContainerNumFreeSlots(i)
            if t > 0 then
                local tNumSlots = GetContainerNumSlots(i)
                for j = 1,tNumSlots do
                    local tLink = GetContainerItemLink(i,j)
                    if not tLink then return i,j end
                end
            end
        end 
    end
    return false
end

function MyContainer:OnCreate(name, settings)
    --print("MyContainer:OnCreate", name)
    settings = settings or {}
    self.Settings = settings
    self.name = name

    local tBag, tBank, tReagent = (name == "cBniv_Bag"), (name == "cBniv_Bank"), (name == "cBniv_BankReagent")
    local tBankBags = string.find(name, "Bank")

    local numSlotsBag = {GetNumFreeSlots("bag")}
    local numSlotsBank = {GetNumFreeSlots("bank")}
    local numSlotsReagent = {GetNumFreeSlots("bankReagent")}
    
    local usedSlotsBag = numSlotsBag[2] - numSlotsBag[1]
    local usedSlotsBank = numSlotsBank[2] - numSlotsBank[1]
    local usedSlotsReagent = numSlotsReagent[2] - numSlotsReagent[1]

    self:EnableMouse(true)
    
    self.UpdateDimensions = UpdateDimensions
    
    self:SetFrameStrata("HIGH")
    tinsert(UISpecialFrames, self:GetName()) -- Close on "Esc"

    if (tBag or tBank) then 
        SetFrameMovable(self, cBnivCfg.Unlocked) 
    end

    if (tBank or tBankBags) then
        self.Columns = (usedSlotsBank > ns.options.sizes.bank.largeItemCount) and ns.options.sizes.bank.columnsLarge or ns.options.sizes.bank.columnsSmall
    elseif (tReagent) then
        self.Columns = (usedSlotsReagent > ns.options.sizes.bank.largeItemCount) and ns.options.sizes.bank.columnsLarge or ns.options.sizes.bank.columnsSmall
    else
        self.Columns = (usedSlotsBag > ns.options.sizes.bags.largeItemCount) and ns.options.sizes.bags.columnsLarge or ns.options.sizes.bags.columnsSmall
    end
    self.ContainerHeight = 0
    self:UpdateDimensions()
    self:SetWidth((itemSlotSize + 4) * self.Columns)

    -- The frame background
    local tBankCustom = (tBankBags and not cBnivCfg.BankBlack)
    local color_rb = ns.options.colors.background[1]
    local color_gb = tBankCustom and .4 or ns.options.colors.background[2]
    local color_bb = tBankCustom and .6 or ns.options.colors.background[3]
    local alpha_fb = ns.options.colors.background[4]

    -- The frame background
    local background = CreateFrame("Frame", nil, self)
    background:SetBackdrop{
        bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\AddOns\\cargBags_Nivaya\\media\\glowTex",
            tile = true, tileSize = 32, edgeSize = 6,
        insets = {left = 6, right = 6, top = 6, bottom = 6},
    }
    background:SetFrameStrata("HIGH")
    background:SetFrameLevel(1)
    background:SetBackdropColor(color_rb,color_gb,color_bb,alpha_fb)
    background:SetBackdropBorderColor(0, 0, 0, 1)

    background:SetPoint("TOPLEFT", -7, 7)
    background:SetPoint("BOTTOMRIGHT", 7, -7)

    -- Caption and close button
    local caption = background:CreateFontString(background, "OVERLAY", "GameFontNormal")
    if(caption) then
        local t = L.bagCaptions[self.name] or (tBankBags and strsub(self.name, 5))
        if not t then t = self.name end
        if self.Name == "cBniv_ItemSets" then t=ItemSetCaption..t end
        caption:SetText(t)
        caption:SetPoint("TOPLEFT", 8, -8)
        self.Caption = caption
        
        if (tBag or tBank) then
            local close = CreateFrame("Button", nil, self, "UIPanelCloseButton")
            close:SetPoint("TOPRIGHT", 8, 8)
            close:SetDisabledTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Disabled")
            close:SetNormalTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Up")
            close:SetPushedTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Down")
            close:SetHighlightTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Highlight", "ADD")
            close:SetScript("OnClick", function(self) if cbNivaya:AtBank() then CloseBankFrame() else CloseAllBags() end end)
        end
    end
    
    -- mover buttons
    if (settings.isCustomBag) then
        local moveLR = function(dir)
            local idx = -1
            for i,v in ipairs(cB_CustomBags) do if v.name == name then idx = i end end
            if (idx == -1) then return end

            local tcol = (cB_CustomBags[idx].col + ((dir == "left") and 1 or -1)) % 2
            cB_CustomBags[idx].col = tcol
            cbNivaya:CreateAnchors()
        end

        local moveUD = function(dir)
            local idx = -1
            for i,v in ipairs(cB_CustomBags) do if v.name == name then idx = i end end
            if (idx == -1) then return end

            local pos = idx
            local d = (dir == "up") and 1 or -1
            repeat 
                pos = pos + d
            until 
                (not cB_CustomBags[pos]) or (cB_CustomBags[pos].col == cB_CustomBags[idx].col)

            if (cB_CustomBags[pos] ~= nil) then
                local ele = cB_CustomBags[idx]
                cB_CustomBags[idx] = cB_CustomBags[pos]
                cB_CustomBags[pos] = ele
                cbNivaya:CreateAnchors()
            end
        end     
        
        local rightBtn = createTextButton(">", self, 20, 20)
        rightBtn:SetPoint("TOPRIGHT", self, "TOPRIGHT", -2, 2)
        rightBtn:SetScript("OnClick", function() moveLR("right") end)

        local leftBtn = createTextButton("<", self, 20, 20)
        leftBtn:SetPoint("TOPRIGHT", self, "TOPRIGHT", -22, 2)
        leftBtn:SetScript("OnClick", function() moveLR("left") end)

        local downBtn = createTextButton("v", self, 20, 20)
        downBtn:SetPoint("TOPRIGHT", self, "TOPRIGHT", -42, 2)
        downBtn:SetScript("OnClick", function() moveUD("down") end)

        local upBtn = createTextButton("^", self, 20, 20)
        upBtn:SetPoint("TOPRIGHT", self, "TOPRIGHT", -62, 2)
        upBtn:SetScript("OnClick", function() moveUD("up") end)

        self.rightBtn = rightBtn
        self.leftBtn = leftBtn
        self.downBtn = downBtn
        self.upBtn = upBtn
    end
        
    local tBtnOffs = 0
    if (tBag or tBank) then
        -- Bag bar for changing bags
        local bagType = tBag and "bags" or "bank"
        
        local tS = tBag and "backpack+bags" or "bank"
        local tI = tBag and 4 or 7
                
        local bagButtons = self:SpawnPlugin("BagBar", tS)
        bagButtons:SetSize(bagButtons:LayoutButtons("grid", tI))
        bagButtons.highlightFunction = function(button, match) button:SetAlpha(match and 1 or 0.1) end
        bagButtons:SetScale(0.85)
        bagButtons.isGlobal = true
        
        bagButtons:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -23, 27)
        bagButtons:Hide()

        -- main window gets a fake bag button for toggling key ring
        self.BagBar = bagButtons
        
        -- We don't need the bag bar every time, so let's create a toggle button for them to show
        self.bagToggle = createTextButton("Bags", self, 50, 24)
        self.bagToggle:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0)
        self.bagToggle:SetScript("OnClick", function()
            if(self.BagBar:IsShown()) then self.BagBar:Hide() else self.BagBar:Show() end
            self:UpdateDimensions()
        end)

        -- Button to reset new items:
        if tBag and cBnivCfg.NewItems then
            self.resetBtn = createTextButton("Renew", self, 70, 24)
        
            self.resetBtn:SetPoint("TOPRIGHT", self, "TOPRIGHT", -24 - tBtnOffs, 2)
            self.resetBtn:SetScript("OnClick", function() resetNewItems(self) end)
        end
        
        
        
        -- Button to send reagents to Reagent Bank:
        if tBank then
            local rbHint = REAGENTBANK_DEPOSIT
            self.reagentBtn = createTextButton("Reagents", self, 78, 24)
            self.reagentBtn:SetPoint("BOTTOMRIGHT", self.bagToggle, "BOTTOMLEFT", 0, 0)
            self.reagentBtn:SetScript("OnClick", function()
                --print("Deposit!!!")
                DepositReagentBank()
            end)
        end

        self.restackBtn = createTextButton("Restack", self, 70, 24)
        self.restackBtn:SetPoint("RIGHT", tBank and self.reagentBtn or self.bagToggle, "LEFT", -tBtnOffs, 0)
        self.restackBtn:SetScript("OnClick", function() restackItems(self) end)
    end

    -- Item drop target
    if (tBag or tBank or tReagent) then
        self.DropTarget = CreateFrame("Button", nil, self, "ItemButtonTemplate")
        
        self.DropTarget:SetWidth(itemSlotSize)
        self.DropTarget:SetHeight(itemSlotSize)
        
        local DropTargetProcessItem = function()
            -- if CursorHasItem() then  -- Commented out to fix Guild Bank -> Bags item dragging
                local bID, sID = GetFirstFreeSlot((tBag and "bag") or (tBank and "bank") or "bankReagent")
                if bID then PickupContainerItem(bID, sID) end
            -- end
        end
        self.DropTarget:SetScript("OnMouseUp", DropTargetProcessItem)
        self.DropTarget:SetScript("OnReceiveDrag", DropTargetProcessItem)
        
        local fs = self:CreateFontString(nil, "OVERLAY")
        fs:SetFont(unpack(ns.options.fonts.standard))
        fs:SetJustifyH("LEFT")
        fs:SetPoint("BOTTOMRIGHT", self.DropTarget, "BOTTOMRIGHT", -5, 3)
        self.EmptySlotCounter = fs
        
        if cBnivCfg.CompressEmpty then 
            self.DropTarget:Show()
            self.EmptySlotCounter:Show()
        else
            self.DropTarget:Hide()
            self.EmptySlotCounter:Hide()
        end
    end
    
    if tBag then
        local infoFrame = CreateFrame("Button", nil, self)
        infoFrame:SetPoint("BOTTOMLEFT", 5, -6)
        infoFrame:SetPoint("BOTTOMRIGHT", -86, -6)
        infoFrame:SetHeight(32)
        
        -- The money display
        local money = self:SpawnPlugin("TagDisplay", "[money]", self)
        money:SetPoint("BOTTOMLEFT", 2, 2)
    end
    
    self:SetScale(cBnivCfg.scale)
    return self
end

------------------------------------------
-- MyButton specific
------------------------------------------
local MyButton = cbNivaya:GetItemButtonClass()
MyButton:Scaffold("Default")

function MyButton:OnAdd()
    self:SetScript('OnMouseUp', function(self, mouseButton)
        if (mouseButton == 'RightButton') and (IsAltKeyDown()) and (IsControlKeyDown()) then
            local tID = GetContainerItemID(self.bagID, self.slotID)
            if tID then 
                cbNivCatDropDown.itemName = GetItemInfo(tID)
                cbNivCatDropDown.itemID = tID
                --ToggleDropDownMenu(1, nil, cbNivCatDropDown, self, 0, 0)
                cbNivCatDropDown:Toggle(self, nil, nil, 0, 0)
            end
        end
    end)
end

------------------------------------------
-- BagButton specific
------------------------------------------
local BagButton = cbNivaya:GetClass("BagButton", true, "BagButton")

function BagButton:OnCreate() self:GetCheckedTexture():SetVertexColor(1, 0.8, 0, 0.8) end
