
-- TODO: combine from inventory to bank
-- TODO: count main bank container too

TITAN_ITEMDED_ID = "ItemDed";

local ITEMDED_WARN_THRESHOLD = 4;	-- TOOD: make an option for this:
local ITEMDED_MAX_QUALITY=5	-- Max quality of item to display in menu. 5 = Epic.

-- Local variables
local TPID_isLoaded = false;
local TitanItemDed_ignored = {};
local TitanItemDed_droppable = {};
-- Better use at least one character that guaranteed not to appear in player name or realm name
local PlayerIdent = GetCVar("RealmName").."|"..UnitName("player");

-- Locale BEGIN
local TPID_MENU_TEXT = "Itemized Deductions"

local TPID_TOOLTIP_TITLE = "Itemized Deductions"
local TPID_TOOLTIP_BAGS = "\nOpen bags\tClick\n"
local TPID_TOOLTIP_DESTROY = "Destroy item\tShift-click\n"
local TPID_TOOLTIP_IGNORE = "Ignore item\tDoubleclick\nAlways ignore\tAlt-Doubleclick\n\n"
local TPID_TOOLTIP_SELL = "Sell item\tShift-click\n"
local TPID_TOOLTIP_NO_ITEM = "No item"
local TPID_TOOLTIP_TOTAL = "Total"

local TPID_MENU_SELL_ALL_JUNK = "Sell all junk"
local TPID_MENU_SELL_ALL_DROPPABLE = "Sell all listed items"
local TPID_MENU_SELL_ITEM = "Sell item"
local TPID_MENU_DROP_ITEM = "Drop item"
local TPID_MENU_ALWAYS_DROPPABLE_ITEM = "Item is always droppable/sellable"
local TPID_MENU_PRICE_AUCTIONEER_BUYOUT_ITEM = "Use auctioneer buyout price for item"
local TPID_MENU_IGNORE_ITEM = "Ignore for this session"
local TPID_MENU_ALWAYS_IGNORE_ITEM = "Ignore always"
local TPID_MENU_RESET_IGNORE_LIST = "Reset current ignore list"
local TPID_MENU_RESET_ALWAYS_IGNORE_LIST = "Reset always ignore list"
local TPID_MENU_THRESHOLD = "Threshold"
local TPID_MENU_IGNORE_CLASS = "Ignore item class"
local TPID_MENU_COMBINE_INCOMPLETE_STACKS = "Combine incomplete stacks"
local TPID_MENU_COMBINE_INCOMPLETE_STACKS_BANK = "Combine incomplete stacks in bank"
local TPID_MENU_SHOW_PANEL_PRICE = "Show item price in panel"

local TPID_GSC_SEPARATOR = "."
local TPID_GSC_NONE = "none"

local TPID_MENU_CHAT_FEEDBACK = "Chat feedback"
local TPID_CHATBACK_THRESHOLD_SET="Threshold set to %s."
local TPID_CHATBACK_ERROR_PARSE_ITEM="Error parsing item link or ID."
local TPID_CHATBACK_ITEM_IGNORED = "%s is now ignored."
local TPID_CHATBACK_NOTHING_TO_IGNORE = "Nothing to ignore!"
local TPID_CHATBACK_ITEM_NOW_ALWAYS_DROPPABLE = "%s is now always droppable/sellable."
local TPID_CHATBACK_ITEM_NO_LONGER_ALWAYS_DROPPABLE = "%s is no longer always droppable/sellable."
local TPID_CHATBACK_SET_PRICE_MODE_ITEM="Price mode for %s is set to %s."
local TPID_CHATBACK_ITEM_ALWAYS_IGNORED = "%s is now always ignored."
local TPID_CHATBACK_RESET_IGNORE_LIST = "Current ignored items list reset."
local TPID_CHATBACK_RESET_ALWAYS_IGNORE_LIST = "Always ignored items list reset."
local TPID_CHATBACK_ITEM1 = "item"
local TPID_CHATBACK_ITEMP = "items"
local TPID_CHATBACK_MOVED_ITEMS = "Moved %d %s."
local TPID_CHATBACK_SHOW_PANEL_PRICE_ON = "Item price display in panel turned on."
local TPID_CHATBACK_SHOW_PANEL_PRICE_OFF = "Item price display in panel turned off."
local TPID_CHATBACK_CLASS_NOW_IGNORED = "\"%s / %s\" items are now ignored."
local TPID_CHATBACK_CLASS_NO_LONGER_IGNORED = "\"%s / %s\" items are no longer ignored."

-- You can reverse parameters if your language needs this
-- Example:
-- local TPID_CHATBACK_ITEM_DELETED = "Deleting item with price %2$s named %1$s."
local TPID_CHATBACK_ITEM_DELETED = "Deleting %s worth %s."
local TPID_CHATBACK_NO_ITEM_TO_DESTROY = "No item to destroy."

local TPID_CUSTOM_PRICE_NA	= "N/A"
local TPID_CUSTOM_PRICE={
	auctioneer_buyout	= { short="buyout",	long="auctioneer buyout" },
	player_defined		= { short="player",	long="player defined"},
	-- used for "nil" custom price mode
	vendor			= { short="vendor",	long="vendor sell price (default, no custom price)"},
}
-- Locale END

-- local functions
local TitanItemDed_IsAlwaysDroppable
local TitanItemDed_IsDroppable

-- localize for speed
local ItemDataCache=ItemDataCache

function TitanItemDed_Chatback(str)
	if (TitanGetVar(TITAN_ITEMDED_ID, "ShowChatFeedback")) then
		DEFAULT_CHAT_FRAME:AddMessage("<ItemDed> "..str);
	end
end

local TPID_Color = {}
for idx = 0, ITEMDED_MAX_QUALITY-1 do
	local _, _, _, hex = GetItemQualityColor(idx)
	TPID_Color[idx+1]={hex, _G["ITEM_QUALITY"..idx.."_DESC"]}
end

function TitanItemDed_OnLoad()
	this.registry = {
		id = TITAN_ITEMDED_ID,
		menuText = TPID_MENU_TEXT,
		buttonTextFunction = "TitanPanelItemDedButton_GetButtonText",
		tooltipTitle = TPID_TOOLTIP_TITLE,
		tooltipTextFunction = "TitanPanelItemDedButton_GetTooltipText",
		icon = "",
		iconWidth = 16,
		category = "Information",
		savedVariables = {
			ShowIcon = 1,
			ShowLabelText = 1,
			ShowChatFeedback = 1
		}
	};

	this:RegisterEvent("VARIABLES_LOADED");
	this:RegisterEvent("BAG_UPDATE");
	this:RegisterEvent("PLAYER_ENTERING_WORLD")

	SlashCmdList["ITEMDED"] = TitanPanelItemDed_Slash
	SLASH_ITEMDED1 = "/itemded";
	SLASH_ITEMDED2 = "/tid";
end

function TitanPanelItemDed_Slash(command)
	local command1, command2, command3=strsplit(" ", command)
	if(command1=="alwaysdrop" or command1=="ad") then
		if(command2=="add") then TitanItemDed_SetAlwaysDroppable(command3, 1) end
		if(command2=="remove" or command2=="del") then TitanItemDed_SetAlwaysDroppable(command3, nil) end
	end
	TitanItemDed_UpdateList()
	TitanPanelItemDedButton_UpdateIcon();
end

local ignorableClasses={
	{0, 0},	-- Consumables
	{5, 0},	-- Reagent
	{6, 2}, -- Projectile/Arrow
	{6, 3}, -- Projectile/Bullet
	{7, 0}, -- Trade Goods
	{12, 0},-- Quest
}

function TitanItemDed_OnEvent(event, arg1)
	if (event == "VARIABLES_LOADED") then
		for idx, ids in ipairs(ignorableClasses) do
			-- TODO: check if true
			ItemDataCache.InitLocalClassName(ids[1], ids[2])
		end
		TitanItemDed_Init();
		TPID_isLoaded = true;
		TitanItemDed_UpdateList()
		TitanPanelItemDedButton_UpdateIcon();
	end
	if (event == "PLAYER_ENTERING_WORLD") then
		TitanItemDed_UpdateList()
		TitanPanelItemDedButton_UpdateIcon();
	end
	if (event == "BAG_UPDATE") then
		if(arg1 <= NUM_BAG_FRAMES) then		-- Ignore bank updates
			TitanItemDed_UpdateList()
			TitanPanelItemDedButton_UpdateIcon();
		end
	end
end

------------------------------------------------------------------------------
-- Bag Search functions
------------------------------------------------------------------------------

local function TitanItemDed_GetItemIdNameFromLink(linkOrId)
	if(not linkOrId) then return nil end
	local _, itemId, itemName
	if(type(linkOrId)=="number") then
		itemId=linkOrId
	else
		_, _, itemId = string.find(linkOrId, "item:(%d+):")
		if(not itemId) then return nil end
		itemId=tonumber(itemId)
	end
	itemName=GetItemInfo(itemId)
	if(not itemName) then return nil end

	return itemId, itemName
end

local function TitanItemDed_GetItemName(bag, slot)
	local link = GetContainerItemLink(bag, slot)
	if(link) then
		local itemName = GetItemInfo(link)
		return itemName
	end
	return nil
end

local function TitanItemDed_GetItemId(bag, slot)
	local itemId=TitanItemDed_GetItemIdNameFromLink(GetContainerItemLink(bag, slot))
	return itemId
end

local function TitanItemDed_GetQuality(bag, slot)
	local _, _, _, quality = GetContainerItemInfo(bag, slot)
	if(not quality) then return nil end
	if(quality == -1) then
		local link = GetContainerItemLink(bag, slot)
		if (link) then
			_, _, quality = GetItemInfo(link)
			return quality+1	-- TitanItemDed indexes go from 1 (Lua convention) instead of Blizzard's 0 (C convention)
		end
		return nil
	else
		return quality+1
	end
end

-- 3-element sized tables for reuse
-- get for unordered list:
-- local newtable if(ftnum==0) then newtable={} else newtable=ftstorage[ftnum] ftnum=ftnum-1 end
-- get for ordered list with removable tail:
-- if(not newtable) then if(ftnum==0) then newtable={} else newtable=ftstorage[ftnum] ftnum=ftnum-1 end end
-- free:
-- ftnum=ftnum+1 ftstorage[ftnum]=newtable newtable=nil
local ftstorage={}
local ftnum=0

local TitanItemDed_ItemList={ }
local TitanItemDed_ItemListSize=0
local totalPrice
local titanPanelOutdatedTooltip=false
local first, firstID
-- no need to track icon - it should be updated always
-- local debugUpdateNumber=1

local function TitanPanelItemDedButton_SortByPrice(a, b)
	return a[3]<b[3]
end

function TitanItemDed_UpdateList()
	-- TitanItemDed_Chatback("Scan no. "..debugUpdateNumber..".") debugUpdateNumber=debugUpdateNumber+1
	local TitanItemDed_ItemListIdx = 0;
	totalPrice=0
	titanPanelOutdatedTooltip=true

	for bag = 0, NUM_BAG_FRAMES do
		for slot=1,GetContainerNumSlots(bag) do
			local price = nil;
			local itemID = TitanItemDed_GetItemId(bag, slot);
			local _, stackCount = GetContainerItemInfo(bag, slot);

			if (itemID and stackCount) then
				if(TitanItemDed_CustomPriceMode(itemID)) then
					price = TitanItemDed_GetCustomPrice(GetContainerItemLink(bag, slot))
				end
				-- fallback to vendor price if no custom price data is available
				if(not price) then price = TitanItemDed_GetVendorPrice(itemID) end

				if (price) then
					price = price * stackCount
					-- CHECK: ID more efficient?
					-- UPDATE: we can't use ID, since we need to check locked status
					if TitanItemDed_IsDroppable(bag, slot) then
						totalPrice=totalPrice+price
						TitanItemDed_ItemListIdx=TitanItemDed_ItemListIdx+1
						-- get
						if(not TitanItemDed_ItemList[TitanItemDed_ItemListIdx]) then if(ftnum==0) then TitanItemDed_ItemList[TitanItemDed_ItemListIdx]={} else TitanItemDed_ItemList[TitanItemDed_ItemListIdx]=ftstorage[ftnum] ftnum=ftnum-1 end end
						TitanItemDed_ItemList[TitanItemDed_ItemListIdx][1] = bag
						TitanItemDed_ItemList[TitanItemDed_ItemListIdx][2] = slot
						TitanItemDed_ItemList[TitanItemDed_ItemListIdx][3] = price
					end
				end
			end
		end
	end

	-- cut list tail
	if(TitanItemDed_ItemListSize > TitanItemDed_ItemListIdx) then for idx=TitanItemDed_ItemListIdx+1, TitanItemDed_ItemListSize do
		-- free
		ftnum=ftnum+1 ftstorage[ftnum]=TitanItemDed_ItemList[idx] TitanItemDed_ItemList[idx]=nil
	end end
	TitanItemDed_ItemListSize=TitanItemDed_ItemListIdx

	sort(TitanItemDed_ItemList, TitanPanelItemDedButton_SortByPrice);
	first=TitanItemDed_ItemList[1]
	firstID=nil
end

function TitanPanelItemDedButton_UpdateIcon()
	-- TitanItemDed_Chatback("Regenerating button icon.")
	local button = TitanUtils_GetButton(TITAN_ITEMDED_ID, true);

	if (first) then
		local texture=GetContainerItemInfo(first[1], first[2])
		button.registry.icon = texture
	else
		button.registry.icon = "";
	end
	TitanPanelButton_UpdateButton(TITAN_ITEMDED_ID);
end

-- itemcolor, itemname, stackCount, emptyColor, emptyNum
local TITAN_BUTTONTEXT_HAVEITEM_FORMAT="%s[%s]"..FONT_COLOR_CODE_CLOSE.." x%d %s(%d)"..FONT_COLOR_CODE_CLOSE
-- itemcolor, itemname, stackCount, GSCPrice, emptyColor, emptyNum
local TITAN_BUTTONTEXT_HAVEITEM_WITH_PRICE_FORMAT="%s[%s]"..FONT_COLOR_CODE_CLOSE.." x%d = %s %s(%d)"..FONT_COLOR_CODE_CLOSE
-- emptyColor, emptyNum
local TITAN_BUTTONTEXT_NOITEM_FORMAT=TPID_TOOLTIP_NO_ITEM.." %s(%d)"..FONT_COLOR_CODE_CLOSE
function TitanPanelItemDedButton_GetButtonText(id)
	-- TitanItemDed_Chatback("Regenerating button text.")
	local emptyNum = TitanItemDed_GetEmpties();
	-- Those are actually Titan specific
	local emptyColor = ((emptyNum < ITEMDED_WARN_THRESHOLD) and RED_FONT_COLOR_CODE) or NORMAL_FONT_COLOR_CODE

	if (first) then
		local _, stackCount = GetContainerItemInfo(first[1], first[2])
		if(TitanItemDedSettings[PlayerIdent].ShowPanelPrice) then
			return format(TITAN_BUTTONTEXT_HAVEITEM_WITH_PRICE_FORMAT,
				TPID_Color[TitanItemDed_GetQuality(first[1], first[2])][1],
				TitanItemDed_GetItemName(first[1], first[2]),
				stackCount,
				TitanItemDed_GetTextGSC(first[3]),
				emptyColor,
				emptyNum)
			-- format end
		else
			return format(TITAN_BUTTONTEXT_HAVEITEM_FORMAT,
				TPID_Color[TitanItemDed_GetQuality(first[1], first[2])][1],
				TitanItemDed_GetItemName(first[1], first[2]),
				stackCount,
				emptyColor,
				emptyNum)
			-- format end
		end
	else
		return format(TITAN_BUTTONTEXT_NOITEM_FORMAT, emptyColor, emptyNum)
	end
end

local TITAN_TOOLTIPTEXT_HEADER_DESTROY=TPID_TOOLTIP_BAGS..TPID_TOOLTIP_DESTROY..TPID_TOOLTIP_IGNORE
local TITAN_TOOLTIPTEXT_HEADER_SELL=TPID_TOOLTIP_BAGS..TPID_TOOLTIP_SELL..TPID_TOOLTIP_IGNORE
local TITAN_TOOLTIPTEXT_HEADER_NOITEM=TPID_TOOLTIP_BAGS..TPID_CHATBACK_NO_ITEM_TO_DESTROY
-- priceMode, itemcolor, itemname, stackCount, GSCPrice
local TITAN_TOOLTIPTEXT_ITEMENTRY_FORMAT="%s%s[%s]"..FONT_COLOR_CODE_CLOSE.." x%d\t%s\n"
local titanTooltipText
local function TitanPanelItemDedButton_RegenerateTooltipText()
	-- TitanItemDed_Chatback("Regenerating tooltip.")
	if(not first) then titanTooltipText=TITAN_TOOLTIPTEXT_HEADER_NOITEM return end
	-- TODO: benchmark what's better - table generation or growing string (I suspect former is better)
	local items=""

	for idx, entry in ipairs(TitanItemDed_ItemList) do
		local itemLink = GetContainerItemLink(entry[1], entry[2])
		local itemID, itemName = TitanItemDed_GetItemIdNameFromLink(itemLink)
		local customPriceMode = TitanItemDed_CustomPriceMode(itemID)
		local customPrice, customPriceTag
		if(customPriceMode) then
			-- TitanItemDed_Chatback(customPriceTag.." "..tostring(customPrice))
			customPrice=TitanItemDed_GetCustomPrice(itemLink)
			customPriceTag="("..(customPrice and "" or (TPID_CUSTOM_PRICE_NA.." "))..TPID_CUSTOM_PRICE[customPriceMode].short..") "
		end
		local _, stackCount = GetContainerItemInfo(entry[1], entry[2])
		items = items..format(TITAN_TOOLTIPTEXT_ITEMENTRY_FORMAT,
			(customPriceTag or ""),
			TPID_Color[TitanItemDed_GetQuality(entry[1], entry[2])][1],
			itemName,
			stackCount,
			TitanItemDed_GetTextGSC(customPrice or entry[3]))
		-- format end
	end
	titanTooltipText=(MerchantFrame:IsVisible() and TITAN_TOOLTIPTEXT_HEADER_SELL or TITAN_TOOLTIPTEXT_HEADER_DESTROY)..items.."\n"..TPID_TOOLTIP_TOTAL..":\t"..TitanItemDed_GetTextGSC(totalPrice)
end

local titanPanelPrevMerchantTootltip=false
function TitanPanelItemDedButton_GetTooltipText()
	if(MerchantFrame:IsVisible() ~= titanPanelPrevMerchantTootltip) then titanPanelOutdatedTooltip=true end
	titanPanelPrevMerchantTootltip=MerchantFrame:IsVisible()
	if(titanPanelOutdatedTooltip) then TitanPanelItemDedButton_RegenerateTooltipText() titanPanelOutdatedTooltip=false end
	return titanTooltipText
end

local function TitanItemDed_InitSettingsVar(var, value)
	if(TitanItemDedSettings[PlayerIdent][var] == nil) then TitanItemDedSettings[PlayerIdent][var] = value end
end

local TitanItemDed_InitSubMenu	-- prototype

function TitanItemDed_Init()
	-- Hook in ItemDataCache updates
	local oldItemDataCacheOnUpdateByID_selltovendor=ItemDataCache.OnUpdate.ByID_selltovendor
	ItemDataCache.OnUpdate.ByID_selltovendor=function() TitanItemDed_UpdateList() TitanPanelItemDedButton_UpdateIcon() return oldItemDataCacheOnUpdateByID_selltovendor() end

	if (TitanItemDedSettings == nil) then TitanItemDedSettings = {}	end
	if (TitanItemDedSettings[PlayerIdent] == nil) then TitanItemDedSettings[PlayerIdent] = {} end
	TitanItemDed_InitSettingsVar("Ignored", {})
	TitanItemDed_InitSettingsVar("IgnoredClass", {})
	TitanItemDed_InitSettingsVar("Droppable", {})
	TitanItemDed_InitSettingsVar("CustomPrice", {})
	TitanItemDed_InitSettingsVar("Threshold", 1)

	TitanItemDed_InitSubMenu()

	TitanItemDed_UpdateList()
	TitanPanelItemDedButton_UpdateIcon();

	return;
end

function TitanItemDed_Listman(cmd)
	local act = cmd or this.value

	-- IDless/linkless commands
	if (act == "r") then
		TitanItemDed_ignored = {};
		TitanItemDed_Chatback(TPID_CHATBACK_RESET_IGNORE_LIST);
	elseif (act == "ra") then
		TitanItemDed_ignored = {};
		TitanItemDedSettings[PlayerIdent]["Ignored"] = {};
		TitanItemDed_Chatback(TPID_CHATBACK_RESET_ALWAYS_IGNORE_LIST);
	end

	if(first and not firstID) then firstID = TitanItemDed_GetItemId(first[1], first[2]) end
	local firstLink=GetContainerItemLink(first[1], first[2])

	if (act == "t") then
		if first then
			if (MerchantFrame:IsVisible()) then
				UseContainerItem(first[1], first[2]);
			else
				local _, firstStack=GetContainerItemInfo(first[1], first[2])
				if(firstStack>1) then firstLink=firstLink.." x"..firstStack end
				TitanItemDed_Chatback(format(TPID_CHATBACK_ITEM_DELETED, firstLink, TitanItemDed_GetTextGSC(first[3])));
				PickupContainerItem(first[1], first[2])
				DeleteCursorItem();
			end
		else
			TitanItemDed_Chatback(TPID_CHATBACK_NO_ITEM_TO_DESTROY);
		end
	elseif (act == "i") then
		if first then
			TitanItemDed_ignored[firstID] = 1
			TitanItemDed_Chatback(format(TPID_CHATBACK_ITEM_IGNORED, firstLink));
		else TitanItemDed_Chatback(TPID_CHATBACK_NOTHING_TO_IGNORE); end
	elseif (act == "ia") then
		if first then
			TitanItemDedSettings[PlayerIdent]["Ignored"][firstID] = 1
			TitanItemDed_Chatback(format(TPID_CHATBACK_ITEM_ALWAYS_IGNORED, firstLink));
		else TitanItemDed_Chatback(TPID_CHATBACK_NOTHING_TO_IGNORE); end
	elseif (act == "tad") then
		-- no item check. This only should be called from menu when item is present.
		-- no simple toggle. We need "nil" to actually clear and remove table entry from saved vars.
		if(TitanItemDed_IsAlwaysDroppable(firstID)) then
			TitanItemDed_SetAlwaysDroppable(firstID, nil)
		else
			TitanItemDed_SetAlwaysDroppable(firstID, 1)
		end
	elseif (act == "auctioneer_buyout") then
		-- no item check. This only should be called from menu when item is present.
		-- With third argument set to true function works as toggle.
		-- If you set custom price to same mode again it clears it.
		TitanItemDed_SetCustomPriceMode(firstLink, "auctioneer_buyout", true)
	end

	TitanItemDed_UpdateList()
	TitanPanelItemDedButton_UpdateIcon();
end

-- Cache once generated buttons
local itemDedDropDownMenuButtons={}
function TPID_MenuButton(button, ...)
	local newButton
	if(itemDedDropDownMenuButtons[button]) then newButton=itemDedDropDownMenuButtons[button]
	else
		if(button==TPID_MENU_SELL_ALL_JUNK) then newButton={
			func = TitanItemDed_SellAll,
			arg1 = TitanItemDed_SellCheckJunk,
		} elseif(button==TPID_MENU_SELL_ALL_DROPPABLE) then newButton={
			func = TitanItemDed_SellAll,
			arg1 = TitanItemDed_SellCheckDroppableStandard,
		} elseif(button==TPID_MENU_SELL_ITEM) then newButton={
			func = TitanItemDed_Listman,
			value = "t",
		} elseif(button==TPID_MENU_DROP_ITEM) then newButton={
			func = TitanItemDed_Listman,
			value = "t",
		} elseif(button==TPID_MENU_IGNORE_ITEM) then newButton={
			func = TitanItemDed_Listman,
			value = "i",
		} elseif(button==TPID_MENU_ALWAYS_IGNORE_ITEM) then newButton={
			func = TitanItemDed_Listman,
			value = "ia",
		} elseif(button==TPID_MENU_ALWAYS_DROPPABLE_ITEM) then newButton={
			func = TitanItemDed_Listman,
			value = "tad",
		} elseif(button==TPID_MENU_PRICE_AUCTIONEER_BUYOUT_ITEM) then newButton={
			func	= TitanItemDed_Listman,
			value	= "auctioneer_buyout",
		} elseif(button==TPID_MENU_COMBINE_INCOMPLETE_STACKS) then newButton={
			func	= TitanItemDed_CombineAll,
			arg1 	= false,
		} elseif(button==TPID_MENU_COMBINE_INCOMPLETE_STACKS_BANK) then newButton={
			func	= function () TitanItemDed_CombineAll(false, NUM_BAG_SLOTS+1, NUM_BAG_SLOTS+NUM_BANKBAGSLOTS+1) end,
		} elseif(button==TPID_MENU_RESET_IGNORE_LIST) then newButton={
			func = TitanItemDed_Listman,
			value = "r",
		} elseif(button==TPID_MENU_RESET_ALWAYS_IGNORE_LIST) then newButton={
			func = TitanItemDed_Listman,
			value = "ra",
		} elseif(button==TPID_MENU_THRESHOLD) then newButton={
			value = button,
			hasArrow = 1,
		} elseif(button==TPID_MENU_IGNORE_CLASS) then newButton={
			value = button,
			hasArrow = 1,
		} elseif(button==TPID_MENU_SHOW_PANEL_PRICE) then newButton={
			func = TitanItemDed_TogglePanelPrice,
			keepShownOnClick = 1,
		} elseif(button==TPID_MENU_CHAT_FEEDBACK) then newButton={
			func = TitanToggleVar,
			arg1 = TITAN_ITEMDED_ID,
			arg2 = "ShowChatFeedback",
			keepShownOnClick = 1,
		} end
		if(not newButton) then return nil end
		newButton.text=button
	end
	local attribute, value=...
	if(attribute) then newButton[attribute]=value end
	itemDedDropDownMenuButtons[button]=newButton
	return newButton
end

local thresholdLevelButton={}
local ignorableClassButton={}
function TitanItemDed_InitSubMenu()
	for i=1,ITEMDED_MAX_QUALITY do thresholdLevelButton[i]={
		text = TPID_Color[i][1]..TPID_Color[i][2],
		value = i,
		func = TitanItemDed_SetThreshold,
	} end
	for idx, ids in ipairs(ignorableClasses) do
		local className, subClassName=ItemDataCache.GetClassSubclassName(ids[1], ids[2])
		if(className and subClassName) then table.insert(ignorableClassButton, {
			text = className.." / "..subClassName,
			func = TitanItemDed_ToggleIgnoreItemClass,
			arg1 = ids[1],
			arg2 = ids[2],
		}) end
	end
end

function TitanPanelRightClickMenu_PrepareItemDedMenu()
	if (not TPID_isLoaded) then return; end

	if (UIDROPDOWNMENU_MENU_LEVEL == 2) then
		local button
		if(UIDROPDOWNMENU_MENU_VALUE==TPID_MENU_THRESHOLD) then
			for i=1,ITEMDED_MAX_QUALITY do
				button = thresholdLevelButton[i]
				button.checked = (TitanItemDedSettings[PlayerIdent].Threshold == i)
				UIDropDownMenu_AddButton(button, UIDROPDOWNMENU_MENU_LEVEL)
			end
		elseif(UIDROPDOWNMENU_MENU_VALUE==TPID_MENU_IGNORE_CLASS) then
			for idx, ids in ipairs(ignorableClasses) do
				button = ignorableClassButton[idx]
				if(button) then
					button.checked = (TitanItemDedSettings[PlayerIdent].IgnoredClass[ids[1]] and TitanItemDedSettings[PlayerIdent].IgnoredClass[ids[1]][ids[2]])
					UIDropDownMenu_AddButton(button, UIDROPDOWNMENU_MENU_LEVEL)
				end
			end
		end
		return
	end

	TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_ITEMDED_ID].menuText);
	TitanPanelRightClickMenu_AddSpacer();

	-- Only show those if we have an item
	if(TitanItemDed_ItemList[1]) then
		if (MerchantFrame:IsVisible()) then
			UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_SELL_ALL_JUNK))
			UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_SELL_ALL_DROPPABLE))
		end

		UIDropDownMenu_AddButton(TPID_MenuButton(MerchantFrame:IsVisible() and TPID_MENU_SELL_ITEM or TPID_MENU_DROP_ITEM))
		TitanPanelRightClickMenu_AddSpacer();

		UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_IGNORE_ITEM))
		UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_ALWAYS_IGNORE_ITEM))
		TitanPanelRightClickMenu_AddSpacer()

		if(not firstID) then firstID = TitanItemDed_GetItemId(first[1], first[2]) end

		UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_ALWAYS_DROPPABLE_ITEM, "checked", TitanItemDed_IsAlwaysDroppable(firstID)))
		UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_PRICE_AUCTIONEER_BUYOUT_ITEM, "checked", (TitanItemDed_CustomPriceMode(firstID)=="auctioneer_buyout")))
		TitanPanelRightClickMenu_AddSpacer();
	end

	local combineSection=false

	if(TitanItemDed_CombineAll(true)) then
		UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_COMBINE_INCOMPLETE_STACKS))
		combineSection=true
	end
	if(TitanItemDed_CombineAll(true, NUM_BAG_SLOTS+1, NUM_BAG_SLOTS+NUM_BANKBAGSLOTS+1)) then
		UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_COMBINE_INCOMPLETE_STACKS_BANK))
		combineSection=true

	end
	if(combineSection) then TitanPanelRightClickMenu_AddSpacer() end

	UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_RESET_IGNORE_LIST))
	UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_RESET_ALWAYS_IGNORE_LIST))
	TitanPanelRightClickMenu_AddSpacer();

	UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_THRESHOLD))
	UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_IGNORE_CLASS))
	TitanPanelRightClickMenu_AddSpacer();

	UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_SHOW_PANEL_PRICE, "checked", TitanItemDedSettings[PlayerIdent].ShowPanelPrice))
	UIDropDownMenu_AddButton(TPID_MenuButton(TPID_MENU_CHAT_FEEDBACK, "checked", TitanGetVar(TITAN_ITEMDED_ID, "ShowChatFeedback")))
	TitanPanelRightClickMenu_AddToggleIcon(TITAN_ITEMDED_ID);
	TitanPanelRightClickMenu_AddSpacer();

	TitanPanelRightClickMenu_AddCommand(TITAN_PANEL_MENU_HIDE, TITAN_ITEMDED_ID, TITAN_PANEL_MENU_FUNC_HIDE);
end

function TitanItemDed_TogglePanelPrice()
	TitanItemDedSettings[PlayerIdent].ShowPanelPrice=(not TitanItemDedSettings[PlayerIdent].ShowPanelPrice) and true or nil
	TitanItemDed_Chatback(TitanItemDedSettings[PlayerIdent].ShowPanelPrice and TPID_CHATBACK_SHOW_PANEL_PRICE_ON or TPID_CHATBACK_SHOW_PANEL_PRICE_OFF)
	TitanPanelItemDedButton_UpdateIcon()
end

function TitanItemDed_OnClick(button)
	if (button == "LeftButton") then
		if(IsShiftKeyDown()) then
			TitanItemDed_Listman("t");
		else
			OpenAllBags();
		end
	end
end

function TitanItemDed_OnDoubleClick(button)
	if (button == "LeftButton") then
		if(IsAltKeyDown()) then
			TitanItemDed_Listman("ia");
		else
			TitanItemDed_Listman("i");
		end
	end
end

function TitanItemDed_SetThreshold()
	TitanItemDedSettings[PlayerIdent].Threshold = this.value;
	TitanItemDed_Chatback(format(TPID_CHATBACK_THRESHOLD_SET, TPID_Color[this.value][1]..TPID_Color[this.value][2].."|r"));
	TitanItemDed_UpdateList()
	TitanPanelItemDedButton_UpdateIcon()
	HideDropDownMenu(UIDROPDOWNMENU_MENU_LEVEL-1)
end

-- Cache for speed
local ItemDataCacheGetByID_selltovendor=ItemDataCache.Get.ByID_selltovendor
function TitanItemDed_GetVendorPrice(itemId)
--	if(ItemDataCache and and ItemDataCache.Get and ItemDataCache.Get.ByID_selltovendor) then
	-- This is required dependency, so we can no longer test if it is available
	local price = ItemDataCacheGetByID_selltovendor(itemId)
	if(price) then return price end
--	end

	if(Informant and Informant.GetItem) then
		local itemData = Informant.GetItem(itemId)
		if(itemData) then price = itemData.sell or itemData.itemSell end
		if(price) then return price end
	end

	price=TitanItemDed_items[itemId]
	if(price) then return price end

	local itemName=GetItemInfo(itemId)
	if (itemName and TitanItemDed_items[itemName]) then
		return TitanItemDed_items[itemName];
	end
	return nil
end

function TitanItemDed_AuctioneerFound()
	if (Auctioneer and Auctioneer.Util and Auctioneer.Util.GetAuctionKey and
	    Auctioneer.ItemDB and Auctioneer.ItemDB.CreateItemKeyFromLink and
	    Auctioneer.HistoryDB and Auctioneer.HistoryDB.GetItemTotals) then
		-- AFAIR it is not possible to unload those, so cache the result
		TitanItemDed_AuctioneerFound=function() return true end
		return true
	end
	-- auctioneer not loaded/not found
	return false
end

function TitanItemDed_GetAuctioneerPrice(itemLink, ...)
	if(not TitanItemDed_AuctioneerFound()) then return false end

	local mode=... or "buyout"
	local ahKey = Auctioneer.Util.GetAuctionKey();
	local itemKey = Auctioneer.ItemDB.CreateItemKeyFromLink(itemLink);
	local itemTotals = Auctioneer.HistoryDB.GetItemTotals(itemKey, ahKey);
	if (itemTotals == nil or itemTotals.seenCount == 0) then
		-- never seen at auction
		return nil
	end

	local bidPrice, buyPrice, marketPrice, warn = Auctioneer.Statistic.GetSuggestedResale(itemKey, ahKey, 1)
	if(mode=="buyout") then return buyPrice end
	return nil
end

------------------------------------------------------------------------------
-- Mass selling
------------------------------------------------------------------------------

function TitanItemDed_SellCheckJunk(bag, slot)
	local qual = TitanItemDed_GetQuality(bag, slot);
	return (qual and qual == 1)
end

function TitanItemDed_SellCheckDroppableStandard(bag, slot)
	return (TitanItemDed_IsDroppable(bag, slot) and (not TitanItemDed_CustomPriceMode(TitanItemDed_GetItemId(bag, slot))))
end

function TitanItemDed_SellAll(checkFunction)
	for bag=0,NUM_BAG_FRAMES do
		for slot=1,GetContainerNumSlots(bag) do
			if (checkFunction(bag, slot)) then
				if (MerchantFrame:IsVisible()) then
					UseContainerItem(bag, slot);
				else
					return nil
				end
			end
		end
	end
	TitanItemDed_UpdateList()
	TitanPanelItemDedButton_UpdateIcon()
end

local foundIncomplete={}
local rememberStackCount={}
-- /script TitanItemDed_CombineAll(false)
-- /script TitanItemDed_CombineAll(false, NUM_BAG_SLOTS+1, NUM_BAG_SLOTS+NUM_BANKBAGSLOTS)
function TitanItemDed_CombineAll(checkOnly, firstBag, lastBag)
	if(not firstBag) then firstBag, lastBag = 0, NUM_BAG_FRAMES end
	local moved, left = 0, 0
	-- wipe tables
	-- the only place where memory savings COULD decrease speed slightly
	for idx, val in pairs(foundIncomplete) do
		for idx2, val2 in pairs(val) do
			ftnum=ftnum+1 ftstorage[ftnum]=val2
			val[idx2]=nil
		end
		ftnum=ftnum+1 ftstorage[ftnum]=val
		foundIncomplete[idx]=nil
	end
	for idx, val in pairs(rememberStackCount) do
		rememberStackCount[idx]=nil
	end
	-- TitanItemDed_Chatback("Size1 "..#foundIncomplete)
	-- TitanItemDed_Chatback("Size2 "..#rememberStackCount)
	-- scan in reverse direction to make incomplete stacks stay first, so
	-- they will be either used up or at least won't make CombineAll think
	-- that it is time to CombineAll again, because first use of item would
	-- take it from full stack
	for bag = lastBag, firstBag, -1 do
		-- Also check BANK_CONTAINER that "conviently" located before all container bags
		local realbag
		if(bag == NUM_BAG_SLOTS+NUM_BANKBAGSLOTS+1) then realbag=BANK_CONTAINER else realbag=bag end
		-- TitanItemDed_Chatback("Bag: "..realbag)
		for slot=GetContainerNumSlots(realbag),1,-1 do
			local _, itemCount, locked
			_, itemCount, locked = GetContainerItemInfo(realbag, slot)
			if(itemCount and not locked) then
				local itemStackCount
				local itemID=TitanItemDed_GetItemId(realbag, slot)
				_, _, _, _, _, _, _, itemStackCount=GetItemInfo(itemID)
				if(itemStackCount > 1 and itemCount ~= itemStackCount) then
					if(not foundIncomplete[itemID]) then foundIncomplete[itemID]={} end
					if(#foundIncomplete[itemID] > 0) then
						if(checkOnly) then return true end
						rememberStackCount[itemID] = itemStackCount
					end
					-- get
					local newtable if(ftnum==0) then newtable={} else newtable=ftstorage[ftnum] ftnum=ftnum-1 end
					newtable[1]=realbag
					newtable[2]=slot
					newtable[3]=itemCount
					table.insert(foundIncomplete[itemID], newtable)
				end
			end
		end
	end
	if(checkOnly) then return nil end
	for itemID, itemStackCount in pairs(rememberStackCount) do
		local bestNum=0, bestFirstIdx, bestSecondIdx
		while(#foundIncomplete[itemID] > 1) do
			for firstIdx = 1, #foundIncomplete[itemID]-1 do
				for secondIdx = firstIdx+1, #foundIncomplete[itemID] do
					local resultStack=foundIncomplete[itemID][firstIdx][3]+foundIncomplete[itemID][secondIdx][3]
					if(resultStack>itemStackCount) then resultStack=1 end
					if(resultStack>bestNum) then bestNum=resultStack bestFirstIdx=firstIdx bestSecondIdx=secondIdx end
					if(resultStack==itemStackCount) then break end
				end
			end
			SplitContainerItem(foundIncomplete[itemID][bestSecondIdx][1], foundIncomplete[itemID][bestSecondIdx][2], foundIncomplete[itemID][bestSecondIdx][3])
			PickupContainerItem(foundIncomplete[itemID][bestFirstIdx][1], foundIncomplete[itemID][bestFirstIdx][2])
			-- free
			ftnum=ftnum+1 ftstorage[ftnum]=foundIncomplete[itemID][bestFirstIdx]
			ftnum=ftnum+1 ftstorage[ftnum]=foundIncomplete[itemID][bestSecondIdx]
			table.remove(foundIncomplete[itemID], bestSecondIdx)
			table.remove(foundIncomplete[itemID], bestFirstIdx)
			moved=moved+1
		end
	end
	TitanItemDed_Chatback(format(TPID_CHATBACK_MOVED_ITEMS, moved, (moved == 1 and TPID_CHATBACK_ITEM1 or TPID_CHATBACK_ITEMP)))
	TitanItemDed_UpdateList()
	TitanPanelItemDedButton_UpdateIcon()
end

function TitanItemDed_GetIgnoreItemClass(itemClassID, itemSubClassID)
	if(TitanItemDedSettings[PlayerIdent].IgnoredClass[itemClassID]) then
		return TitanItemDedSettings[PlayerIdent].IgnoredClass[itemClassID][itemSubClassID]
	else
		return nil
	end
end

function TitanItemDed_ToggleIgnoreItemClass(itemClassID, itemSubClassID)
	TitanItemDed_SetIgnoreItemClass(itemClassID, itemSubClassID, (not (TitanItemDedSettings[PlayerIdent].IgnoredClass[itemClassID] and TitanItemDedSettings[PlayerIdent].IgnoredClass[itemClassID][itemSubClassID])) and 1 or nil)
	HideDropDownMenu(UIDROPDOWNMENU_MENU_LEVEL-1)
end

function TitanItemDed_SetIgnoreItemClass(itemClassID, itemSubClassID, ignore)
	local className, subClassName=ItemDataCache.GetClassSubclassName(itemClassID, itemSubClassID)
	if(not className or (not subClassName)) then return nil end
	if(not TitanItemDedSettings[PlayerIdent].IgnoredClass[itemClassID]) then TitanItemDedSettings[PlayerIdent].IgnoredClass[itemClassID]={} end
	TitanItemDedSettings[PlayerIdent].IgnoredClass[itemClassID][itemSubClassID]=ignore
	if(ignore) then
		TitanItemDed_Chatback(format(TPID_CHATBACK_CLASS_NOW_IGNORED, className, subClassName))
	else
		TitanItemDed_Chatback(format(TPID_CHATBACK_CLASS_NO_LONGER_IGNORED, className, subClassName))
	end
	TitanItemDed_UpdateList()
	TitanPanelItemDedButton_UpdateIcon()
end

-- GUI/slash command is now in, but you still can do it manually:
-- Add: /script TitanItemDed_SetAlwaysDroppable(2862, 1) -- 2862 == rough sharpening stone, 1 == do sell/drop
-- Remove: /script TitanItemDed_SetAlwaysDroppable(2862, nil) -- 2862 == rough sharpening stone, nil == remove table entry
function TitanItemDed_SetAlwaysDroppable(item, value)
	local itemId, itemName=TitanItemDed_GetItemIdNameFromLink(item)
	if(not itemId) then TitanItemDed_Chatback(TPID_CHATBACK_ERROR_PARSE_ITEM) return nil end
	TitanItemDedSettings[PlayerIdent]["Droppable"][itemId] = value
	local _, itemLink=GetItemInfo(itemId)
	if(value) then
		TitanItemDed_Chatback(format(TPID_CHATBACK_ITEM_NOW_ALWAYS_DROPPABLE, itemLink));
	else
		TitanItemDed_Chatback(format(TPID_CHATBACK_ITEM_NO_LONGER_ALWAYS_DROPPABLE, itemLink))
	end
end

function TitanItemDed_SetCustomPriceMode(itemLink, priceMode, ...)
	local toggle=...
	local itemId, itemName=TitanItemDed_GetItemIdNameFromLink(itemLink)
	if(not itemId) then TitanItemDed_Chatback(TPID_CHATBACK_ERROR_PARSE_ITEM) return nil end
	local currentMode=TitanItemDed_CustomPriceMode(itemId)
	if(toggle and currentMode and (priceMode==currentMode)) then
		return TitanItemDed_SetCustomPriceMode(itemId, nil)
	end
	TitanItemDedSettings[PlayerIdent]["CustomPrice"][itemId]=priceMode
	if(type(priceMode)=="number") then priceMode="player_defined" end
	if(type(priceMode)=="nil") then priceMode="vendor" end
	TitanItemDed_Chatback(format(TPID_CHATBACK_SET_PRICE_MODE_ITEM, itemName, TPID_CUSTOM_PRICE[priceMode].long))
end

function TitanItemDed_CustomPriceMode(itemId)
	local priceMode=TitanItemDedSettings[PlayerIdent]["CustomPrice"][itemId]
	if(type(priceMode)=="number") then return "player_defined" end
	return priceMode
end

function TitanItemDed_GetCustomPrice(itemLink, ...)
	local priceMode=...
	local itemId, itemName=TitanItemDed_GetItemIdNameFromLink(itemLink)
	if(not itemId) then TitanItemDed_Chatback(TPID_CHATBACK_ERROR_PARSE_ITEM) return nil end
	priceMode=priceMode or TitanItemDed_CustomPriceMode(itemId)
	if(priceMode=="auctioneer_buyout") then return TitanItemDed_GetAuctioneerPrice(itemLink, "buyout") end
	return nil
end

function TitanItemDed_IsAlwaysDroppable(item)
	local itemId, itemName=TitanItemDed_GetItemIdNameFromLink(item)
	if(not itemId) then TitanItemDed_Chatback(TPID_CHATBACK_ERROR_PARSE_ITEM) return nil end
	return TitanItemDedSettings[PlayerIdent]["Droppable"][itemId]
end

function TitanItemDed_IsDroppable(bag, slot)
	local _, _, locked = GetContainerItemInfo(bag, slot)
	if(locked) then return false end
	local itemId = TitanItemDed_GetItemId(bag, slot);
	if (not itemId) then return false end
	if TitanItemDed_droppable[itemId] then return true; end;
	if TitanItemDed_ignored[itemId] then return false; end;
	if TitanItemDedSettings[PlayerIdent].Ignored[itemId] then return false; end;
	if TitanItemDedSettings[PlayerIdent].Droppable[itemId] then return true; end;
	local quality=TitanItemDed_GetQuality(bag, slot)
	if ((not quality) or (quality > TitanItemDedSettings[PlayerIdent].Threshold)) then return false end
	local _, _, _, _, _, itemClass, itemSubClass=GetItemInfo(itemId)
	local itemClassID, itemSubClassID=ItemDataCache.GetClassSubclassID(itemClass, itemSubClass)
	if(itemClassID and itemSubClassID) then
		if(TitanItemDed_GetIgnoreItemClass(itemClassID, itemSubClassID)) then return false end
	end
	return true
end

function TitanItemDed_GetEmpties()
	local numempty = 0;
	for bag=0,NUM_BAG_FRAMES do
		if (not TitanItemDed_IsAmmoBag(bag)) then
			for slot=1,GetContainerNumSlots(bag) do
			  	if (not GetContainerItemInfo(bag, slot)) then numempty = numempty+1; end
			end
		end
	end
	return numempty;
end

function TitanItemDed_IsAmmoBag(bag)
	if(bag<1 or bag>11) then return nil end
	local bagInvId=ContainerIDToInventoryID(bag)
	if(not bagInvId) then return nil end
	local bagLink=GetInventoryItemLink("player", bagInvId)
	if(not bagLink) then return nil end
        _, _, _, _, _, bagType = GetItemInfo(bagLink)
	if(not bagType) then return nil end
	if(bagType == "Quiver") then
		return true
	else
		return false;
	end
end

-------------------------------------------------------------------------------
-- Gold formatting code, shamelessly "borrowed" from Auctioneer no longer
-------------------------------------------------------------------------------

function TitanItemDed_GetGSC(money)
	if (money == nil) then return 0, 0, 0 end
	local g = math.floor(money / 10000);
	local s = math.floor((money - (g*10000)) / 100);
	local c = math.floor(money - (g*10000) - (s*100));
	return g,s,c;
end

local GSC_GOLD="ffd100";
local GSC_SILVER="e6e6e6";
local GSC_COPPER="c8602c";
local GSC_PART_PRE="|cff";
local GSC_FIRST_PART_POST="%d|r";
local GSC_PART_POST="%02d|r";

local GSC_FULL_G   = GSC_PART_PRE..GSC_GOLD..GSC_FIRST_PART_POST
local GSC_FULL_S   = GSC_PART_PRE..GSC_SILVER..GSC_FIRST_PART_POST
local GSC_FULL_C   = GSC_PART_PRE..GSC_COPPER..GSC_FIRST_PART_POST
local GSC_FULL_SC  = GSC_FULL_S..TPID_GSC_SEPARATOR..GSC_PART_PRE..GSC_COPPER..GSC_PART_POST
local GSC_FULL_GSC = GSC_FULL_G..TPID_GSC_SEPARATOR..GSC_PART_PRE..GSC_SILVER..GSC_PART_POST..TPID_GSC_SEPARATOR..GSC_PART_PRE..GSC_COPPER..GSC_PART_POST
local GSC_FULL_GS  = GSC_FULL_G..TPID_GSC_SEPARATOR..GSC_PART_PRE..GSC_SILVER..GSC_PART_POST
local GSC_FULL_GC  = GSC_FULL_G..TPID_GSC_SEPARATOR..GSC_PART_PRE..GSC_COPPER..GSC_PART_POST

local GSC_NONE="|cffa0a0a0"..TPID_GSC_NONE.."|r";

function TitanItemDed_GetTextGSC(money)
	if(not money or money==0) then return GSC_NONE end
	if(money<100) then return format(GSC_FULL_C, money) end

	local g, s, c = TitanItemDed_GetGSC(money)

	if(g==0) then return format((c==0 and GSC_FULL_S or GSC_FULL_SC), s, c) end
	if(c==0) then return format((s==0 and GSC_FULL_G or GSC_FULL_GS), g, s) end
	return (s==0 and format(GSC_FULL_GC, g, c) or format(GSC_FULL_GSC, g, s, c))
end
