-- BuyEmAll - By Cogwheel v1.12 - See readme.txt

--[[Hook BuyMerchantItem for debugging purposes 
function BuyMerchantItem(button, amount)
    if not amount then amount = 1 end
    print("Buying "..amount.." items.")
end --]]

-- Herb & Enchanting item lists courtesy of Periodic Table by Tekkub
BuyEmAll_SpecialItems = {
    Herb = "3358 8839 13466 4625 13467 3821 785 13465 13468 2450 2452 3818 3355 3357 8838 3369 3820 8153 8836 13463 8845 8846 13464 2447 2449 765 2453 3819 3356 8831",
    Enchant = "11083 16204 11137 11176 10940 11174 10938 11135 11175 16202 11134 16203 10998 11082 10939 11084 14343 11139 10978 11177 14344 11138 11178",
}




function BuyEmAllFrame_OnLoad()
    -- Set up confirmation dialog
	StaticPopupDialogs["BUYEMALL_CONFIRM"] = {
		text = BUYEMALL_CONFIRMATION,
		button1 = TEXT(YES),
		button2 = TEXT(NO),
		OnAccept = BuyEmAll_OnAccept,
		timeout = 0,
		hideOnEscape = true,
	}
    
    BuyEmAllStackButton.defaultText = BUYEMALL_STACK
    BuyEmAllMaxButton.defaultText = BUYEMALL_MAX
    

    -- Replace the SplitStack callback and  for each merchant item button
	for i=1,12 do
        local button=getglobal("MerchantItem"..i.."ItemButton")
		button.SplitStack = BuyEmAll_SplitStack
        button:SetScript("OnHide", function()
            if ( this.hasBuyEmAll == 1 ) then
				BuyEmAllFrame:Hide();
			end
        end)
	end
end




function BuyEmAllCostMoney_OnLoad()
    MoneyTypeInfo["BUYEMALL"] = {
        UpdateFunc = function() return this.staticMoney end,
        showSmallerCoins = "Backpack",
        fixedWidth = 1,
        collapse = 0,
        truncateSmallCoins = nil
    }
    this.small = 1
    this.staticMoney = 0
    MoneyFrame_SetType("BUYEMALL")
end




--[[ Since I have to control two different paths through this function, I just
     recreated it here to make life a bit easier. ]]
function MerchantItemButton_OnClick(button, ignoreModifiers)
	if ( MerchantFrame.selectedTab == 1 ) then
		-- Is merchant frame
		if ( button == "LeftButton" ) then
			if ( IsControlKeyDown() and not ignoreModifiers ) then
				DressUpItemLink(GetMerchantItemLink(this:GetID()));
			elseif ( IsShiftKeyDown() and not ignoreModifiers ) then
				if ( ChatFrameEditBox:IsVisible() ) then
					ChatFrameEditBox:Insert(GetMerchantItemLink(this:GetID()));
				else
                    BuyEmAll_ChooseAmount()
				end
			else
				PickupMerchantItem(this:GetID());
			end
		else
			if ( IsControlKeyDown() and not ignoreModifiers ) then
				return;
			elseif ( IsShiftKeyDown() and not ignoreModifiers ) then
                BuyEmAll_ChooseAmount()
			else
				BuyMerchantItem(this:GetID());
			end
		end
	else
		-- Is buyback item
		BuybackItem(this:GetID());
	end
end




-- Courtesy of wowwiki.com
function GetItemInfoFromItemLink(link)
    local itemId = nil;
    if ( type(link) == "string" ) then
        _,_, itemId = string.find(link, "item:(%d+):");
    end
    if ( itemId ) then
        return itemId, GetItemInfo(itemId);
    end
end




-- Figures out maximum purchase amount and shows the BuyEmAllFrame
function BuyEmAll_ChooseAmount()
    local name, _, price, quantity, numAvailable = GetMerchantItemInfo(this:GetID());
    this.presetStack = quantity
    this.price = price
    this.itemName = name
    this.itemID, _,_,_,_,_, this.itemSubType, this.stackSize = 
        GetItemInfoFromItemLink(GetMerchantItemLink(this:GetID()))
    
    local bagSpace, specialSpace = BuyEmAll_FreeSpace(name, itemID)
    local specialMax = floor(specialSpace / quantity) * quantity
    this.bagMax = floor(bagSpace / quantity) * quantity + specialMax
    this.moneyMax = floor(GetMoney() / price) * quantity
    this.available = numAvailable
    local maxPurchase = min(this.bagMax, this.moneyMax)
    if numAvailable ~= -1 then maxPurchase = min(maxPurchase, numAvailable * quantity) end
    this.defaultStack = specialMax > 0 and specialMax <= maxPurchase and specialMax or quantity
    
    if not name or maxPurchase == 0 then
        return
    elseif maxPurchase == 1 then
        MerchantItemButton_OnClick("LeftButton", 1)
        return
    end
    
    OpenBuyEmAllFrame(maxPurchase, "BOTTOMLEFT", "TOPLEFT")
end




--  Determines free bag space.
function BuyEmAll_FreeSpace(name, itemID)
    local returns = { freeSpace = 0, specialSpace = 0}
    
	for theBag = 0,4 do
        local which = "freeSpace"
        local doBag = true
        
        if theBag > 0 then
            local _,_,_,_,_,_,bagSubType =
                GetItemInfoFromItemLink(GetInventoryItemLink("player", theBag + 19)) -- Bag #1 is in inventory slot 20
            if bagSubType == "Ammo Pouch" and this.itemSubType == "Bullet" or
               bagSubType == "Quiver" and this.itemSubType == "Arrow" then
                which = "specialSpace"
            elseif bagSubType == "Ammo Pouch" and this.itemSubType ~= "Bullet" or
                   bagSubType == "Quiver" and this.itemSubType ~= "Arrow" or
                   bagSubType == "Herb Bag" and not BuyEmAll_IsSpecial("Herb") or
                   bagSubType == "Enchanting Bag" and not BuyEmAll_IsSpecial("Enchant") then
                doBag = false
            end
        end
            
		if doBag then
            local numSlot = GetContainerNumSlots(theBag);
            for theSlot = 1, numSlot do
                local itemLink = GetContainerItemLink(theBag, theSlot);
                if not itemLink then
                    returns[which] = returns[which] + this.stackSize;
                elseif string.find(itemLink, "%["..name.."%]") then
                    local _,itemCount = GetContainerItemInfo(theBag, theSlot)
                    returns[which] = returns[which] + this.stackSize - itemCount
                end
            end
        end
	end
    return returns.freeSpace, returns.specialSpace
end




-- Determine whether an item is an herb or enchanting material
function BuyEmAll_IsSpecial(which)
    for itemID in gfind(BuyEmAll_SpecialItems[which], "%d+") do
        if tonumber(this.itemID) == tonumber(itemID) then return true end
    end
    return false
end




function BuyEmAll_SplitStack(amount)
    local button = BuyEmAllFrame.owner
    if (amount > 0) then
        amount = ceil(amount/button.presetStack) * button.presetStack
        if amount > button.stackSize and amount > button.defaultStack then
            local dialog = StaticPopup_Show("BUYEMALL_CONFIRM", amount, button.itemName)
            dialog.data = amount
        elseif button.presetStack > 1 then
            BuyEmAll_OnAccept(amount)
        else
            BuyMerchantItem(button:GetID(), amount);
            BuyEmAllFrame:Hide()
        end
    end
end




function BuyEmAll_OnAccept(amount)
    BuyEmAllFrame:Hide()
    
    local button = BuyEmAllFrame.owner
    local numLoops, purchAmount, leftover
    
    if button.presetStack > 1 then
        numLoops = amount/button.presetStack
        purchAmount = 1
        leftover = 0
    else
        numLoops = floor(amount/button.stackSize)
        purchAmount = button.stackSize
        leftover = mod(amount, button.stackSize)
    end
    
    for i = 1, numLoops do
        BuyMerchantItem(button:GetID(), purchAmount)
    end
    
    if leftover > 0 then BuyMerchantItem(button:GetID(), leftover) end
end




local OldMerchantFrame_OnHide = MerchantFrame_OnHide
function MerchantFrame_OnHide(...)
    StaticPopup_Hide("BUYEMALL_CONFIRM")
    return OldMerchantFrame_OnHide(unpack(arg))
end





function BuyEmAll_UpdateCost(amount)
    local button = BuyEmAllFrame.owner
    local purchase = ceil((amount and amount or BuyEmAllFrame.split) / button.presetStack)
    local cost = purchase * button.price
    
    MoneyFrame_Update("BuyEmAllCostMoney", cost)
end




function BuyEmAllStack_Click()
    BuyEmAll_ConfirmPurchase(BuyEmAllFrame.owner.stackSize)
end




function BuyEmAllMax_Click()
    BuyEmAll_ConfirmPurchase(BuyEmAllFrame.maxStack)
end




function BuyEmAll_ConfirmPurchase(amount)
    local dialog = StaticPopup_Show("BUYEMALL_CONFIRM", amount, BuyEmAllFrame.owner.itemName)
    dialog.data = amount
end




function BuyEmAllStackButton_Enter()
    local amount = BuyEmAllFrame.owner.stackSize
    BuyEmAll_UpdateCost(amount)
    
    GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
    GameTooltip:SetText(BUYEMALL_STACK_SIZE.." - |cFFFFFFFF"..amount.."|r")
end




function BuyEmAllMaxButton_Enter()
    local amount = BuyEmAllFrame.maxStack
    BuyEmAll_UpdateCost(amount)
    
    GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
    GameTooltip:SetText(BUYEMALL_CAN_BUY.." - |cFFFFFFFF"..amount.."|r")
    GameTooltip:AddDoubleLine(BUYEMALL_CAN_FIT, BuyEmAllFrame.owner.bagMax,1,1,1,1,1,1)
    GameTooltip:AddDoubleLine(BUYEMALL_CAN_AFFORD, BuyEmAllFrame.owner.moneyMax,1,1,1,1,1,1)
    
    local available = BuyEmAllFrame.owner.available
    if available == -1 then
        available = "∞"
    end
    GameTooltip:AddDoubleLine(BUYEMALL_AVAILABLE, available,1,1,1,1,1,1)
    
    GameTooltip:Show()
end




function BuyEmAllMSButton_Leave()
    BuyEmAll_UpdateCost()
    GameTooltip:Hide()
end




--[[ Below is the modified code from the built-in StackSplitFrame ]]



function OpenBuyEmAllFrame(maxStack, anchor, anchorTo)
    if ( BuyEmAllFrame.owner ) then
		BuyEmAllFrame.owner.hasBuyEmAll = 0;
	end

	BuyEmAllFrame.maxStack = maxStack;
	if ( BuyEmAllFrame.maxStack < 2 ) then
		BuyEmAllFrame:Hide();
		return;
	end

	BuyEmAllFrame.owner = this;
	this.hasBuyEmAll = 1;
	BuyEmAllFrame.split = this.defaultStack;
	BuyEmAllFrame.typing = 0;
	BuyEmAllText:SetText(BuyEmAllFrame.split);
	BuyEmAllLeftButton:Disable();
	BuyEmAllRightButton:Enable();
 
    BuyEmAllStackButton:SetText(BuyEmAllStackButton.defaultText)
    BuyEmAllMaxButton:SetText(BuyEmAllMaxButton.defaultText)
    BuyEmAll_UpdateCost()
    
    BuyEmAllStackButton:Enable()
    if BuyEmAllFrame.maxStack < this.stackSize then
        BuyEmAllStackButton:Disable()
    end

	BuyEmAllFrame:ClearAllPoints();
	BuyEmAllFrame:SetPoint(anchor, this, anchorTo, 0, 0);
	BuyEmAllFrame:Show();
end




function BuyEmAllFrame_OnChar()
	if ( arg1 < "0" or arg1 > "9" ) then
		return;
	end

	if ( this.typing == 0 ) then
		this.typing = 1;
		this.split = 0;
	end

	local split = (this.split * 10) + arg1;
	if ( split == this.split ) then
		if( this.split == 0 ) then
			this.split = 1;
		end
        BuyEmAll_UpdateCost()
		return;
	end

	if ( split <= this.maxStack ) then
		this.split = split;
		BuyEmAllText:SetText(split);
		if ( split == this.maxStack ) then
			BuyEmAllRightButton:Disable();
		else
			BuyEmAllRightButton:Enable();
		end
		if ( split <= this.owner.presetStack ) then
			BuyEmAllLeftButton:Disable();
		else
			BuyEmAllLeftButton:Enable();
		end
	elseif ( split == 0 ) then
		this.split = 1;
	end
    BuyEmAll_UpdateCost()
end




function BuyEmAllFrame_OnKeyDown()
	if ( arg1 == "BACKSPACE" or arg1 == "DELETE" ) then
		if ( this.typing == 0 or this.split == 1 ) then
			return;
		end

		this.split = floor(this.split / 10);
		if ( this.split <= 1 ) then
			this.split = 1;
			this.typing = 0;
        end
        if ( this.split <= this.owner.presetStack ) then
			BuyEmAllLeftButton:Disable();
		else
			BuyEmAllLeftButton:Enable();
		end
		BuyEmAllText:SetText(this.split);
		if ( this.money == this.maxStack ) then
			BuyEmAllRightButton:Disable();
		else
			BuyEmAllRightButton:Enable();
		end
        BuyEmAll_UpdateCost()
	elseif ( arg1 == "ENTER" ) then
		BuyEmAllOkay_Click();
	elseif ( arg1 == "ESCAPE" ) then
		BuyEmAllCancel_Click();
	elseif ( arg1 == "LEFT" or arg1 == "DOWN" ) then
		BuyEmAllLeft_Click();
	elseif ( arg1 == "RIGHT" or arg1 == "UP" ) then
		BuyEmAllRight_Click();
	end
end




function BuyEmAllLeft_Click()
    local preset = BuyEmAllFrame.owner.presetStack
	if ( BuyEmAllFrame.split <= preset ) then
		return;
	end
    
    local decrease = mod(BuyEmAllFrame.split, preset)
    decrease = decrease == 0 and preset or decrease

	BuyEmAllFrame.split = BuyEmAllFrame.split - decrease

	BuyEmAllText:SetText(BuyEmAllFrame.split)
	if ( BuyEmAllFrame.split <= preset ) then
		BuyEmAllLeftButton:Disable()
	end
	BuyEmAllRightButton:Enable()
    BuyEmAll_UpdateCost()
end




function BuyEmAllRight_Click()
    local preset = BuyEmAllFrame.owner.presetStack
    local increase = preset - mod(BuyEmAllFrame.split, preset)

	if ( BuyEmAllFrame.split + increase > BuyEmAllFrame.maxStack ) then
		return;
	end
    
	BuyEmAllFrame.split = BuyEmAllFrame.split + increase;
	BuyEmAllText:SetText(BuyEmAllFrame.split);
	if ( BuyEmAllFrame.split == BuyEmAllFrame.maxStack ) then
		BuyEmAllRightButton:Disable();
	end
	BuyEmAllLeftButton:Enable();
    BuyEmAll_UpdateCost()
end




function BuyEmAllOkay_Click()
	if ( BuyEmAllFrame.owner ) then
		BuyEmAllFrame.owner.SplitStack(BuyEmAllFrame.split);
	end
end




function BuyEmAllCancel_Click()
	BuyEmAllFrame:Hide()
    StaticPopup_Hide("BUYEMALL_CONFIRM")
end




function BuyEmAllFrame_OnHide()
	if ( this.owner ) then
		BuyEmAllFrame.owner.hasBuyEmAll = 0;
	end
    StaticPopup_Hide("BUYEMALL_CONFIRM")
end
