Quantcast
-- GLOBALS: GDKPd, GDKPd_PotData, GDKPd_Anchor, GDKPd_BalanceData, SlashCmdList, SLASH_GDKPD1, SLASH_GDKPD2
-- fetch all used functions into locals to improve performance
local table, tinsert, tremove, pairs, ipairs, unpack, math, tostring, tonumber, select, _G, strlen, setmetatable, string, print, next, type, rawget, date, tconcat, min =
	  table, tinsert, tremove, pairs, ipairs, unpack, math, tostring, tonumber, select, _G, strlen, setmetatable, string, print, next, type, rawget, date, table.concat, math.min
local SendAddonMessage, SendChatMessage, UnitIsRaidOfficer, UnitIsUnit, UnitIsGroupLeader, GetMasterLootCandidate, GetNumLootItems, GetLootSlotLink, GiveMasterLoot, UnitName, GetUnitName, CreateFrame, GetCVar, GetCVarBool, GetTime, StaticPopup_Show, GetItemInfo, GameTooltip, LibStub, ITEM_QUALITY_COLORS, InCombatLockdown, ERR_TRADE_COMPLETE, GetPlayerTradeMoney, GetTargetTradeMoney, GetItemIcon, ClearCursor, GetNumGroupMembers, GetRaidRosterInfo, GetLootThreshold, GetLootSlotType, GetLootSlotInfo, EditBox_HandleTabbing, GetCursorInfo, PickupItem, IsInRaid, IsInGroup, SendMail, SetSendMailMoney, ClearSendMail, IsShiftKeyDown =
	  SendAddonMessage, SendChatMessage, UnitIsRaidOfficer, UnitIsUnit, UnitIsGroupLeader, GetMasterLootCandidate, GetNumLootItems, GetLootSlotLink, GiveMasterLoot, UnitName, GetUnitName, CreateFrame, GetCVar, GetCVarBool, GetTime, StaticPopup_Show, GetItemInfo, GameTooltip, LibStub, ITEM_QUALITY_COLORS, InCombatLockdown, ERR_TRADE_COMPLETE, GetPlayerTradeMoney, GetTargetTradeMoney, GetItemIcon, ClearCursor, GetNumGroupMembers, GetRaidRosterInfo, GetLootThreshold, GetLootSlotType, GetLootSlotInfo, EditBox_HandleTabbing, GetCursorInfo, PickupItem, IsInRaid, IsInGroup, SendMail, SetSendMailMoney, ClearSendMail, IsShiftKeyDown
local _
local UIParent, MailFrame =
	  UIParent, MailFrame

local RegisterAddonMessagePrefix, SendAddonMessage = C_ChatInfo.RegisterAddonMessagePrefix, C_ChatInfo.SendAddonMessage

-- Fetch all the different realm separators into a table
local REALM_SEPARATOR_LIST = {}
for s in REALM_SEPARATORS:gmatch(".") do tinsert(REALM_SEPARATOR_LIST,s) end

-- table handling to prevent any memory leakage from accumulating.
local emptytable = select(2,...).emptytable

local DEBUGFORCEVERSION

--@debug@
DEBUGFORCEVERSION="beta-19"
--@end-debug@
-- fetch locale data
local L = LibStub("AceLocale-3.0"):GetLocale("GDKPd")
-- versioning info
local VERSIONING_STRINGS = {
	VERSION_NONFUNCTIONAL = L["This version of GDKPd was never functional due to internal errors."],
	INCOMPATIBLE_AUCTIONSTART = L["This version will be unable to recognize auctions started by you."],
	INCOMPATIBLE_DISTRIBUTE = L["This version's player balance window will be unable to recognize distributions by you."],
	INCOMPATIBLE_AUCTIONCANCEL = L["This version will be unable to recognize auctions cancelled by you."],
	INCOMPATIBLE_VERSIONCHECK = L["This version will be unable to recognize version check requests by you. Version check requests sent by this version of GDKPd will not be answered."],
}
local COMPATIBLE_VERSIONS = {
	["beta-19"]=true,
	["1.4.2"]=true,
	["beta-18"]=true,
	["1.4.1"]=true,
	["beta-17a"]=true,
	["beta-17"]=true,
	["1.4.0"]=true,
	["beta-16"]=true,
	["1.3.0"]=true,
	["beta-15b"]=true,
	["beta-15a"]=true,
	["beta-15"]=true,
	["1.2.0"]=true,
}
local INCOMPATIBLE_VERSIONS = {
	["1.1.4"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-14f"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-14e"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-14d"]={"INCOMPATIBLE_VERSIONCHECK"},
	["1.1.3"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-14c"]={"INCOMPATIBLE_VERSIONCHECK"},
	["1.1.2"]={"INCOMPATIBLE_VERSIONCHECK"},
	["1.1.1"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-14b"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-14a"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-14"]={"INCOMPATIBLE_VERSIONCHECK"},
	["1.1.0"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-13c"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-13b"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-13a"]={"INCOMPATIBLE_VERSIONCHECK"},
	["beta-13"]={"VERSION_NONFUNCTIONAL"},
	["beta-12"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["1.0.0a"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["1.0.0"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11s"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11r"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11q"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11p"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11o"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11m"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11l"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11i"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11h"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11g"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11f"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11e"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11d"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11c"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11b"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11a"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11"]={"INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11n"]={"VERSION_NONFUNCTIONAL"},
	["beta-11k"]={"INCOMPATIBLE_DISTRIBUTE","INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-11j"]={"INCOMPATIBLE_DISTRIBUTE","INCOMPATIBLE_AUCTIONCANCEL"},
	["beta-10h"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10g"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10f"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10e"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10d"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10c"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10b"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10a"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-10"]={"VERSION_NONFUNCTIONAL"},
	["beta-9a"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-9"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-8"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-7b"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-7a"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-7"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-6"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-5"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-4"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-3"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-2b"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-2a"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-2"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-1a"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
	["beta-1"]={"INCOMPATIBLE_AUCTIONSTART","INCOMPATIBLE_AUCTIONCANCEL","INCOMPATIBLE_DISTRIBUTE"},
}

-- recursive table copy
local trcopy
do
	local trueCopy = {["ruleTemplate.rules"]=1,["ruleTemplate.rules.args"]=1,["ruleEntryTemplate.args"]=1,["ruleEntryTemplate.args.ruleArgs"]=1} -- val is number of levels to always truecopy including this one, negative for infinite
	trcopy = function(from,to,pKey,copy)
		copy = copy or trueCopy[pKey] or 0
		for key,val in pairs(from) do
			if type(val) == "table" then
				local tKey= ("%s.%s"):format(pKey,key)
				local copyThis = trueCopy[tKey] or copy
				if copyThis ~= 0 then
					to[key] = trcopy(val,{},tKey,copyThis-1)
				else
					to[key] = val
				end
			else
				to[key] = val
			end
		end
		return to
	end
end

-- define a few old API functions that I can't be bothered to replace everywhere
local function IsRaidOfficer()
	return IsInRaid() and UnitIsRaidOfficer("player")
end

local function IsRaidLeader()
	return IsInRaid() and UnitIsGroupLeader("player")
end

-- static popup dialog definition
StaticPopupDialogs["GDKPD_RESETPOT"] = {
	text=L["Do you want to save your pot or reset without saving? You can also add a note to the pot."],
	button1=SAVE.." & "..RESET,
	button2=RESET,
	button3=CANCEL,
	hasEditBox=true,
	EditBoxOnEnterPressed=function(self) self:GetParent().button1:Click() end,
	OnAccept=function(self)
		tinsert(GDKPd_PotData.history, {size=GDKPd_PotData.potAmount, date=date("%Y-%m-%d"), items=GDKPd_PotData.curPotHistory, note=(strlen(self.editBox:GetText()) > 0 and self.editBox:GetText())})
		GDKPd_PotData.potAmount = 0
		GDKPd_PotData.prevDist = 0
		GDKPd_PotData.curPotHistory = {}
		GDKPd_PotData.playerBalance = setmetatable({},{__index=function() return 0 end})
		GDKPd.status:Update()
		GDKPd.balance:Update()
		if GDKPd.history:IsShown() then
			GDKPd.history:Update()
		end
	end,
	OnCancel=function(self)
		GDKPd_PotData.potAmount = 0
		GDKPd_PotData.prevDist = 0
		GDKPd_PotData.curPotHistory = {}
		GDKPd_PotData.playerBalance = setmetatable({},{__index=function() return 0 end})
		GDKPd.status:Update()
		GDKPd.balance:Update()
	end,
	timeout=0,
}
StaticPopupDialogs["GDKPD_SLIMMLWARN"] = {
	text=L["WARNING!\n\nIf you use the slim bidding frame, you will be unable to cancel auctions and revert bids!\nAre you certain you want to do this?"],
	button1=YES,
	button2=NO,
	OnShow=function(self)
		--elevate it above aceconfig
		self:SetFrameStrata("FULLSCREEN_DIALOG")
		self.button1:SetFrameLevel(10000)
		self.button2:SetFrameLevel(10000)
	end,
	OnAccept=function()
		GDKPd.opt.slimML = true
		GDKPd.opt.slimMLConfirmed=true
	end,
	OnHide=function(self)
		self:SetFrameStrata("DIALOG")
	end,
	timeout=0,
	hideOnEscape=true,
	whileDead=true,
	showAlert=true,
	cancels="GDKPD_SLIMMLWARN",
}
StaticPopupDialogs["GDKPD_ADDTOPOT"] = {
	text=L["Enter the amount you want to add to the pot:"],
	button1=ADD,
	button2=CANCEL,
	hasEditBox=true,
	OnShow=function(self)
		self.button1:Disable()
	end,
	EditBoxOnEnterPressed=function(self) self:GetParent().button1:Click() end,
	EditBoxOnTextChanged = function(self)
		if strlen(self:GetText()) > 0 then
			self:GetParent().button1:Enable()
		else
			self:GetParent().button1:Disable()
		end
	end,
	OnAccept=function(self)
        local amt = (tonumber(self.editBox:GetText()) or 0)
        if amt <= 0 then return end
		GDKPd_PotData.potAmount = GDKPd_PotData.potAmount + amt
		tinsert(GDKPd_PotData.curPotHistory, tonumber(self.editBox:GetText()) or 0)
		GDKPd.status:Update()
	end,
	timeout=0,
	whileDead=true,
}
StaticPopupDialogs["GDKPD_REMFROMPOT"] = {
	text=L["Enter the amount you want to subtract from the pot:"],
	button1=REMOVE,
	button2=CANCEL,
	hasEditBox=true,
	OnShow=function(self)
		self.button1:Disable()
	end,
	EditBoxOnEnterPressed=function(self) self:GetParent().button1:Click() end,
	EditBoxOnTextChanged=function(self)
		if strlen(self:GetText()) > 0 then
			self:GetParent().button1:Enable()
		else
			self:GetParent().button1:Disable()
		end
	end,
	OnAccept = function(self)
        local amt = (tonumber(self.editBox:GetText()) or 0)
        if (amt <= 0) or (GDKPd_PotData.potAmount == 0) then return end
		GDKPd_PotData.potAmount = math.max(0, GDKPd_PotData.potAmount - amt)
		tinsert(GDKPd_PotData.curPotHistory, (tonumber(self.editBox:GetText()) or 0)*(-1))
		GDKPd.status:Update()
	end,
	timeout=0,
	whileDead=true,
}
StaticPopupDialogs["GDKPD_ADDTOPLAYER"] = {
	text=L["Enter the amount you want to add to player %s:"],
	button1=ADD,
	button2=CANCEL,
	hasEditBox=true,
	OnShow=function(self)
		self.button1:Disable()
	end,
	EditBoxOnEnterPressed=function(self) self:GetParent().button1:Click() end,
	EditBoxOnTextChanged=function(self)
		if strlen(self:GetText()) > 0 then
			self:GetParent().button1:Enable()
		else
			self:GetParent().button1:Disable()
		end
	end,
	OnAccept = function(self, data)
		GDKPd_PotData.playerBalance[data] = (GDKPd_PotData.playerBalance[data]+(tonumber(self.editBox:GetText()) or 0))
		SendAddonMessage("GDKPD MANADJ",tostring((tonumber(self.editBox:GetText()) or 0)*(-1)),"WHISPER",data)
		GDKPd.balance:Update()
		if GDKPd.opt.linkBalancePot then
			GDKPd_PotData.potAmount = math.max(0, GDKPd_PotData.potAmount-(tonumber(self.editBox:GetText()) or 0))
			tinsert(GDKPd_PotData.curPotHistory, (tonumber(self.editBox:GetText()) or 0)*(-1))
			GDKPd.status:Update()
		end
	end,
	timeout=0,
	whileDead=true,
}
StaticPopupDialogs["GDKPD_REMFROMPLAYER"] = {
	text=L["Enter the amount you want to subtract from player %s:"],
	button1=REMOVE,
	button2=CANCEL,
	hasEditBox=true,
	OnShow=function(self)
		self.button1:Disable()
	end,
	EditBoxOnEnterPressed=function(self) self:GetParent().button1:Click() end,
	EditBoxOnTextChanged=function(self)
		if strlen(self:GetText()) > 0 then
			self:GetParent().button1:Enable()
		else
			self:GetParent().button1:Disable()
		end
	end,
	OnAccept = function(self, data)
		GDKPd_PotData.playerBalance[data] = (GDKPd_PotData.playerBalance[data]-(tonumber(self.editBox:GetText()) or 0))
		SendAddonMessage("GDKPD MANADJ",tostring(tonumber(self.editBox:GetText()) or 0),"WHISPER",data)
		GDKPd.balance:Update()
		if GDKPd.opt.linkBalancePot then
			GDKPd_PotData.potAmount = GDKPd_PotData.potAmount+(tonumber(self.editBox:GetText()) or 0)
			tinsert(GDKPd_PotData.curPotHistory, tonumber(self.editBox:GetText()) or 0)
			GDKPd.status:Update()
		end
	end,
	timeout=0,
	whileDead=true,
}
StaticPopupDialogs["GDKPD_MAILGOLD"]={
	text=L["Are you sure you want to mail %s gold to player %s?"],
	button1=L["Mail money"],
	button2=CANCEL,
	OnAccept=function(self,data)
		GDKPd:MailBalanceGold(data)
	end,
	timeout=0,
	whileDead=true,
	showAlert=true,
	hideOnEscape=true,
}
StaticPopupDialogs["GDKPD_WIPEHISTORY"]={
	text=L["This will completely wipe your auction history and is IRREVERSIBLE.\nAre you completely SURE you want to do this?"],
	button1=L["Wipe history"],
	button2=CANCEL,
	OnAccept=function()
		table.wipe(GDKPd_PotData.history)
		if GDKPd.history:IsShown() then
			GDKPd.history:Update()
		end
	end,
	timeout=0,
	hideOnEscape=true,
	whileDead=true,
	showAlert=true,
	cancels="GDKPD_WIPEHISTORY",
}
StaticPopupDialogs["GDKPD_AUTOBID"] = {
	text=L["Enter the maximum amount of money you want to bid on %s:"],
	button1=BID,
	button2=CANCEL,
	hasEditBox=true,
	OnShow=function(self)
		self.button1:Disable()
	end,
	EditBoxOnEnterPressed=function(self) self:GetParent().button1:Click() end,
	EditBoxOnTextChanged = function(self)
		if strlen(self:GetText()) > 0 then
			self:GetParent().button1:Enable()
		else
			self:GetParent().button1:Disable()
		end
	end,
	OnAccept=function(self, data)
		data.maxAutoBid = tonumber(self.editBox:GetText())
		if (data.curbidismine == false) and data.maxAutoBid then
			local newBid = data.curbidamount + data.bidIncrement
			if newBid <= data.maxAutoBid then
				if data.isMultiBid then
					SendChatMessage(data.itemlink.." "..newBid,"RAID")
				else
					SendChatMessage(tostring(newBid),"RAID")
				end
			end
		end
		data.autobid:Hide()
		data.stopautobid:Show()
	end,
	timeout=0,
}
StaticPopupDialogs["GDKPD_CURPOTCLICK"]={
	text=L["You have selected the current pot, size %d gold.\nWhat do you want to do with this pot?"],
	button1=L["Export"],
	button2=DELETE,
	button3=CANCEL,
	OnShow=function(self) self.button3:Disable() end,
	OnAccept=function(self)
		--[[local output = "GDKPd pot data for Current Pot\nPot size: "..GDKPd_PotData.potAmount.." gold"
		for _, aucdata in ipairs(GDKPd_PotData.curPotHistory) do
			if type(aucdata) == "table" then
				output = output.."\n"..(aucdata.item:match("(|h.+|h)"))..": "..aucdata.name.." ("..aucdata.bid.." gold)"
			else
				output = output.."\n"..L["Manual adjustment"]..": "..(aucdata > 0 and "+" or "")..aucdata.." gold"
			end
		end--]]
		GDKPd.exportframe:Show()
		GDKPd.exportframe:Set("GDKPd pot data for Current Pot\nPot size: "..GDKPd_PotData.potAmount.." gold", GDKPd_PotData.curPotHistory)
	end,
	timeout=0,
	whileDead=true,
}
StaticPopupDialogs["GDKPD_HISTORYCLICK"] = {
	text="%s",
	button1=L["Export"],
	button2=DELETE,
	button3=CANCEL,
	OnAccept=function(self, data)
		local output = "GDKPd pot data for "..data.date.."\nPot size: "..data.size.." gold"
		if data.note then
			output = output.."\nNote: "..data.note
		end
		--[[if data.items then
			for _, aucdata in ipairs(data.items) do
				if type(aucdata) == "table" then
					output = output.."\n"..(aucdata.item:match("(|h.+|h)"))..": "..aucdata.name.." ("..aucdata.bid.." gold)"
				else
					output = output.."\n"..L["Manual adjustment"]..": "..(aucdata > 0 and "+" or "")..aucdata.." gold"
				end
			end
		end--]]
		GDKPd.exportframe:Show()
		GDKPd.exportframe:Set(output,data.items)
	end,
	OnCancel=function(self, data,clickType)
		if clickType == "override" then return end
		for num, t in ipairs(GDKPd_PotData.history) do
			if t == data then
				tremove(GDKPd_PotData.history, num)
				break
			end
		end
		GDKPd.history:Update()
	end,
	timeout=0,
	whileDead=0,
}
StaticPopupDialogs["GDKPD_42_ADDONMSG"]={
	text=L["Due to the changes to the addon message system implemented in patch 4.2, GDKPd is no longer able to communicate using its old version checking standard.\nThus, this version of GDKPd will only be able to send and receive version checks from and to versions 1.2.0 and above of GDKPd.\nWhile all other functionalities of GDKPd should still be compatible with previous versions, we |cffff0000strongly recommend updating GDKPd to version 1.2.0 or above|r."],
	button1=OKAY,
	showAlert=true,
	hideOnEscape=false,
	timeout=0,
}
local function checkSafeDelete()
	if not GDKPd.opt.safeDelete then return true end
	if IsShiftKeyDown() then return true end
	print(L["|cff8888ffGDKPd:|r This destructive action requires that you hold down the shift key. (Safe delete mode is |cff00ff00ON|r)"])
	return false
end

local function HideTooltipOnLeave(self)
    if GameTooltip:IsOwned(self) then
        GameTooltip:Hide()
    end
end

local function round(num, places)
	return tonumber(string.format("%."..(places or 0).."f",num))
end
-- if GetUnitName cannot parse the name as a unitID, that means they're from our realm - parse manually
local function localNameOnly(name)
	for _,s in ipairs(REALM_SEPARATOR_LIST) do
		local i = name:find(s,1,true)
		if i then name=name:sub(1,i-1) end
	end
	return name
end
local function pruneCrossRealm(name) -- only use for people in the raid group!
	return GetUnitName(name,true) or localNameOnly(name)
end

-- item filter definitions
local itemFilters = {
	["false"] = {
		title=L["Filter is always false"],
		func=function() return false end,
		describe=function() return L["Filter is always false"] end,
		args={},
	},
	["itemid"] = {
		title=L["Item id is one of..."],
		func=function(link,args)
			if not args.idlist then return false end
			local id = tonumber((link:match("|Hitem:(%d+)")))
			if not id then return end
			for mId in args.idlist:gmatch("%d+") do
				if id == tonumber(mId) then
					return true
				end
			end
		end,
		describe=function(args)
			if not args.idlist then return L["Filter is always false"] end
			local ctable = emptytable()
			for mId in args.idlist:gmatch("%d+") do
				tinsert(ctable,mId)
			end
			local desc = L["Item ID is one of the following: %s"]:format(tconcat(ctable,", "))
			ctable:Release()
			return desc
		end,
		defaults={
			idlist="",
		},
		args={
			idlist = {
				type="input",
				name=L["Item IDs"],
				desc=L["List of item IDs. Any non-numerical character is treated as a seperator."],
				width="full",
			},
		},
	},
	["itemname"] = {
		title=L["Item name equals..."],
		func=function(link,args)
			local name = (GetItemInfo(link))
			return (name == args.name)
		end,
		describe=function(args)
			if not args.name then return L["Filter is always false"] end
			return L["Item name is exactly \"%s\""]:format(args.name)
		end,
		defaults={
			name="",
		},
		args={
			name = {
				type="input",
				name=L["Item name"],
				width="full",
			},
		},
	},
	["itemname-pattern"] = {
		title=L["Item name matches Lua pattern..."],
		func=function(link,args)
			if (not args.pattern) or (args.pattern == "") then return false end
			local name = (GetItemInfo(link))
			return not not (name and name:match(args.pattern))
		end,
		describe=function(args)
			if (not args.pattern) or (args.pattern == "") then return L["Filter is always false"] end
			return L["Item name matches pattern \"%s\""]:format(args.pattern)
		end,
		defaults={
			name="",
		},
		args={
			pattern = {
				type="input",
				name=L["Pattern"],
				width="full",
			},
		},
	},
	["itemlevel"] = {
		title=L["Item level within range..."],
		func=function(link,args)
			if not (args.lowerBound and args.upperBound) then return false end
			local ilvl = (select(4,GetItemInfo(link)))
			if not ilvl then return false end
			return (ilvl <= args.upperBound) and (ilvl >= args.lowerBound)
		end,
		describe=function(args)
			if not (args.lowerBound and args.upperBound) then return L["Filter is always false"] end
			return L["Item level is between %d and %d inclusive"]:format(args.lowerBound,args.upperBound)
		end,
		defaults={
			lowerBound=0,
			upperBound=0,
		},
		args={
			lowerBound = {
				type="range",
				name=L["Lower bounds"],
				desc=L["Lower limit on item level (inclusive)"],
				min=0,
				max=100000,
				softMax=1000,
				step=1,
				order=1,
			},
			upperBound = {
				type="range",
				name=L["Upper bounds"],
				desc=L["Upper limit on item level (inclusive)"],
				min=0,
				max=100000,
				softMax=1000,
				step=1,
				order=2,
			},
		},
	},
}
local itemFilterListSelect = {}
for key,val in pairs(itemFilters) do
	itemFilterListSelect[key] = val.title or key
end
-- item filter definitions end

GDKPd = CreateFrame("Frame")
local GDKPd = GDKPd
GDKPd.frames = {}
GDKPd.curAuction = {}
GDKPd.curAuctions = {}
GDKPd.auctionList = {}
GDKPd.ignoredLinks = {}
GDKPd.versions = {}
GDKPd:Hide()
GDKPd:SetScript("OnUpdate", function(self, elapsed)
	if (not self.curAuction.item) and (not next(self.curAuctions)) then self:Hide() return end
	if not self.opt.allowMultipleAuctions then
		-- old code for single auctions
		local curPot = math.floor(self.curAuction.timeRemains/self.opt.countdownTimerJump)
		self.curAuction.timeRemains = self.curAuction.timeRemains-elapsed
		if (curPot ~= math.floor(self.curAuction.timeRemains/self.opt.countdownTimerJump)) and (curPot*self.opt.countdownTimerJump < self.opt.auctionTimer) and (not (next(self.curAuction.bidders,nil) and (curPot*self.opt.countdownTimerJump == self.opt.auctionTimerRefresh))) and (curPot > 0) then
			SendChatMessage("[GDKPd] "..(curPot*self.opt.countdownTimerJump).." seconds remaining!","RAID")
		end
		if self.curAuction.timeRemains <= 0 then
			self:Hide()
			self:FinishAuction()
		end
	else
		-- new code for multiple auctions
		local auctionsToFinish = emptytable()
		for item,aucdata in pairs(self.curAuctions) do
			local curPot = math.floor(aucdata.timeRemains/self.opt.countdownTimerJump)
			aucdata.timeRemains = aucdata.timeRemains-elapsed
			if (curPot ~= math.floor(aucdata.timeRemains/self.opt.countdownTimerJump)) and (curPot*self.opt.countdownTimerJump < self.opt.auctionTimer) and (not (next(aucdata.bidders,nil) and (curPot*self.opt.countdownTimerJump == self.opt.auctionTimerRefresh))) and (curPot > 0) then
				SendChatMessage("[GDKPd] "..(curPot*self.opt.countdownTimerJump).." seconds remaining for item "..item.."!","RAID")
			end
			if aucdata.timeRemains <= 0 then
				tinsert(auctionsToFinish, item)
			end
		end
		if #auctionsToFinish > 0 then
			for _, link in ipairs(auctionsToFinish) do
				self:FinishAuction(link)
			end
		end
		auctionsToFinish:Release()
		-- there are no keys
		if not next(self.curAuctions) then
			self:Hide()
		end
	end
end)
local anchor = CreateFrame("Frame", "GDKPd_Anchor", UIParent)
anchor:SetClampedToScreen(true)
anchor:EnableMouse(true)
anchor:SetScript("OnMouseDown", function(self)
	self:StartMoving()
end)
anchor:SetMovable(true)
anchor:SetScript("OnMouseUp", function(self)
	self:StopMovingOrSizing()
	GDKPd.opt.point.point, _, GDKPd.opt.point.relative, GDKPd.opt.point.x, GDKPd.opt.point.y = self:GetPoint()
end)
anchor:SetSize(300,60)
anchor:SetFrameStrata("DIALOG")
anchor:Hide()
anchor.movetx = anchor:CreateTexture()
anchor.movetx:SetAllPoints()
anchor.movetx:SetColorTexture(0.3,0.3,0.9)
anchor.movetx:SetAlpha(0.5)
anchor.movetx.text = anchor:CreateFontString()
anchor.movetx.text:SetFontObject(GameFontHighlightLarge)
anchor.movetx.text:SetText(L["GDKPd: Drag to move\n/gdkpd and check \"Lock\" to hide"])
anchor.movetx.text:SetAllPoints()
GDKPd.status = CreateFrame("Frame", "GDKPd_Status", UIParent)
local status = GDKPd.status
status:SetSize(200, 90)
status:Hide()
status:SetBackdrop({
	bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
	edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
	tileSize=32,
	tile=true,
	insets={
		top=12,
		bottom=12,
		right=12,
		left=12,
	},
})
function status:UpdateVisibility(forceCombat)
	if GDKPd.opt.hide then
		self:Hide()
		return
	end
	if ((not GDKPd.opt.hideCombat.status) or (not (forceCombat ~= nil and forceCombat or InCombatLockdown()))) and GDKPd:PlayerIsML((UnitName("player")),true) then
		self:Show()
	else
		self:Hide()
	end
end
status.header = CreateFrame("Button", nil, status)
status.header:SetNormalTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
status.header:SetSize(133,34)
status.header.text = status.header:CreateFontString()
status.header.text:SetPoint("TOP",0,-7)
status.header.text:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
status.header.text:SetTextColor(1,1,1)
status.header.text:SetText("GDKPd")
status.header:SetMovable(true)
status.header:SetScript("OnMouseDown", function(self)
	self:StartMoving()
end)
status.header:SetScript("OnMouseUp", function(self)
	self:StopMovingOrSizing()
	GDKPd.opt.statuspoint.point, _, GDKPd.opt.statuspoint.relative, GDKPd.opt.statuspoint.x, GDKPd.opt.statuspoint.y = self:GetPoint()
end)
status:SetPoint("TOP", status.header, "TOP", 0, -6)
status:SetScript("OnShow", function(self)
	self:UpdateSize()
end)
status.text = status:CreateFontString()
status.text:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
status.text:SetTextColor(1,1,1)
status.text:SetPoint("TOPLEFT", 15, -15)
status.text:SetJustifyH("LEFT")
status.distribute = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.distribute:SetSize(65, 15)
status.distribute:SetPoint("TOPLEFT", status.text, "BOTTOMLEFT", 0, -5)
status.distribute:SetText(L["Distribute"])
status.distribute:SetScript("OnClick", function(self)
	GDKPd:DistributePot()
end)
status.reset = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.reset:SetSize(65, 15)
status.reset:SetPoint("LEFT", status.distribute, "RIGHT")
status.reset:SetText(RESET)
status.reset:SetScript("OnClick", function(self)
	StaticPopup_Show("GDKPD_RESETPOT")
end)
status.add = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.add:SetSize(15,15)
status.add:SetPoint("LEFT", status.reset, "RIGHT",10,0)
status.add:SetText("+")
status.add:SetScript("OnClick", function(self)
	StaticPopup_Show("GDKPD_ADDTOPOT")
end)
status.rem = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.rem:SetSize(15,15)
status.rem:SetPoint("LEFT", status.add, "RIGHT")
status.rem:SetText("-")
status.rem:SetScript("OnClick", function(self)
	StaticPopup_Show("GDKPD_REMFROMPOT")
end)
status.rules = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.rules:SetSize(170, 15)
status.rules:SetPoint("TOPLEFT", status.distribute, "BOTTOMLEFT")
status.rules:SetText(L["Broadcast rules"])
status.rules:SetScript("OnClick",function()
	local announceStrings = emptytable("")
	for line in string.gmatch(GDKPd.opt.rulesString,"[^\n]+") do
		for word in string.gmatch(line, "%S+") do
			if strlen(announceStrings[#announceStrings])+1+strlen(word) > 255 then
				tinsert(announceStrings, word)
			else
				if strlen(announceStrings[#announceStrings]) > 0 then
					announceStrings[#announceStrings] = announceStrings[#announceStrings].." "..word
				else
					announceStrings[#announceStrings] = word
				end
			end
		end
		tinsert(announceStrings, "")
	end
	for _, msg in ipairs(announceStrings) do
		SendChatMessage(msg, "RAID")
	end
	announceStrings:Release()
end)
status.rules:Disable()
status.itemhistory = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.itemhistory:SetSize(170, 15)
status.itemhistory:SetPoint("TOPLEFT", status.rules, "BOTTOMLEFT")
status.itemhistory:SetText(L["Auction history"])
status.itemhistory:SetScript("OnEnter", function(self)
	GameTooltip:SetOwner(self, "ANCHOR_TOP", 0, 5)
	GameTooltip:AddLine(L["GDKPd auction history"],1,1,1)
	for _, aucdata in ipairs(GDKPd_PotData.curPotHistory) do
		if type(aucdata) == "table" then
			GameTooltip:AddDoubleLine("|T"..GetItemIcon(aucdata.item)..":12|t "..aucdata.item, aucdata.name.." ("..aucdata.bid.."|cffffd100g|r)",1,1,1,1,1,1)
		else
			GameTooltip:AddDoubleLine("|T:12|t "..L["Manual adjustment"], (aucdata > 0 and "+" or "")..aucdata.."|cffffd100g|r",1,1,1,1,1,1)
		end
	end
	GameTooltip:Show()
end)
status.itemhistory:SetScript("OnLeave", HideTooltipOnLeave)
status.itemhistory:SetScript("OnClick", function()
	GDKPd.history:Show()
end)
status.announcetext = status:CreateFontString()
status.announcetext:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
status.announcetext:SetTextColor(1,1,1)
status.announcetext:SetPoint("TOPLEFT", status.itemhistory, "BOTTOMLEFT", 0, -5)
status.announcetext:SetJustifyH("LEFT")
status.announcetext:SetText(L["You have looted a monster!\nDo you want GDKPd to announce loot?"])
status.announcetext:Hide()
status.announce1 = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.announce1:SetSize(170,15)
status.announce1:SetPoint("TOPLEFT", status.announcetext, "BOTTOMLEFT", 0, -5)
status.announce1:SetText(L["Announce & auto-auction"])
status.announce1:SetScript("OnClick", function(self)
	GDKPd:AnnounceLoot(true)
	status.announcetext:Hide()
	self:Hide()
	status.announce2:Hide()
	status.noannounce:Hide()
	status:UpdateSize()
end)
status.announce1:Hide()
status.announce2 = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.announce2:SetSize(170,15)
status.announce2:SetPoint("TOPLEFT", status.announce1, "BOTTOMLEFT", 0, -5)
status.announce2:SetText(L["Announce loot"])
status.announce2:SetScript("OnClick", function(self)
	GDKPd:AnnounceLoot(false)
	status.announcetext:Hide()
	status.announce1:Hide()
	self:Hide()
	status.noannounce:Hide()
	status:UpdateSize()
end)
status.announce2:Hide()
status.noannounce = CreateFrame("Button", nil, status, "UIPanelButtonTemplate")
status.noannounce:SetSize(170,15)
status.noannounce:SetPoint("TOPLEFT", status.announce2, "BOTTOMLEFT", 0, -5)
status.noannounce:SetText(L["Do not announce"])
status.noannounce:SetScript("OnClick", function(self)
	status.announcetext:Hide()
	status.announce1:Hide()
	status.announce2:Hide()
	self:Hide()
	status:UpdateSize()
end)
status.noannounce:Hide()
function status:UpdateSize()
	local height = 80
	height = height+status.text:GetHeight()
	if status.announcetext:IsShown() then
		height=height+status.announcetext:GetHeight()+5
	end
	if status.announce1:IsShown() then
		height=height+20
	end
	if status.announce2:IsShown() then
		height=height+20
	end
	if status.noannounce:IsShown() then
		height=height+20
	end
	self:SetHeight(height)
end
function status:Update()
	local potAmount = (GDKPd_PotData.potAmount or 0)
	local lastDist = (GDKPd_PotData.prevDist or 0)
	if lastDist > 0 then
		self.text:SetText(L["Pot size: %d|cffffd100g|r"]:format(potAmount)..L[" |cffaa0000(Distribute: %dg)|r"]:format(potAmount-lastDist))
	else
		self.text:SetText(L["Pot size: %d|cffffd100g|r"]:format(potAmount))
	end
	self:UpdateSize()
end
GDKPd.history = CreateFrame("Frame", "GDKPd_History", UIParent)
local history = GDKPd.history
history:SetSize(200,95)
history:Hide()
history:SetBackdrop({
	bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
	edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
	tileSize=32,
	tile=true,
	insets={
		top=12,
		bottom=12,
		right=12,
		left=12,
	},
})
history.header = CreateFrame("Button", nil, history)
history.header:SetNormalTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
history.header:SetSize(133,34)
history.header:SetHitRectInsets(31.5,31.5,4.5,14.5)
history.header.text = history.header:CreateFontString()
history.header.text:SetPoint("TOP",0,-7)
history.header.text:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
history.header.text:SetTextColor(1,1,1)
history.header.text:SetText(L["History"])
history.header:SetMovable(true)
history.header:SetScript("OnMouseDown", function(self)
	self:StartMoving()
end)
history.header:SetScript("OnMouseUp", function(self)
	self:StopMovingOrSizing()
end)
history.header:SetPoint("CENTER",UIParent,"CENTER")
history:SetPoint("TOP", history.header, "TOP", 0, -6)
history:SetScript("OnShow", function(self)
	self:Update()
end)
history.entries = setmetatable({},{__index=function(t,v)
	local f = CreateFrame("Button", nil, history)
	if v > 1 then
		f:SetPoint("TOPLEFT", t[v-1], "BOTTOMLEFT", 0, -5)
		f:SetPoint("TOPRIGHT", t[v-1], "BOTTOMRIGHT", 0, -5)
	else
		f:SetPoint("TOPLEFT", 15, -15)
		f:SetPoint("TOPRIGHT", -15, -15)
	end
	function f:UpdateHeight()
		self:SetHeight(f.date:GetHeight())
	end
	f.date = f:CreateFontString()
	f.date:SetFont("Fonts\\FRIZQT__.TTF", 8,"")
	f.date:SetTextColor(1,1,1)
	f.date:SetPoint("TOPLEFT")
	f.date:SetWidth(55)
	f.amount = f:CreateFontString()
	f.amount:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
	f.amount:SetTextColor(1,1,1)
	f.amount:SetPoint("TOPLEFT", f.date, "TOPRIGHT", 5, 0)
	f.amount:SetPoint("BOTTOMLEFT", f.date, "BOTTOMRIGHT", 5, 0)
	f.amount:SetWidth(40)
	f.amount:SetJustifyH("RIGHT")
	f.note = f:CreateFontString()
	f.note:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
	f.note:SetTextColor(1,1,1)
	f.note:SetPoint("BOTTOMLEFT", f.amount, "BOTTOMRIGHT", 5, 0)
	f.note:SetPoint("TOPRIGHT")
	f.note:SetJustifyH("LEFT")
	function f:SetDataTable(data)
		self.date:SetText(data.date)
		self.rawdate = data.date
		self.amount:SetText(data.size.."|cffffd100g|r")
		self.rawamount = data.size
		self.note:SetText(data.note)
		self.itemtable = data.items
		self.data = data
		self:UpdateHeight()
	end
	function f:SetRawData(date,amount,note,items)
		self.date:SetText(date)
		self.rawdate = date
		self.amount:SetText(amount.."|cffffd100g|r")
		self.rawamount = amount
		self.note:SetText(note)
		self.itemtable = items
		self:UpdateHeight()
	end
	f:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_NONE")
		if self.itemtable then
			GameTooltip:AddLine(L["GDKPd auction history for %s"]:format(self.rawdate),1,1,1)
			if self.note:GetText() then
				GameTooltip:AddLine(L["Auction note: %s"]:format(self.note:GetText()),1,1,1)
			end
			for _, aucdata in ipairs(self.itemtable) do
				if type(aucdata) == "table" then
					GameTooltip:AddDoubleLine("|T"..GetItemIcon(aucdata.item)..":12|t "..aucdata.item, aucdata.name.." ("..aucdata.bid.."|cffffd100g|r)",1,1,1,1,1,1)
				else
					GameTooltip:AddDoubleLine("|T:12|t "..L["Manual adjustment"], (aucdata > 0 and "+" or "")..aucdata.."|cffffd100g|r",1,1,1,1,1,1)
				end
			end
		else
			GameTooltip:AddLine(L["GDKPd: No detailed data available"],1,1,1)
		end
		GameTooltip:SetPoint("TOPRIGHT", self, "LEFT", -5, 0)
		GameTooltip:Show()
	end)
	f:SetScript("OnLeave", HideTooltipOnLeave)
	f:SetScript("OnClick", function(self)
		ClearCursor()
		if self.data then
			StaticPopup_Show("GDKPD_HISTORYCLICK", L["You have selected the following pot:\n%s, dated %s, size %d gold.\nWhat do you want to do with this pot?"]:format(self.note:GetText(), self.date:GetText(), self.rawamount)).data = self.data
		else
			StaticPopup_Show("GDKPD_CURPOTCLICK", GDKPd_PotData.potAmount)
		end
	end)
	t[v]=f
	return f
end})
history.hide = CreateFrame("Button", nil, history, "UIPanelButtonTemplate")
history.hide:SetSize(170,15)
history.hide:SetPoint("BOTTOM", 0, 15)
history.hide:SetText(L["Hide"])
history.hide:SetScript("OnClick", function() history:Hide() end)
function history:Update()
	for _, f in ipairs(self.entries) do
		f:Hide()
	end
	local c = 1
	local size = 45
	for _, potdata in ipairs(GDKPd_PotData.history) do
		local f = self.entries[c]
		f:Show()
		f:SetDataTable(potdata)
		size=size+f:GetHeight()+5
		c=c+1
	end
	if GDKPd_PotData.potAmount > 0 then
		local f = self.entries[c]
		f:Show()
		f:SetRawData("Current pot", GDKPd_PotData.potAmount, nil, GDKPd_PotData.curPotHistory)
		size=size+f:GetHeight()+5
		c=c+1
	end
	self:SetHeight(size)
end
GDKPd.version = CreateFrame("Frame", "GDKPd_Versions", UIParent)
local version = GDKPd.version
version:SetSize(200,85)
version:Hide()
version:SetBackdrop({
	bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
	edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
	tileSize=32,
	tile=true,
	insets={
		top=12,
		bottom=12,
		right=12,
		left=12,
	},
})
version.header = CreateFrame("Button", nil, version)
version.header:SetNormalTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
version.header:SetSize(133,34)
version.header:SetHitRectInsets(31.5,31.5,4.5,14.5)
version.header.text = version.header:CreateFontString()
version.header.text:SetPoint("TOP", 0, -7)
version.header.text:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
version.header.text:SetTextColor(1,1,1)
version.header.text:SetText(L["Versions"])
version.header:SetMovable(true)
version.header:SetScript("OnMouseDown", function(self)
	self:StartMoving()
end)
version.header:SetScript("OnMouseUp", function(self)
	self:StopMovingOrSizing()
end)
version.header:SetPoint("CENTER", UIParent, "CENTER")
version:SetPoint("TOP", version.header, "TOP", 0, -6)
version:SetScript("OnShow", function(self)
	self:Update()
end)
version.entries = setmetatable({},{__index=function(t,v)
	local f = CreateFrame("Button", nil, version)
	if v > 1 then
		f:SetPoint("TOPLEFT", t[v-1], "BOTTOMLEFT", 0, -5)
		f:SetPoint("TOPRIGHT", t[v-1], "BOTTOMRIGHT", 0, -5)
	else
		f:SetPoint("TOPLEFT", 15, -15)
		f:SetPoint("TOPRIGHT", -15, -15)
	end
	function f:UpdateHeight()
		self:SetHeight(f.name:GetHeight())
	end
	f.name = f:CreateFontString()
	f.name:SetFont("Fonts\\FRIZQT__.TTF", 8, "OUTLINE")
	f.name:SetTextColor(1,1,1)
	f.name:SetPoint("TOPLEFT")
	f.name:SetWidth(110)
	f.name:SetJustifyH("LEFT")
	f.version = f:CreateFontString()
	f.version:SetFont("Fonts\\FRIZQT__.TTF", 8, "OUTLINE")
	f.version:SetPoint("BOTTOMLEFT", f.name, "BOTTOMRIGHT", 5, 0)
	f.version:SetPoint("TOPRIGHT")
	f.version:SetJustifyH("LEFT")
	function f:SetVersion(name, versionstring)
		if not versionstring then
			f.version:SetTextColor(0.8,0,0)
			f.name:SetText(name)
			f.version:SetText("n/a")
			f.status = "not_installed"
			GDKPd.version.notify:Enable()
			self:UpdateHeight()
			return
		end
		if versionstring == (DEBUGFORCEVERSION or "@project-version@") then
			f.version:SetTextColor(0,0.8,0)
			f.name:SetText(name)
			f.version:SetText(versionstring)
			f.status = "updated"
		elseif COMPATIBLE_VERSIONS[versionstring] then
			f.version:SetTextColor(0.8,0.8,0)
			f.name:SetText(name)
			f.version:SetText(versionstring)
			f.status = "outdated_compatible"
			GDKPd.version.notify:Enable()
		elseif INCOMPATIBLE_VERSIONS[versionstring] then
			f.version:SetTextColor(0.8,0,0)
			f.name:SetText(name)
			f.version:SetText(versionstring)
			f.status = "outdated_incompatible"
			GDKPd.version.notify:Enable()
		else
			f.version:SetTextColor(0.3,0.3,1)
			f.name:SetText(name)
			f.version:SetText(versionstring)
			f.status = "self_outdated"
		end
		self:UpdateHeight()
	end
	f:SetScript("OnEnter", function(self)
		GameTooltip:ClearAllPoints()
		GameTooltip:ClearLines()
		GameTooltip:SetOwner(self, "ANCHOR_NONE")
		GameTooltip:AddLine(L["Version status for player %s"]:format(self.name:GetText()))
		if self.status == "updated" then
			GameTooltip:AddLine(L["This player has the same version of GDKPd as you do. Full compability is ensured."])
		elseif self.status == "outdated_compatible" then
			GameTooltip:AddLine(L["This player's version of GDKPd is outdated. However, their version should be fully compatible with yours."])
		elseif self.status == "outdated_incompatible" then
			GameTooltip:AddLine(L["This player's version of GDKPd is outdated and one or more functionalities are not compatible:"])
			for _, incompatible_string in ipairs(INCOMPATIBLE_VERSIONS[f.version:GetText()]) do
				GameTooltip:AddLine(" - "..VERSIONING_STRINGS[incompatible_string])
			end
		elseif self.status == "self_outdated" then
			GameTooltip:AddLine(L["This player's version of GDKPd is more advanced than yours. Please consult your Curse Client for updates or manually check the curse.com page."])
		elseif self.status == "not_installed" then
			GameTooltip:AddLine(L["This player does not have GDKPd running or his version of GDKPd does not yet support version checks."])
		end
		GameTooltip:SetPoint("TOPRIGHT", self, "LEFT", -5, 0)
		GameTooltip:Show()
	end)
	f:SetScript("OnLeave", HideTooltipOnLeave)
	t[v] = f
	return f
end})
version.hide = CreateFrame("Button", nil, version, "UIPanelButtonTemplate")
version.hide:SetSize(170,15)
version.hide:SetPoint("BOTTOM", 0, 15)
version.hide:SetText(L["Hide"])
version.hide:SetScript("OnClick", function() version:Hide() end)
version.notify = CreateFrame("Button", nil, version, "UIPanelButtonTemplate")
version.notify:SetSize(170,15)
version.notify:SetPoint("BOTTOM", version.hide, "TOP", 0, 5)
version.notify:SetText(L["Notify outdated versions"])
version.notify:SetScript("OnClick", function()
	local c = 1
	local f = rawget(version.entries,c)
	while (f and f:IsShown()) do
		if f.status == "outdated_compatible" and GDKPd.opt.notifyVersions.notifyCompatibleOutdated then
			SendChatMessage(L["[GDKPd] Your version of GDKPd is slightly outdated compared to the raid leader's. Full compability should be possible, however, you might want to take some time and update GDKPd."], "WHISPER", nil, f.name:GetText())
		elseif f.status == "outdated_incompatible"  and GDKPd.opt.notifyVersions.notifyIncompatibleOutdated then
			SendChatMessage(L["[GDKPd] Your version of GDKPd is outdated and no longer compatible with the raid leader's in one or more functionalities. In order to ensure smooth performance, please update GDKPd."], "WHISPER", nil, f.name:GetText())
		elseif f.status == "not_installed" and GDKPd.opt.notifyVersions.notifyNotInstalled then
			SendChatMessage(L["[GDKPd] This raid uses GDKPd to faciliate its GDKP bidding process. While you can bid on items without having GDKPd installed, installing it provides you with a GUI bidding panel, auto bidding functions, auction timers, chat filtering and more!"], "WHISPER", nil, f.name:GetText())
		end
		c=c+1
		f=rawget(version.entries,c)
	end
end)
version.notify:Disable()
version.request = CreateFrame("Button", nil, version, "UIPanelButtonTemplate")
version.request:SetSize(170,15)
version.request:SetPoint("BOTTOM", version.notify, "TOP", 0, 5)
version.request:SetText(L["Request version data"])
version.request:SetScript("OnClick", function() GDKPd.hasRequestedData = true SendAddonMessage("GDKPD VREQ","hello","RAID") end)
function version:Update()
	if not GDKPd.hasRequestedData then return end
	for _, f in ipairs(self.entries) do
		f:Hide()
	end
	self.notify:Disable()
	local size = 85
	for numRaid=1, GetNumGroupMembers() do
		local pName = UnitName("raid"..numRaid)
		local f = self.entries[numRaid]
		f:Show()
		f:SetVersion(pName, GDKPd.versions[pName])
		size=size+f:GetHeight()+5
	end
	self:SetHeight(size)
end
function GDKPd:MailBalanceGold(targetName)
	local moneyToMail = GDKPd_PotData.playerBalance[targetName]
	if moneyToMail <= 0 then return end
	ClearSendMail()
	SetSendMailMoney(moneyToMail*10000)
	SendMail(targetName, "<GDKPd> "..moneyToMail.." gold")
	GDKPd_PotData.playerBalance[targetName] = 0
	self.balance:Update()
end
GDKPd.balance = CreateFrame("Frame", "GDKPd_PlayerBalance", status)
local balance = GDKPd.balance
balance:SetSize(200, 95)
balance:SetBackdrop({
	bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
	edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
	tileSize=32,
	tile=true,
	insets={
		top=12,
		bottom=12,
		right=12,
		left=12,
	},
})
balance.header = CreateFrame("Button", nil, balance)
balance.header:SetNormalTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
balance.header:SetSize(133,34)
balance.header:SetHitRectInsets(31.5,31.5,4.5,14.5)
balance.header.text = balance.header:CreateFontString()
balance.header.text:SetPoint("TOP", 0, -7)
balance.header.text:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
balance.header.text:SetTextColor(1,1,1)
balance.header.text:SetText(L["Balance"])
balance.header:SetMovable(true)
balance.header:SetScript("OnMouseDown", function(self)
	if self:IsMovable() then
		self:StartMoving()
	end
end)
balance.header:SetScript("OnMouseUp", function(self)
	if self:IsMovable() then
		self:StopMovingOrSizing()
		GDKPd.opt.balancepoint.point, _, GDKPd.opt.balancepoint.relative, GDKPd.opt.balancepoint.x, GDKPd.opt.balancepoint.y = self:GetPoint()
	end
end)
balance:SetPoint("TOP", balance.header, "TOP", 0, -6)
balance.toggle = CreateFrame("Button", nil, balance, "UIPanelButtonTemplate")
balance.toggle:SetSize(170,15)
balance.toggle:SetPoint("TOP", 0, -15)
balance.toggle:SetText(L["Toggle zero balance"])
balance.toggle:SetScript("OnClick", function() GDKPd.opt.showZeroBalance = not GDKPd.opt.showZeroBalance GDKPd.balance:Update() end)
balance:SetScript("OnShow", function(self)
	self:Update()
end)
balance.entries = setmetatable({}, {__index=function(t,v)
	local f = CreateFrame("Button", nil, balance)
	if v > 1 then
		f:SetPoint("TOPLEFT", t[v-1], "BOTTOMLEFT", 0, -5)
		f:SetPoint("TOPRIGHT", t[v-1], "BOTTOMRIGHT", 0, -5)
	else
		f:SetPoint("TOPLEFT", 15, -35)
		f:SetWidth(170)
	end
	function f:UpdateHeight()
		self:SetHeight(math.max(self.name:GetHeight(), self.amount:GetHeight()))
	end
	f.name = f:CreateFontString()
	f.name:SetPoint("TOPLEFT")
	f.name:SetPoint("BOTTOMLEFT")
	f.name:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
	f.name:SetTextColor(1,1,1)
	f.name:SetJustifyH("LEFT")
	f.amount = f:CreateFontString()
	f.amount:SetPoint("TOPLEFT", f.name, "TOPRIGHT", 5, 0)
	f.amount:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
	f.amount:SetTextColor(1,1,1)
	f.amount:SetJustifyH("RIGHT")
	f.add = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.add:SetSize(15,15)
	f.add:SetText("+")
	f.add:SetScript("OnClick", function(self)
		StaticPopup_Show("GDKPD_ADDTOPLAYER", f.name:GetText()).data=f.name:GetText()
	end)
	f.rem = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.rem:SetSize(15,15)
	f.rem:SetText("-")
	f.rem:SetScript("OnClick", function(self)
		StaticPopup_Show("GDKPD_REMFROMPLAYER", f.name:GetText()).data=f.name:GetText()
	end)
	--f.rem:SetPoint("TOPRIGHT")
	f.rem:SetPoint("RIGHT")
	f.add:SetPoint("RIGHT", f.rem, "LEFT")
	--f.add:SetPoint("BOTTOMRIGHT", f.rem, "BOTTOMLEFT")
	f.amount:SetPoint("BOTTOMRIGHT", f.add, "BOTTOMLEFT")
	function f.amount:SetAmount(gAmount)
		if gAmount > 0 then
			self:SetText("|cff00ff00"..gAmount.."|r|cffffd100g|r")
		elseif gAmount < 0 then
			self:SetText("|cffff0000"..gAmount.."|r|cffffd100g|r")
		else
			self:SetText("0|cffffd100g|r")
		end
	end
	f.mail = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.mail:SetSize(40, 15)
	f.mail:SetText(L["Mail"])
	f.mail:SetScript("OnClick", function(self)
		local targetName = f.name:GetText()
		if GDKPd.opt.confirmMail then
			StaticPopup_Show("GDKPD_MAILGOLD", GDKPd_PotData.playerBalance[targetName],targetName).data=targetName
		else
			GDKPd:MailBalanceGold(targetName)
		end
	end)
	function f.mail:UpdateState()
		local shouldDisable = (not MailFrame) or (not MailFrame:IsShown())
		shouldDisable = shouldDisable or (GDKPd_PotData.playerBalance[f.name:GetText()] <= 0)
		if shouldDisable then
			self:Disable()
			return false
		else
			self:Enable()
			return true
		end
	end
	f.mail:SetPoint("LEFT", f.rem, "RIGHT", 5, 0)
	t[v] = f
	return f
end})
function balance:UpdatePosition()
	local f = self.header
	f:ClearAllPoints()
	if not GDKPd.opt.anchorBalance then
		f:SetPoint(GDKPd.opt.balancepoint.point, UIParent, GDKPd.opt.balancepoint.relative, GDKPd.opt.balancepoint.x, GDKPd.opt.balancepoint.y)
		f:SetMovable(true)
	else
		f:SetPoint("TOP", status, "BOTTOM", 0, -15)
		f:StopMovingOrSizing()
		f:SetMovable(false)
	end
end
function balance:Update()
	for _, f in ipairs(self.entries) do
		f:Hide()
	end
	local c = 1
	local size = 50
	local isWidthIncreased = false
	if (GDKPd.isTrading) then
		local f = self.entries[c]
		f:Show()
		f.amount:SetAmount(GDKPd_PotData.playerBalance[(UnitName("NPC"))])
		f.name:SetText((UnitName("NPC")))
		f:UpdateHeight()
		isWidthIncreased = f.mail:UpdateState() or isWidthIncreased
		c = c+1
		size=size+f:GetHeight()+5
	end
	for name, amount in pairs(GDKPd_PotData.playerBalance) do
		if ((not GDKPd.isTrading) or (name ~= (UnitName("NPC")))) and (amount ~= 0) and (name ~= (UnitName("player"))) then
			local f = self.entries[c]
			f:Show()
			f.name:SetText(name)
			f.amount:SetAmount(amount)
			f:UpdateHeight()
			isWidthIncreased = f.mail:UpdateState() or isWidthIncreased
			c = c+1
			size=size+f:GetHeight()+5
		end
	end
	if GDKPd.opt.showZeroBalance then
		for raidNum=1, GetNumGroupMembers() do
			local name = UnitName("raid"..raidNum)
			if (not UnitIsUnit("player","raid"..raidNum)) and (GDKPd_PotData.playerBalance[name] == 0) then
				local f = self.entries[c]
				f:Show()
				f.name:SetText(name)
				f.amount:SetAmount(0)
				f:UpdateHeight()
				isWidthIncreased = f.mail:UpdateState() or isWidthIncreased
				c = c+1
				size=size+f:GetHeight()+5
			end
		end
	end
	self:SetHeight(size)
	if isWidthIncreased then
		for _, f in ipairs(self.entries) do
			f.mail:Show()
		end
		self:SetWidth(245)
	else
		for _, f in ipairs(self.entries) do
			f.mail:Hide()
		end
		self:SetWidth(200)
	end
end
GDKPd.playerBalance = CreateFrame("Frame", "GDKPd_PlayerBalance", UIParent)
local playerBalance = GDKPd.playerBalance
playerBalance:SetSize(200, 95)
playerBalance:SetBackdrop({
	bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
	edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
	tileSize=32,
	tile=true,
	insets={
		top=12,
		bottom=12,
		right=12,
		left=12,
	},
})
playerBalance.header = CreateFrame("Button", nil, playerBalance)
playerBalance.header:SetNormalTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
playerBalance.header:SetSize(133,34)
playerBalance.header:SetHitRectInsets(31.5,31.5,4.5,14.5)
playerBalance.header.text = playerBalance.header:CreateFontString()
playerBalance.header.text:SetPoint("TOP", 0, -7)
playerBalance.header.text:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
playerBalance.header.text:SetTextColor(1,1,1)
playerBalance.header.text:SetText(L["Player balance"])
playerBalance.header:SetMovable(true)
playerBalance.header:SetScript("OnMouseDown", function(self)
	self:StartMoving()
end)
playerBalance.header:SetScript("OnMouseUp", function(self)
	self:StopMovingOrSizing()
	GDKPd.opt.playerbalancepoint.point, _, GDKPd.opt.playerbalancepoint.relative, GDKPd.opt.playerbalancepoint.x, GDKPd.opt.playerbalancepoint.y = self:GetPoint()
end)
playerBalance:SetPoint("TOP", playerBalance.header, "TOP", 0, -6)
playerBalance:SetScript("OnShow", function(self)
	self:Update()
end)
playerBalance.reset = CreateFrame("Button", nil, playerBalance, "UIPanelButtonTemplate")
playerBalance.reset:SetSize(170,15)
playerBalance.reset:SetPoint("BOTTOM", 0, 15)
playerBalance.reset:SetText(RESET)
playerBalance.reset:SetScript("OnClick", function() GDKPd_BalanceData = setmetatable({},{__index=function() return 0 end}) GDKPd.playerBalance:Update() end)
playerBalance.entries = setmetatable({}, {__index=function(t,v)
	local f = CreateFrame("Button", nil, playerBalance)
	if v > 1 then
		f:SetPoint("TOPLEFT", t[v-1], "BOTTOMLEFT", 0, -5)
		f:SetPoint("TOPRIGHT", t[v-1], "BOTTOMRIGHT", 0, -5)
	else
		f:SetPoint("TOPLEFT", 15, -15)
		f:SetPoint("TOPRIGHT", -15, -15)
	end
	function f:UpdateHeight()
		self:SetHeight(math.max(self.name:GetHeight(), self.amount:GetHeight()))
	end
	f.name = f:CreateFontString()
	f.name:SetPoint("TOPLEFT")
	f.name:SetPoint("BOTTOMLEFT")
	f.name:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
	f.name:SetTextColor(1,1,1)
	f.name:SetJustifyH("LEFT")
	f.amount = f:CreateFontString()
	f.amount:SetPoint("TOPLEFT", f.name, "TOPRIGHT", 5, 0)
	f.amount:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
	f.amount:SetTextColor(1,1,1)
	f.amount:SetJustifyH("RIGHT")
	f.amount:SetPoint("BOTTOMRIGHT")
	function f.amount:SetAmount(gAmount)
		if gAmount > 0 then
			self:SetText("|cff00ff00"..gAmount.."|r|cffffd100g|r")
		elseif gAmount < 0 then
			self:SetText("|cffff0000"..gAmount.."|r|cffffd100g|r")
		else
			self:SetText("0|cffffd100g|r")
		end
	end
	t[v] = f
	return f
end})
function playerBalance:UpdateVisibility(forceCombat)
	if GDKPd.opt.hide then
		self:Hide()
		return
	end
	if (self:GetHeight() > 50) and ((not GDKPd.opt.hideCombat.status) or (not (forceCombat~=nil and forceCombat or InCombatLockdown()))) then
		self:Show()
	else
		self:Hide()
	end
end
function playerBalance:Update()
	for _, f in ipairs(self.entries) do
		f:Hide()
	end
	local c = 1
	local size = 45
	if (GDKPd.isTrading) then
		local f = self.entries[c]
		f:Show()
		f.amount:SetAmount(GDKPd_BalanceData[(UnitName("NPC"))])
		f.name:SetText((UnitName("NPC")))
		f:UpdateHeight()
		c = c+1
		size=size+f:GetHeight()+5
	end
	for name, amount in pairs(GDKPd_BalanceData) do
		if ((not GDKPd.isTrading) or (name ~= (UnitName("NPC")))) and (amount ~= 0) and (name ~= (UnitName("player"))) then
			local f = self.entries[c]
			f:Show()
			f.name:SetText(name)
			f.amount:SetAmount(amount)
			f:UpdateHeight()
			c = c+1
			size=size+f:GetHeight()+5
		end
	end
	self:SetHeight(size)
	self:UpdateVisibility()
end
GDKPd.exportframe = CreateFrame("Frame", "GDKPd_Export", UIParent)
local export = GDKPd.exportframe
export:Hide()
export:SetBackdrop({
	bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
	edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
	tileSize=32,
	tile=true,
	insets={
		top=12,
		bottom=12,
		right=12,
		left=12,
	},
})
export.header = CreateFrame("Button", nil, export)
export.header:SetNormalTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
export.header:SetSize(133,34)
export.header:SetHitRectInsets(31.5,31.5,4.5,14.5)
export.header.text = export.header:CreateFontString()
export.header.text:SetPoint("TOP", 0, -7)
export.header.text:SetFont("Fonts\\FRIZQT__.TTF", 8, "")
export.header.text:SetTextColor(1,1,1)
export.header.text:SetText(L["Pot export"])
export.header:SetMovable(true)
export.header:SetScript("OnMouseDown", function(self)
	self:StartMoving()
end)
export.header:SetScript("OnMouseUp", function(self)
	self:StopMovingOrSizing()
end)
export.header:SetPoint("TOP", history, "BOTTOM", 0, -10)
export.box = CreateFrame("EditBox", nil, export)
export.box:SetMultiLine(true)
export.box:SetAutoFocus(false)
export.box:SetFont("Fonts\\FRIZQT__.TTF", 12)
export.box:SetPoint("TOP", export.header, "TOP", 0, -21)
export.box:SetJustifyH("LEFT")
export.box:SetWidth(50)
do
	local st = export.box.SetText
	local dummy_text = UIParent:CreateFontString()
	dummy_text:SetFont("Fonts\\FRIZQT__.TTF", 12)
	function export.box:SetText(text)
		dummy_text:SetText(text)
		self:SetWidth(dummy_text:GetStringWidth())
		self.text = text
		st(self, text)
	end
end
export.box:SetScript("OnTextChanged", function(self, userInput)
	if userInput then
		self:SetText(self.text or "")
	end
	self:HighlightText()
	self:SetFocus()
end)
export.box:SetScript("OnEscapePressed", function(self)
	self:ClearFocus()
	export:Hide()
end)
export.box:SetScript("OnEnterPressed", function(self)
	self:ClearFocus()
end)
export:SetPoint("TOPLEFT", export.box, "TOPLEFT", -15, 15)
export:SetPoint("BOTTOMRIGHT", export.box, "BOTTOMRIGHT", 15, -15)

export.toggleBB = CreateFrame("Button", nil, export, "UIPanelButtonTemplate")
export.toggleBB:SetSize(150,20)
export.toggleBB:SetPoint("TOP", export, "BOTTOM", 0, 10)
export.toggleBB:SetText("BBCode")
export.toggleBB:SetScript("OnClick", function() export:SetType('BB') end)

export.toggleDefault = CreateFrame("Button", nil, export, "UIPanelButtonTemplate")
export.toggleDefault:SetSize(150,20)
export.toggleDefault:SetPoint("RIGHT",export.toggleBB,"LEFT")
export.toggleDefault:SetText("Plain text")
export.toggleDefault:SetScript("OnClick", function() export:SetType('Default') end)

export.toggleBN = CreateFrame("Button", nil, export, "UIPanelButtonTemplate")
export.toggleBN:SetSize(150,20)
export.toggleBN:SetPoint("LEFT",export.toggleBB,"RIGHT")
export.toggleBN:SetText("Battle.net forums")
export.toggleBN:SetScript("OnClick",function() export:SetType('BN') end)

function export:Update()
	local text = self.header
	for _, aucdata in ipairs(self.data) do
		if type(aucdata) == "table" then
			if self.exportType == "BB" then
				text = text.."\n[color=#"..aucdata.item:match("|c[fF][fF]([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])").."][url=http://classic.wowhead.com/item="..aucdata.item:match("|Hitem:(%d+):").."]"..(aucdata.item:match("(|h.+|h)")).."[/url][/color]: "..aucdata.name.." ("..aucdata.bid.." gold)"
			elseif self.exportType == "BN" then
				text = text.."\n[item=\""..aucdata.item:match("|Hitem:(%d+):").."\" /]: "..aucdata.name.." ("..aucdata.bid.." gold)"
			else
				text = text.."\n"..(aucdata.item:match("(|h.+|h)"))..": "..aucdata.name.." ("..aucdata.bid.." gold)"
			end
		else
			text = text.."\n"..L["Manual adjustment"]..": "..(aucdata > 0 and "+" or "")..aucdata.." gold"
		end
	end
	self.box:SetText(text)
end

function export:Set(header,data)
	self.header = header
	self.data = data
	self:Update()
end

function export:SetType(t)
	self["toggle"..self.exportType]:UnlockHighlight()
	self.exportType = t
	self["toggle"..t]:LockHighlight()
	self:Update()
end
export.exportType = "Default"
export.toggleDefault:LockHighlight()

function GDKPd:SetMovable(movable)
	if movable then
		anchor:EnableMouse(true)
		anchor:Show()
	else
		anchor:EnableMouse(false)
		anchor:Hide()
	end
end
function GDKPd:GetStartBid(link)
	for _,filter in ipairs(GDKPd.opt.filteredSettings) do
		if filter.enable and filter.setStartBid and #filter.rules > 0 then
			local m = true
			for _,rule in ipairs(filter.rules) do
				if not itemFilters[rule.ruleName].func(link,rule.ruleArgs) then
					m = false
					break
				end
			end
			if m then
				return filter.startBid
			end
		end
	end
	return self.opt.startBid
end
function GDKPd:GetMinIncrement(link)
	for _,filter in ipairs(GDKPd.opt.filteredSettings) do
		if filter.enable and filter.setIncrement and #filter.rules > 0 then
			local m = true
			for _,rule in ipairs(filter.rules) do
				if not itemFilters[rule.ruleName].func(link,rule.ruleArgs) then
					m = false
					break
				end
			end
			if m then
				return filter.increment
			end
		end
	end
	return self.opt.increment
end
function GDKPd:FetchFrameFromLink(itemLink)
	for num, frame in ipairs(GDKPd.frames) do
		if (frame.itemlink == itemLink) and frame.isActive then
			return frame,num
		end
	end
end
function GDKPd:PlayerIsML(playerName, invert)
	for raidID = (invert and GetNumGroupMembers() or 1), (invert and 1 or GetNumGroupMembers()), (invert and -1 or 1) do
		local name, _, _, _, _,_,_,_,_,_,isML = GetRaidRosterInfo(raidID)
		if playerName == name then
			return isML
		end
	end
end
function GDKPd:AnnounceLoot(shouldQueueAuctions)
	if GetNumLootItems() <= 0 then return end
	local lootList = emptytable()
	local minQuality = (self.opt.minQuality == -1 and GetLootThreshold() or self.opt.minQuality)
	local playerName = (UnitName("player"))
	for numLoot=1, GetNumLootItems() do
		if LootSlotHasItem(numLoot) then
			local tex, item, quantity, currency, quality, isLocked = GetLootSlotInfo(numLoot)
			if quality >= minQuality then
				tinsert(lootList, GetLootSlotLink(numLoot))
				if self.opt.awardToML then
					local candidateIndex = 1
					local candidateName = GetMasterLootCandidate(numLoot,candidateIndex)
					while candidateName do
						if candidateName == playerName then
							GiveMasterLoot(numLoot,candidateIndex)
							break
						end
						candidateIndex = candidateIndex + 1
						candidateName = GetMasterLootCandidate(numLoot,candidateIndex)
					end
				end
			end
		end
	end
    if #lootList > 0 then
        local lootString = L["[GDKPd] Loot dropped: "]..lootList[1]
        for lootNum, link in ipairs(lootList) do
            if lootNum > 1 then
                if strlen(lootString)+strlen(link)+2 > 255 then
                    SendChatMessage(lootString,"RAID")
                    lootString=link
                else
                    lootString=lootString..", "..link
                end
            end
        end
        SendChatMessage(lootString, "RAID")
        for _, itemLink in ipairs(lootList) do
            if shouldQueueAuctions then
                GDKPd:QueueAuction(itemLink, GDKPd:GetStartBid(itemLink), GDKPd:GetMinIncrement(itemLink))
            else
                SendAddonMessage("GDKPD START", itemLink, "RAID")
            end
        end
    end
	lootList:Release()
end
function GDKPd:QueueAuction(item, minbid, increment)
	if (not GDKPd.curAuction.item) or GDKPd.opt.allowMultipleAuctions then
		GDKPd:AuctionOffItem(item, minbid, increment)
	else
		SendAddonMessage("GDKPD START", item, "RAID")
		tinsert(GDKPd.auctionList,emptytable(item,minbid,increment))
	end
end
function GDKPd:AuctionOffItem(item, minbid, increment)
	if (GDKPd.curAuction.item) and (not self.opt.allowMultipleAuctions) then return end
	if (self.opt.allowMultipleAuctions) and (self.curAuctions[item]) then return end
	if (not self.opt.allowMultipleAuctions) then
		-- old code
		SendChatMessage(("[GDKPd] Bidding starts on %s. Please bid in raid chat, starting bid %d gold, minimum increment %d gold. TTL: %d/%d"):format(item,minbid,increment,self.opt.auctionTimer, self.opt.auctionTimerRefresh), (self.opt.announceRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
		GDKPd.curAuction.item = item
		GDKPd.curAuction.curBid = (minbid-increment)
		GDKPd.curAuction.increment = increment
		GDKPd.curAuction.bidders = emptytable()
		GDKPd.curAuction.timeRemains = self.opt.auctionTimer
	else
		-- new code
		SendChatMessage(("[GDKPd] Bidding starts on %s. Bid using format '[item] 1000', starting bid %d gold, minimum increment %d gold. TTL: %d/%d"):format(item,minbid,increment,self.opt.auctionTimer, self.opt.auctionTimerRefresh), (self.opt.announceRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
		local aucTable = emptytable()
		aucTable.item = item
		aucTable.curBid = (minbid-increment)
		aucTable.increment = increment
		aucTable.bidders = emptytable()
		aucTable.timeRemains = self.opt.auctionTimer
		GDKPd.curAuctions[item] = aucTable
	end
	GDKPd:Show()
end
function GDKPd:RevertHighestBid(link)
	if self.opt.allowMultipleAuctions then
		if not link then return end
		local aucdata = self.curAuctions[link]
		if not aucdata then return end
		if #aucdata.bidders < 2 then return end
		table.sort(aucdata.bidders, function(a,b) return a.bidAmount > b.bidAmount end)
		aucdata.bidders[aucdata.bidders[1].bidderName] = nil
		tremove(aucdata.bidders,1)
		SendChatMessage(("[GDKPd] New highest bidder on %s: %s (%d gold)"):format(link, aucdata.bidders[1].bidderName, aucdata.bidders[1].bidAmount), (self.opt.announceBidRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
		-- fix name-to-index assigns
		for num, t in ipairs(aucdata.bidders) do
			aucdata.bidders[t.bidderName] = num
		end
		aucdata.timeRemains = math.max(aucdata.timeRemains, self.opt.auctionTimerRefresh)
		aucdata.curBid = aucdata.bidders[1].bidAmount
	else
		if #self.curAuction.bidders < 2 then return end
		table.sort(self.curAuction.bidders, function(a,b) return a.bidAmount > b.bidAmount end)
		self.curAuction.bidders[self.curAuction.bidders[1].bidderName] = nil
		tremove(self.curAuction.bidders, 1)
		SendChatMessage(("[GDKPd] New highest bidder: %s (%d gold)"):format(self.curAuction.bidders[1].bidderName, self.curAuction.bidders[1].bidAmount), (self.opt.announceBidRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
		for num, t in ipairs(self.curAuction.bidders) do
			self.curAuction.bidders[t.bidderName] = num
		end
		self.curAuction.timeRemains = math.max(self.curAuction.timeRemains, self.opt.auctionTimerRefresh)
		self.curAuction.curBid = self.curAuction.bidders[1].bidAmount
	end
end
function GDKPd:CancelAuction(link)
	if self.opt.allowMultipleAuctions then
		if not link then return end
		local aucdata = self.curAuctions[link]
		if not aucdata then return end
		SendChatMessage(("[GDKPd] Auction cancelled for %s."):format(link), (self.opt.announceRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
		self.curAuctions[link] = nil
	else
		SendChatMessage("[GDKPd] Auction cancelled.", (self.opt.announceRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
		table.wipe(self.curAuction)
		if self.auctionList[1] then
			self:AuctionOffItem(unpack(self.auctionList[1]))
			self.auctionList[1]:Release()
			tremove(self.auctionList,1)
		end
	end
end
function GDKPd:FinishAuction(link)
	if self.opt.allowMultipleAuctions then
		-- new code
		if not link then return end
		local aucdata = self.curAuctions[link]
		if aucdata then
			table.sort(aucdata.bidders, function(a,b) return a.bidAmount > b.bidAmount end)
			if aucdata.bidders[1] then
				local totalAmount = aucdata.bidders[1].bidAmount
				local remAmount = totalAmount
				local paymentString = "%d to pot"
				if self.opt.shareSecondEnable and aucdata.bidders[2] then
					local secondShare = round(totalAmount*self.opt.shareSecondAmount)
					remAmount = remAmount-secondShare
					paymentString = paymentString..", "..secondShare.." to "..aucdata.bidders[2].bidderName
				end
				if self.opt.shareThirdEnable and aucdata.bidders[3] then
					local thirdShare = round(totalAmount*self.opt.shareThirdAmount)
					remAmount = remAmount-thirdShare
					paymentString = paymentString..", "..thirdShare.." to "..aucdata.bidders[3].bidderName
				end
				paymentString = paymentString:format(remAmount)
				SendChatMessage(("[GDKPd] Auction finished for %s. Winner: %s. %s."):format(link, aucdata.bidders[1].bidderName, paymentString),"RAID")
				GDKPd_PotData.potAmount = (GDKPd_PotData.potAmount or 0)+remAmount
				GDKPd_PotData.playerBalance[aucdata.bidders[1].bidderName] = GDKPd_PotData.playerBalance[aucdata.bidders[1].bidderName] -remAmount
				GDKPd.balance:Update()
				if self.opt.announcePotAfterAuction then
					SendChatMessage("[GDKPd] Current pot: "..GDKPd_PotData.potAmount.." gold","RAID")
				end
				tinsert(GDKPd_PotData.curPotHistory, {item=link, bid=totalAmount, name=aucdata.bidders[1].bidderName})
				self.status:Update()
				if self.opt.autoAwardLoot then
					local bestBidderName = aucdata.bidders[1].bidderName
					for lootSlot = 1, GetNumLootItems() do
						if GetLootSlotLink(lootSlot) == link then
							local candidateIndex = 1
							local candidateName = GetMasterLootCandidate(lootSlot,candidateIndex)
							while candidateName do
								if candidateName == bestBidderName then
									GiveMasterLoot(lootSlot,candidateIndex)
									break
								end
								candidateIndex = candidateIndex + 1
								candidateName = GetMasterLootCandidate(candidateIndex)
							end
							break
						end
					end
				end
			else
				SendChatMessage(("[GDKPd] Auction finished for %s. No bids recieved."):format(link),"RAID")
			end
			aucdata:Release()
		end
		self.curAuctions[link] = nil
	else
		-- old code
		table.sort(self.curAuction.bidders, function(a,b) return a.bidAmount > b.bidAmount end)
		if self.curAuction.bidders[1] then
			local totalAmount = self.curAuction.bidders[1].bidAmount
			local remAmount = totalAmount
			local paymentString = "%d to pot"
			if self.opt.shareSecondEnable and self.curAuction.bidders[2] then
				local secondShare = round(totalAmount*self.opt.shareSecondAmount)
				remAmount = remAmount-secondShare
				paymentString = paymentString..", "..secondShare.." to "..self.curAuction.bidders[2].bidderName
			end
			if self.opt.shareThirdEnable and self.curAuction.bidders[3] then
				local thirdShare = round(totalAmount*self.opt.shareThirdAmount)
				remAmount = remAmount-thirdShare
				paymentString = paymentString..", "..thirdShare.." to "..self.curAuction.bidders[3].bidderName
			end
			paymentString = paymentString:format(remAmount)
			SendChatMessage(("[GDKPd] Auction finished. Winner: %s. %s."):format(self.curAuction.bidders[1].bidderName, paymentString),"RAID")
			GDKPd_PotData.potAmount = (GDKPd_PotData.potAmount or 0)+remAmount
			GDKPd_PotData.playerBalance[self.curAuction.bidders[1].bidderName] = GDKPd_PotData.playerBalance[self.curAuction.bidders[1].bidderName] -remAmount
			GDKPd.balance:Update()
			if self.opt.announcePotAfterAuction then
				SendChatMessage("[GDKPd] Current pot: "..GDKPd_PotData.potAmount.." gold","RAID")
			end
			tinsert(GDKPd_PotData.curPotHistory, {item=self.curAuction.item, bid=totalAmount, name=self.curAuction.bidders[1].bidderName})
			self.status:Update()
			if self.opt.autoAwardLoot then
				local bestBidderName = self.curAuction.bidders[1].bidderName
				local candidateIndex = 1
				local candidateName = GetMasterLootCandidate(candidateIndex)
				while candidateName do
					if candidateName == bestBidderName then
						for lootSlot = 1, GetNumLootItems() do
							if GetLootSlotLink(lootSlot) == self.curAuction.item then
								GiveMasterLoot(lootSlot,candidateIndex)
								break
							end
						end
						break
					end
					candidateIndex = candidateIndex + 1
					candidateName = GetMasterLootCandidate(candidateIndex)
				end
			end
		else
			SendChatMessage("[GDKPd] Auction finished. No bids recieved.","RAID")
		end
		self.curAuction.bidders:Release()
		table.wipe(self.curAuction)
		if self.auctionList[1] then
			self:AuctionOffItem(unpack(self.auctionList[1]))
			self.auctionList[1]:Release()
			tremove(self.auctionList,1)
		end
	end
end
function GDKPd:DistributePot()
	local numraid = GetNumGroupMembers()
	if not (numraid > 0) then return end
	local distAmount = (GDKPd_PotData.potAmount or 0)-(GDKPd_PotData.prevDist or 0)
	if distAmount <= 0 then return end
    local amt = math.floor(distAmount/numraid)
	SendChatMessage(("[GDKPd] Distributing pot. Pot size: %d gold. Amount to distribute: %d gold. Players in raid: %d. Share per player: %d gold."):format((GDKPd_PotData.potAmount or 0), distAmount, numraid, amt), "RAID")
	for numRaid=1, numraid do
		GDKPd_PotData.playerBalance[(UnitName("raid"..numRaid))] = (GDKPd_PotData.playerBalance[(UnitName("raid"..numRaid))] + amt)
	end
	GDKPd_PotData.prevDist = GDKPd_PotData.potAmount
	GDKPd.balance:Update()
    GDKPd.status:Update()
end
function GDKPd:GetUnoccupiedFrame()
	local c = 1
	while GDKPd.frames[c] do
		if not GDKPd.frames[c]:IsShown() then
			GDKPd.frames[c].hide:Disable()
			GDKPd.frames[c].bidbox:SetNumber(0)
			GDKPd.frames[c].autobid:Disable()
			GDKPd.frames[c].bidbox:Hide()
			GDKPd.frames[c].bid:Disable()
			GDKPd.frames[c].itemlink = nil
			GDKPd.frames[c].maxAutoBid = nil
			GDKPd.frames[c].curbidamount = nil
			GDKPd.frames[c].curbidismine = nil
			GDKPd.frames[c].bidIncrement = nil
			GDKPd.frames[c].initialBid = nil
			GDKPd.frames[c].autobid:Show()
			GDKPd.frames[c].stopautobid:Hide()
			GDKPd.frames[c].curbid:Hide()
			GDKPd.frames[c].isActive = false
			GDKPd.frames[c].restartAuction:Hide()
			GDKPd.frames[c].bigHide:Hide()
			if (GDKPd:PlayerIsML((UnitName("player")),true) and (not GDKPd.opt.slimML)) then
				GDKPd.frames[c].cancelAuction:Show()
				GDKPd.frames[c].reverseBid:Show()
			else
				GDKPd.frames[c].cancelAuction:Hide()
				GDKPd.frames[c].reverseBid:Hide()
			end
			GDKPd.frames[c].reverseBid:Disable()
			GDKPd.frames[c]:UpdateSize()
			return GDKPd.frames[c]
		end
		c=c+1
	end
	local f = CreateFrame("Frame", "GDKPdBidFrame"..c, UIParent)
	f:SetSize(300,60)
	f:SetBackdrop({
		bgFile="Interface\\Tooltips\\UI-Tooltip-Background",
		tileSize=16,
		edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
		tile=true,
		edgeSize=16,
		insets={top=5,bottom=5,left=5,right=5},
	})
	if c > 1 then
		f:SetPoint("TOPLEFT", GDKPd.frames[c-1], "BOTTOMLEFT")
	else
		f:SetPoint("TOPLEFT", anchor, "TOPLEFT")
	end
	--f:SetPoint("TOPLEFT", anchor, "TOPLEFT", 0, (-60)*(c-1))
	f:Hide()
	f:SetFrameStrata("DIALOG")
	f.icon = f:CreateTexture()
	f.icon:SetSize(40,40)
	f.icon:SetColorTexture(1,1,1)
	f.icon:SetPoint("TOPLEFT", 10, -10)
	f.itemstring = f:CreateFontString()
	f.itemstring:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE")
	f.itemstring:SetTextColor(1,1,1)
	f.itemstring:SetPoint("TOPLEFT", f.icon, "TOPRIGHT", 5, 0)
	f.itemstring:SetWidth(160)
	f.itemstring:SetWordWrap(false)
	f.itemstring:SetJustifyH("LEFT")
	f.curbid = f:CreateFontString()
	f.curbid:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
	f.curbid:SetTextColor(1,1,1)
	f.curbid:SetPoint("TOPLEFT", f.itemstring, "BOTTOMLEFT", 0, -5)
	f.curbid:Hide()
	f.highestbid = f:CreateFontString()
	f.highestbid:SetFont("Fonts\\FRIZQT__.TTF", 10, "OUTLINE")
	f.highestbid:SetTextColor(0,0.8,0)
	f.highestbid:SetPoint("TOPLEFT", f.curbid, "BOTTOMLEFT", 0, -5)
	f.highestbid:SetText("You are the top bidder!")
	f.highestbidder = f:CreateFontString()
	f.highestbidder:SetFont("Fonts\\FRIZQT__.TTF", 10, "")
	f.highestbidder:SetTextColor(1,1,1)
	f.highestbidder:SetPoint("TOPLEFT", f.curbid, "BOTTOMLEFT", 0, -5)
	f.timer = CreateFrame("Cooldown",nil,f)
	-- omnicc stuff
	f.timer.noCooldownCount = true
	f.timer:SetReverse(true)
	f.timer:SetAllPoints(f.icon)
	f.timer.update = CreateFrame("Frame")
	f.timer.update:Hide()
	f.timer.update:SetScript("OnUpdate", function(self)
		local timeRemain = self.endTime-GetTime()
		if timeRemain <= 0 then
			self:Hide()
			f.timer.text:Hide()
		end
		if timeRemain%1 > 0.5 then
			f.timer.text:SetTextColor(1,0,0)
		else
			f.timer.text:SetTextColor(1,1,0)
		end
		f.timer.text:SetText(math.ceil(timeRemain))
	end)
	f.timer.text = f.timer:CreateFontString()
	f.timer.text:SetFont("Fonts\\FRIZQT__.TTF", GetCVarBool("useUiScale") and (32*(GetCVar("uiScale") or 1)) or 28, "OUTLINE")
	f.timer.text:SetAllPoints()
	f.timer.text:Hide()
	f.autobid = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.autobid:SetText(L["Auto bid"])
	f.autobid:SetSize(70, 16)
	f.autobid:SetScript("OnClick", function(self)
		StaticPopup_Show("GDKPD_AUTOBID", f.itemlink).data=f
		f.hide:Disable()
	end)
	f.autobid:SetPoint("TOPRIGHT", -10, -10)
	f.stopautobid = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.stopautobid:SetText(L["Stop bid"])
	f.stopautobid:SetAllPoints(f.autobid)
	f.stopautobid:Hide()
	f.stopautobid:SetScript("OnClick", function(self)
		self:Hide()
		f.maxAutoBid = nil
		f.autobid:Show()
		f.hide:Enable()
	end)
	f.bidbox = CreateFrame("EditBox", nil, f)
	f.bidbox:SetMultiLine(nil)
	f.bidbox:SetScript("OnEditFocusGained", function(self)
		if self.disabled then
			self:ClearFocus()
		end
	end)
	function f.bidbox:Enable()
		self.disabled = false
	end
	function f.bidbox:Disable()
		self.disabled = true
	end
	f.bidbox:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
	f.bidbox:SetScript("OnEnterPressed", function(self)
		self:ClearFocus()
		local wantBid = self:GetNumber()
		if wantBid >= (f.bidIncrement+f.curbidamount) then
			SendChatMessage((f.isMultiBid and f.itemlink.." " or "")..wantBid, "RAID")
		end
		self:SetNumber(0)
	end)
	f.bidbox:SetBackdrop({bgFile="Interface\\ChatFrame\\UI-ChatInputBorder",tile=false})
	f.bidbox:SetTextInsets(5,5,2,2)
	f.bidbox:SetSize(40,16)
	f.bidbox:SetFont("Fonts\\FRIZQT__.TTF", 9)
	f.bidbox:SetAutoFocus(false)
	f.bidbox:SetPoint("LEFT", f.curbid, "RIGHT", 5, 0)
	f.bidbox:SetJustifyH("RIGHT")
	f.bidbox:SetNumeric(true)
	f.bidbox:SetNumber(0)
	f.bidbox:Hide()
	f.bid = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.bid:SetText(L["Bid"])
	f.bid:SetSize(70,16)
	f.bid:SetPoint("TOP", f.autobid, "BOTTOM", 0, -8)
	f.bid:SetScript("OnClick", function(self)
		local newBid = f.curbidamount + f.bidIncrement
		if f.isMultiBid then
			SendChatMessage(f.itemlink.." "..newBid,"RAID")
		else
			SendChatMessage(tostring(newBid),"RAID")
		end
	end)
	f.bid:Disable()
	f.bid.enabledelay = CreateFrame("Frame", nil, f.bid)
	f.bid.enabledelay:Hide()
	f.bid.enabledelay:SetScript("OnUpdate", function(self)
		if not self.reenabletime then self:Hide() return end
		if GetTime() >= self.reenabletime then f.bid:Enable() self.reenabletime = nil self:Hide() end
	end)
	--f.hide = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.hide = CreateFrame("Button", nil, f, "UIPanelCloseButton")
	--f.hide:SetText(L["Hide"])
	f.hide:SetSize(16,16)
	f.hide:SetPoint("TOPRIGHT")
	f.hide:SetScript("OnClick", function(self)
		GDKPd.ignoredLinks[f.itemlink] = true
		f:Hide()
	end)
	f.hide:SetScript("OnEnter", function(self)
		self:SetAlpha(1)
	end)
	f.hide:SetScript("OnLeave", function(self)
		if (not GDKPd.opt.forceHideShow) then
			self:SetAlpha(0)
		end
	end)
	f.hide:SetAlpha(GDKPd.opt.forceHideShow and 1 or 0)
	f.hide:SetDisabledTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Disabled")
	f.autobid:Disable()
	f.hide:Disable()
	f.bigHide = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.bigHide:SetText(L["Hide"])
	f.bigHide:SetHeight(15)
	f.bigHide:SetPoint("BOTTOMLEFT", 10, 10)
	f.bigHide:SetPoint("BOTTOMRIGHT", -10, 10)
	f.bigHide:SetScript("OnClick", function(self)
		f:Hide()
	end)
	f.bigHide:Hide()
	f.restartAuction = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.restartAuction:SetText(L["Restart auction"])
	f.restartAuction:SetHeight(15)
	f.restartAuction:SetPoint("BOTTOMLEFT", f.bigHide, "TOPLEFT", 0, 5)
	f.restartAuction:SetPoint("BOTTOMRIGHT", f.bigHide, "TOPRIGHT", 0, 5)
	f.restartAuction:SetScript("OnClick", function(self)
		f:Hide()
		local itemLink = f.itemlink
		GDKPd:QueueAuction(itemLink, GDKPd:GetStartBid(itemLink), GDKPd:GetMinIncrement(itemLink))
	end)
	f.restartAuction:Hide()
	f.cancelAuction = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.cancelAuction:SetText(L["Cancel auction"])
	f.cancelAuction:SetAllPoints(f.restartAuction)
	f.cancelAuction:SetScript("OnClick", function(self)
		GDKPd:CancelAuction(f.itemlink)
		self:Hide()
		f.reverseBid:Hide()
		f.bigHide:Show()
		f.restartAuction:Show()
	end)
	f.reverseBid = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
	f.reverseBid:SetText(L["Revert highest bid"])
	f.reverseBid:SetAllPoints(f.bigHide)
	f.reverseBid:SetScript("OnClick", function(self)
		GDKPd:RevertHighestBid(f.itemlink)
	end)
	if (not self:PlayerIsML((UnitName("player")), true)) or self.opt.slimML then
		f.cancelAuction:Hide()
		f.reverseBid:Hide()
	end
	f.reverseBid:Disable()
	function f:SetItem(itemlink)
		self.icon:SetTexture((select(10,GetItemInfo(itemlink))))
		self.itemstring:SetText(itemlink)
		self:EnableMouse(true)
		self.autobid:Enable()
		self.bidbox:Enable()
		self.hide:Enable()
		self.highestbid:Hide()
		self.itemlink = itemlink
	end
	function f:SetCurBid(goldAmount, bidderName, isMine, isInitial)
		self.curbid:SetText((isInitial and L["Minimum bid: "] or L["Current bid: "])..goldAmount.."|cffffd100g|r")
		if bidderName and (not isMine) then
			self.highestbidder:Show()
			self.highestbidder:SetText(L["Highest bidder: %s"]:format(bidderName))
			self.highestbid:Hide()
		elseif isMine then
			self.highestbid:Show()
			self.highestbidder:Hide()
		else
			self.highestbid:Hide()
			self.highestbidder:Hide()
		end
		self.curbidamount = goldAmount-(isInitial and self.bidIncrement or 0)
		self.curbidismine = not not isMine
		self.curbid:Show()
		self.bidbox:Show()
		self.bid:Enable()
		if not isInitial then
			self.bid:Disable()
			if not isMine then
				self.bid.enabledelay.reenabletime = GetTime()+GDKPd.opt.bidButtonReenableDelay
				self.bid.enabledelay:Show()
			end
			if goldAmount > (self.initialBid or math.huge) then
				self.reverseBid:Enable()
			end
		else
			self.initialBid = goldAmount
		end
	end
	function f:SetAuctionTimer(timerDuration, timerResetDuration)
		if (not timerDuration) then return end
		local ctime = GetTime()
		self.timer:SetCooldown(ctime, timerDuration)
		self.timer.update.endTime = ctime+timerDuration
		self.timer[GDKPd.opt.showAuctionDurationTimer and "Show" or "Hide"](self.timer)
		self.timer.text[GDKPd.opt.showAuctionDurationTimerText and "Show" or "Hide"](self.timer.text)
		self.timer.update[GDKPd.opt.showAuctionDurationTimerText and "Show" or "Hide"](self.timer.update)
		self.timerDuration = timerDuration
		self.timerResetDuration = timerResetDuration or timerDuration
	end
	function f:ResetAuctionTimer()
		if not self.timerResetDuration then return end
		if (self.timerResetDuration+GetTime()) < self.timer.update.endTime then return end
		self.timer:SetCooldown(GetTime()-(self.timerDuration-self.timerResetDuration), self.timerDuration)
		self.timer.update.endTime = GetTime()+self.timerResetDuration
	end
	f:SetScript("OnEnter", function(self)
        if not GameTooltip:IsOwned(self) then
            GameTooltip:SetOwner(self, "ANCHOR_LEFT")
            GameTooltip:SetHyperlink(self.itemlink)
        end
		GameTooltip:Show()
        GameTooltip:Show()
	end)
	f:SetScript("OnLeave", HideTooltipOnLeave)
	f:SetScale(self.opt.appearScale)
	f:SetAlpha(self.opt.appearAlpha)
	f.isActive = false
	function f:UpdateSize()
		if (self.bigHide:IsShown() or self.cancelAuction:IsShown()) then
			self:SetHeight(100)
		else
			self:SetHeight(60)
		end
	end
	f:UpdateSize()
	GDKPd.frames[c] = f
	return f
end

function GDKPd:UpdateAllVisibilities()
	status:UpdateVisibility()
	playerBalance:UpdateVisibility()
end

local function capshares() GDKPd.opt.shareThirdAmount = min(GDKPd.opt.shareThirdAmount, GDKPd.opt.shareSecondEnable and 1-GDKPd.opt.shareSecondAmount or 1) end
local function updateFilteredSettings()
	--local opt =
end
local defaults={profile={
	safeDelete=true,
	point={
		point="CENTER",
		relative="CENTER",
		x=0,
		y=0,
	},
	statuspoint={
		point="CENTER",
		relative="CENTER",
		x=0,
		y=0,
	},
	balancepoint={
		point="CENTER",
		relative="CENTER",
		x=0,
		y=-50,
	},
	playerbalancepoint={
		point="CENTER",
		relative="CENTER",
		x=0,
		y=50,
	},
	filteredSettings={
	},
	forceHideShow=true,
	countdownTimerJump=5,
	showZeroBalance=false,
	shareSecondEnable=false,
	shareSecondAmount=0.33,
	shareThirdEnable=false,
	shareThirdAmount=0.11,
	auctionTimer=15,
	auctionTimerRefresh=15,
	movable=true,
	startBid=300,
	increment=50,
	minQuality=-1,
	autoAwardLoot=false,
	awardToML=false,
	showAuctionDurationTimer=true,
	showAuctionDurationTimerText=false,
	announceRaidWarning=true,
	announceBidRaidWarning=false,
	allowMultipleAuctions=false,
	announcePotAfterAuction=true,
	hideChatMessages={
		auctionAnnounce=false,
		auctionAnnounceRW=false,
		newBid=true,
		bidFinished=false,
		secondsRemaining=true,
		bidChats=false,
		potValues=false,
		auctionCancel=false,
		auctionCancelRW=false,
	},
	notifyVersions={
		notifyCompatibleOutdated=true,
		notifyIncompatibleOutdated=true,
		notifyNotInstalled=false,
	},
	hideCombat={
	},
	appearAlpha=1,
	appearScale=1,
	controlScale=1,
	bidButtonReenableDelay=0.3,
	slimML=false,
	slimMLConfirmed=false,
	confirmMailAll=true,
	confirmMail=false,
	linkBalancePot=false,
}}

local addfilter,filtersettingsupdate,filtersettingsruleupdate
do
	addfilter = function() tinsert(GDKPd.opt.filteredSettings,{enable=false,setStartBid=false,startBid=GDKPd.opt.startBid,setIncrement=false,increment=GDKPd.opt.increment,rules={}}) filtersettingsupdate() end
	local function addrule(i) if GDKPd.opt.filteredSettings[i] then tinsert(GDKPd.opt.filteredSettings[i].rules,{ruleName="false",ruleArgs={}}) filtersettingsruleupdate(i) end end

	local movementShown,rulesShown={},{}
	local moveSliders=setmetatable({},{__index=function(t,k) t[k]=1 return 1 end})
	local _ruleTemplate = {
		type="group",
		inline=true,
		name=function(t) return L["Rule #%s"]:format(t[#t]) end,
		args={
			enable={
				type="toggle",
				name=L["Enable"],
				order=1,
			},
			delete={
				type="toggle",
				name=L["Delete rule"],
				desc=L["PERMANENTLY deletes this rule."],
				get=function() return false end,
				set=function(t) if not checkSafeDelete() then return end tremove(GDKPd.opt.filteredSettings,tonumber(t[#t-1])) filtersettingsupdate() end,
				order=2,
			},
			setStartBid={
				type="toggle",
				name=L["Set starting bid"],
				order=11,
			},
			startBid={
				type="range",
				name=L["Starting bid"],
				min=1,
				max=999999,
				softMax=150000,
				softMin=500,
				step=1,
				order=12,
			},
			setIncrement={
				type="toggle",
				name=L["Set increment"],
				order=13,
			},
			increment={
				type="range",
				name=L["Minimum increment"],
				min=1,
				max=999999,
				softMax=75000,
				softMin=100,
				step=1,
				order=14,
			},
			norules={
				type="group",
				order=21,
				inline=true,
				name=L["Conditions"],
				hidden=function(t) return rulesShown[t[#t-1]] end,
				args={
					showrules={
						type="toggle",
						name=L["Edit conditions"],
						order=1,
						hidden=false,
						get=function() return false end,
						set=function(t) rulesShown[t[#t-2]]=true end,
						width="full",
					},
					ruletext={
						type="description",
						name=function(t)
							local index = tonumber(t[#t-2])
							if not index then return "Error - index not a number?" end
							if not GDKPd.opt.filteredSettings[index] then return "<this will disappear in a moment>" end
							local ctable = emptytable()
							for _,rule in ipairs(GDKPd.opt.filteredSettings[index].rules) do
								tinsert(ctable,itemFilters[rule.ruleName].describe(rule.ruleArgs))
							end
							local text = tconcat(ctable,"\n"..L["AND"].."\n")
							ctable:Release()
							return text
						end,
						order=2,
						hidden=function(t) return false end,
						width="full",
					},
				},
			},
			rules={
				type="group",
				inline=true,
				name=function(t) local k = tonumber(t[#t-1]) return (GDKPd.opt.filteredSettings[k] and #GDKPd.opt.filteredSettings[k].rules>0) and "" or L["Conditions"] end,
				order=21,
				hidden=function(t) return (t[#t]=="rules") and not rulesShown[t[#t-1]] end,
				args={
					add={
						type="execute",
						name=L["Add new condition"],
						order=-1,
						func=function(t) addrule(tonumber(t[#t-2])) end,
					},
				},
			},
			showMovement={
				type="toggle",
				name=L["Show reordering options"],
				get=function() return false end,
				set=function(t) movementShown[t[#t-1]]=true end,
				hidden=function(t) return movementShown[t[#t-1]] end,
				order=31,
				width="full",
			},
			movement={
				type="group",
				inline=true,
				name=L["Reordering options"],
				hidden=function(t) return not movementShown[t[#t-1]] end,
				order=32,
				args={
					showMovement={
						type="toggle",
						name=L["Show reordering options"],
						get=function() return true end,
						set=function(t) movementShown[t[#t-2]]=false end,
						order=1,
						width="full",
						hidden=false,
					},
					moveUp={
						type="execute",
						name=L["Move up"],
						disabled=function(t) return (t[#t-2]=="1") end,
						func=function(t) movementShown[t[#t-2]]=false local k = tonumber(t[#t-2]) local t=GDKPd.opt.filteredSettings[k-1] GDKPd.opt.filteredSettings[k-1]=GDKPd.opt.filteredSettings[k] GDKPd.opt.filteredSettings[k]=t end,
						order=11,
						hidden=false,
					},
					moveDown={
						type="execute",
						name=L["Move down"],
						disabled=function(t) return not GDKPd.opt.filteredSettings[tonumber(t[#t-2])+1] end,
						func=function(t) movementShown[t[#t-2]]=false local k = tonumber(t[#t-2]) local t=GDKPd.opt.filteredSettings[k+1] GDKPd.opt.filteredSettings[k+1]=GDKPd.opt.filteredSettings[k] GDKPd.opt.filteredSettings[k]=t end,
						order=12,
						hidden=false,
					},
					moveTo={
						type="execute",
						name=L["Move to before rule #..."],
						func=function(t) movementShown[t[#t-2]]=false local k = tonumber(t[#t-2]) local v = moveSliders[t[#t-2]] if k==v or k==(v-1) then return end tinsert(GDKPd.opt.filteredSettings,(k<v) and v-1 or v,tremove(GDKPd.opt.filteredSettings,k)) end,
						order=13,
						hidden=false,
					},
					moveToPos={
						type="range",
						name="",
						min=1,
						max=1,
						step=1,
						get=function(t) return moveSliders[t[#t-2]] end,
						set=function(t,v) moveSliders[t[#t-2]] = v end,
						order=14,
						hidden=false,
					},
				},
			},
		},
		order=function(t) return tonumber(t[#t]) end
	}

	local function ruleTemplate()
		return trcopy(_ruleTemplate,{},"ruleTemplate")
	end
	local _ruleEntryTemplate = {
		type="group",
		inline=true,
		name=function(t) return L["Condition #%s"]:format(t[#t]) end,
		set=function(t,d)
			local index,subindex,key=tonumber(t[#t-3]),tonumber(t[#t-1]),t[#t]
			if index and subindex and key and GDKPd.opt.filteredSettings then
				if GDKPd.opt.filteredSettings[index] then
					if GDKPd.opt.filteredSettings[index].rules[subindex] then
						GDKPd.opt.filteredSettings[index].rules[subindex][key] = d

						if key == "ruleName" then -- change rule settings display
							filtersettingsruleupdate(index)
						end
					else
						filtersettingsruleupdate(index)
					end
				else
					filtersettingsupdate()
				end
			end
		end,
		get=function(t)
			local index,subindex,key=tonumber(t[#t-3]),tonumber(t[#t-1]),t[#t]
			if index and subindex and key and GDKPd.opt.filteredSettings then
				if GDKPd.opt.filteredSettings[index] then
					if GDKPd.opt.filteredSettings[index].rules[subindex] then
						return GDKPd.opt.filteredSettings[index].rules[subindex][key]
					else
						filtersettingsruleupdate(index)
					end
				else
					filtersettingsupdate()
				end
			end
		end,
		args={
			show={
				type="toggle",
				name=L["Edit conditions"],
				order=1,
				get=function() return true end,
				set=function(t) rulesShown[t[#t-3]]=false end,
				disabled=function(t) return t[#t-1]~="1" end,
			},
			delete={
				type="toggle",
				name=L["Delete condition"],
				desc=L["Removes this condition from the rule. A rule with no conditions can never be true."],
				get=function() return false end,
				set=function(t) if not checkSafeDelete() then return end local index,subindex = tonumber(t[#t-3]),tonumber(t[#t-1]) if index and subindex and GDKPd.opt.filteredSettings[index] then tremove(GDKPd.opt.filteredSettings[index].rules,subindex) filtersettingsruleupdate(index) end end,
				order=2,
			},
			ruleName={
				type="select",
				name="",
				values=itemFilterListSelect,
				order=3,
				width="full",
			},
			ruleArgs={
				type="group",
				inline=true,
				name="",
				order=4,
				set=function(t,d)
					local index,subindex,key=tonumber(t[#t-4]),tonumber(t[#t-2]),t[#t]
					if index and subindex and key and GDKPd.opt.filteredSettings then
						if GDKPd.opt.filteredSettings[index] then
							if GDKPd.opt.filteredSettings[index].rules[subindex] then
								GDKPd.opt.filteredSettings[index].rules[subindex].ruleArgs[key] = d
							else
								filtersettingsruleupdate(index)
							end
						else
							filtersettingsupdate()
						end
					end
				end,
				get=function(t)
					local index,subindex,key=tonumber(t[#t-4]),tonumber(t[#t-2]),t[#t]
					if index and subindex and key and GDKPd.opt.filteredSettings then
						if GDKPd.opt.filteredSettings[index] then
							if GDKPd.opt.filteredSettings[index].rules[subindex] then
								return GDKPd.opt.filteredSettings[index].rules[subindex].ruleArgs[key]
							else
								filtersettingsruleupdate(index)
							end
						else
							filtersettingsupdate()
						end
					end
				end,
			}
		},
	}
	local function ruleEntryTemplate()
		return trcopy(_ruleEntryTemplate,{},"ruleEntryTemplate")
	end


	local filterSettingsNeedUpdate = false
	local filterSettingsNeedRuleUpdate = {}

	local function updateFilterRuleSettings(i)
		local opt = GDKPd.opt.filteredSettings[i]
		if opt then
			local k = tostring(i)
			local rules = GDKPd.options.args.behaviour.args.filteredSettings.args.rules.args[k].args.rules
			for j,rule in ipairs(opt.rules) do
				local l = tostring(j)
				if not rules.args[l] then
					rules.args[l] = ruleEntryTemplate()
				end
				rules.args[l].args.ruleArgs.args = (itemFilters[rule.ruleName]).args

				if itemFilters[rule.ruleName].defaults then
					for key,val in pairs(itemFilters[rule.ruleName].defaults) do
						if rule.ruleArgs[key] == nil then
							rule.ruleArgs[key] = val
						end
					end
				end
			end

			local j = #opt.rules+1
			while true do
				local l = tostring(j)
				if rules.args[l] then
					rules.args[l] = nil
				else
					break
				end
				j=j+1
			end
		end
	end

	local function updateFilterSettings()
		if filterSettingsNeedUpdate then
			_ruleTemplate.args.movement.args.moveToPos.max=(#GDKPd.opt.filteredSettings+1)

			local rulesArgs = GDKPd.options.args.behaviour.args.filteredSettings.args.rules.args
			for i=#GDKPd.opt.filteredSettings,1,-1 do
				local k = tostring(i)
				if not rulesArgs[k] then
					rulesArgs[k] = ruleTemplate()
				else
					break
				end
			end

			local i = #GDKPd.opt.filteredSettings+1
			while true do
				local k = tostring(i)
				if rulesArgs[k] then
					rulesArgs[k] = nil
				else
					break
				end
				i=i+1
			end

			filterSettingsNeedUpdate = false
		end

		local k,v=next(filterSettingsNeedRuleUpdate)
		while k do
			if v then
				updateFilterRuleSettings(k)
			end
			filterSettingsNeedRuleUpdate[k] = nil

			k,v=next(filterSettingsNeedRuleUpdate)
		end

		LibStub("AceConfigRegistry-3.0"):NotifyChange("GDKPd")
	end
	local filterSettingsThrottle = CreateFrame("Frame")
	filterSettingsThrottle:Hide()
	filterSettingsThrottle:SetScript("OnUpdate",function(s) updateFilterSettings() s:Hide() end)

	filtersettingsupdate = function() filterSettingsNeedUpdate=true filterSettingsThrottle:Show() end
	filtersettingsruleupdate = function(i) filterSettingsNeedRuleUpdate[i]=true filterSettingsThrottle:Show() end
end
GDKPd.options={
	type="group",
	args={
		lock={
			type="toggle",
			name=L["Lock"],
			desc=L["Prevent dragging and hide anchor"],
			get=function() return not GDKPd.opt.movable end,
			set=function(info, value) GDKPd.opt.movable = not value GDKPd:SetMovable(not value) end,
			order=1,
			--width="half",
		},
		show={
			type="toggle",
			name=L["Show"],
			desc=L["Show addon frames"],
			get=function() return not GDKPd.opt.hide end,
			set=function(info, value) GDKPd.opt.hide = not value GDKPd:UpdateAllVisibilities() end,
			order=2,
			--width="half",
		},
		safedelete={
			type="toggle",
			name=L["Safe delete mode"],
			desc=L["If turned on, requires the shift key to be held down to enable certain destructive actions."],
			get=function() return GDKPd.opt.safeDelete end,
			set=function(_,val) GDKPd.opt.safeDelete = val end,
			order=3,
			--width="half",
		},
		behaviour={
			type="group",
			name=L["Behaviour options"],
			args={
				filteredSettings={
					type="group",
					name=L["Special case rules"],
					args={
						label={
							type="header",
							name=L["Special case rules"],
							order=0,
						},
						desc={
							type="description",
							name=L["For each item, rules are processed top to bottom. If a matching rule is found, anything below that rule is ignored. If no matching rules are found, the settings configured in %s are used. For a rule to match, all conditions in that rule must be fulfilled."]:format(L["Behaviour options"]),
							order=1,
						},
						add1={
							type="execute",
							name=L["Add new rule"],
							func=addfilter,
							order=2,
						},
						rules={
							type="group",
							inline=true,
							name=L["Rules"],
							set=function(t,d)
								local index,key = tonumber(t[#t-1]),t[#t]
								if index and key and GDKPd.opt.filteredSettings then
									if GDKPd.opt.filteredSettings[index] then
										GDKPd.opt.filteredSettings[index][key] = d
									else
										filtersettingsupdate()
									end
								end
							end,
							get=function(t)
								local index,key = tonumber(t[#t-1]),t[#t]
								if index and key and GDKPd.opt.filteredSettings then
									if GDKPd.opt.filteredSettings[index] then
										return GDKPd.opt.filteredSettings[index][key]
									else
										filtersettingsupdate()
									end
								end
							end,
							args={
								base={
									type="group",
									inline=true,
									name=L["Special rule: Use default settings"],
									args={
										desc={
											type="description",
											name=L["If this rule is reached, default settings will be used."],
											order=1,
										},
									},
									order=-1,
								},
							},
							order=3,
						},
						add2={
							type="execute",
							name=L["Add new rule"],
							func=addfilter,
							order=4,
						}
					},
				},
				startBid={
					type="range",
					name=L["Starting bid"],
					min=0,
					max=999999,
					softMax=10000,
					softMin=50,
					step=1,
					get=function() return GDKPd.opt.startBid end,
					set=function(info, value) GDKPd.opt.startBid = value end,
					order=1,
				},
				minIncrement={
					type="range",
					name=L["Minimum increment"],
					min=1,
					max=999999,
					softMax=500,
					softMin=5,
					step=1,
					get=function() return GDKPd.opt.increment end,
					set=function(info, value) GDKPd.opt.increment = value end,
					order=2,
				},
				secondShare={
					dialogInline=true,
					name=L["Second bidder share"],
					order=3,
					type="group",
					args={
						isEnabled={
							order=1,
							type="toggle",
							name=L["Enable"],
							set=function(info,value) GDKPd.opt.shareSecondEnable = value capshares() end,
							get=function() return GDKPd.opt.shareSecondEnable end,
						},
						shareAmount={
							order=2,
							type="range",
							name=L["Amount"],
							min=0.01,
							max=0.99,
							isPercent=true,
							set=function(info, value) GDKPd.opt.shareSecondAmount = value capshares() end,
							get=function() return GDKPd.opt.shareSecondAmount end,
						},
					},
				},
				thirdShare={
					dialogInline=true,
					name=L["Third bidder share"],
					order=4,
					type="group",
					args={
						isEnabled={
							order=1,
							type="toggle",
							name=L["Enable"],
							set=function(info,value) GDKPd.opt.shareThirdEnable = value capshares() end,
							get=function() return GDKPd.opt.shareThirdEnable end,
						},
						shareAmount={
							order=2,
							type="range",
							name=L["Amount"],
							min=0.01,
							max=0.99,
							isPercent=true,
							set=function(info, value) GDKPd.opt.shareThirdAmount = value capshares() end,
							get=function() return GDKPd.opt.shareThirdAmount end,
						},
					},
				},
				minQuality={
					type="select",
					values=function()
						local vtab={}
						for key, tab in pairs(ITEM_QUALITY_COLORS) do
							if _G["ITEM_QUALITY"..key.."_DESC"] then
								vtab[key] = tab.hex.._G["ITEM_QUALITY"..key.."_DESC"].."|r"
							end
						end
						vtab[-1] = "|cffaa2222"..L["Use looting system loot threshold setting"].."|r"
						return vtab
					end,
					name=L["Minimum quality"],
					set=function(info, value) GDKPd.opt.minQuality = value end,
					get=function() return GDKPd.opt.minQuality end,
					order=5,
					width="full",
				},
				auctionTimer={
					type="range",
					softMin=5,
					softMax=30,
					order=6,
					name=L["Auction timeout"],
					desc=L["The amount of seconds that have to pass before the auction is closed without bids recieved"],
					set=function(info, value) GDKPd.opt.auctionTimer = value end,
					get=function() return GDKPd.opt.auctionTimer end,
				},
				auctionTimerRefresh={
					type="range",
					softMin=5,
					softMax=30,
					order=7,
					name=L["Auction bid timeout refresh"],
					desc=L["The amount of seconds that have to pass after a bid before the auction is closed"],
					set=function(info, value) GDKPd.opt.auctionTimerRefresh = value end,
					get=function() return GDKPd.opt.auctionTimerRefresh end,
				},
				countdownTimerJump={
					type="range",
					softMin=1,
					softMax=10,
					order=7.5,
					name=L["Countdown timer announce interval"],
					desc=L["The amount of seconds between each announcement of the remaining time"],
					set=function(info, value) GDKPd.opt.countdownTimerJump = value end,
					get=function() return GDKPd.opt.countdownTimerJump end,
				},
				autoAward={
					type="toggle",
					name=L["Auto-award loot to winner"],
					set=function(info, value) GDKPd.opt.autoAwardLoot = value end,
					get=function() return GDKPd.opt.autoAwardLoot end,
					width="full",
					order=8,
					disabled=function() return not not GDKPd.opt.awardToML end,
				},
				awardToML={
					type="toggle",
					name=L["Award loot to Master Looter when auto-auctioning"],
					set=function(info, value) GDKPd.opt.awardToML = value end,
					get=function() return GDKPd.opt.awardToML end,
					width="full",
					order=9,
					disabled=function() return not not GDKPd.opt.autoAwardLoot end,
				},
				announceRW={
					type="toggle",
					name=L["Announce auction start to raid warning"],
					set=function(info, value) GDKPd.opt.announceRaidWarning = value end,
					get=function() return GDKPd.opt.announceRaidWarning end,
					width="full",
					order=10,
				},
				announceRWBid={
					type="toggle",
					name=L["Announce bids to raid warning"],
					width="full",
					set=function(info, value) GDKPd.opt.announceBidRaidWarning = value end,
					get=function() return GDKPd.opt.announceBidRaidWarning end,
					order=11,
				},
				allowMultiple={
					type="toggle",
					name=L["Allow multiple simultanous auctions"],
					width="full",
					set=function(info, value) GDKPd.opt.allowMultipleAuctions = value end,
					get=function() return GDKPd.opt.allowMultipleAuctions end,
					disabled=function() return ((GDKPd.curAuctions and (#GDKPd.curAuctions > 0)) or (GDKPd.curAuction.item)) end,
					order=12,
				},
				announcePotAfterAuction={
					type="toggle",
					name=L["Announce the current pot amount after each auction"],
					width="full",
					set=function(info, value) GDKPd.opt.announcePotAfterAuction = value end,
					get=function() return GDKPd.opt.announcePotAfterAuction end,
					order=13,
				},
				confirmMail={
					type="toggle",
					name=L["Require confirmation when mailing pot shares"],
					width="full",
					set=function(info, value) GDKPd.opt.confirmMail = value end,
					get=function() return GDKPd.opt.confirmMail end,
					order=14,
				},
				linkBalancePot={
					type="toggle",
					name=L["Link raid member balance to pot"],
					desc=L["Any money subtracted from raid members is added to the pot and vice versa"],
					width="full",
					set=function(info, value) GDKPd.opt.linkBalancePot = value end,
					get=function() return GDKPd.opt.linkBalancePot end,
					order=15,
				},
			},
			order=1,
		},
		appearance={
			type="group",
			name=L["Appearance options"],
			args={
				showtimer={
					set=function(info, value) GDKPd.opt.showAuctionDurationTimer = value end,
					get=function() return GDKPd.opt.showAuctionDurationTimer end,
					type="toggle",
					name=L["Show auction duration spiral"],
					width="full",
					order=1,
				},
				showtimertext={
					disabled=function() return not GDKPd.opt.showAuctionDurationTimer end,
					set=function(info, value) GDKPd.opt.showAuctionDurationTimerText = value end,
					get=function() return GDKPd.opt.showAuctionDurationTimerText end,
					type="toggle",
					name=L["Show countdown text on auction duration spiral"],
					width="full",
					order=2,
				},
				hideChats={
					type="multiselect",
					name=L["Hide chat messages"],
					values={
						auctionAnnounce=L["Hide 'Bidding starts' announcements"],
						auctionAnnounceRW=L["Hide 'Bidding starts' announcements from raid warning"],
						newBid=L["Hide 'New highest bidder' announcements"],
						secondsRemaining=L["Hide 'Time remaining' announcements"],
						bidFinished=L["Hide 'Auction finished' announcements"],
						bidChats=L["Hide players' bid messages"],
						potValues=L["Hide 'Current pot:' announcements"],
						auctionCancel=L["Hide 'Auction cancelled' announcements"],
						auctionCancelRW=L["Hide 'Auction cancelled' announcements from raid warning"],
					},
					set=function(info, key, value) GDKPd.opt.hideChatMessages[key]=value end,
					get=function(info, key) return GDKPd.opt.hideChatMessages[key] end,
					order=3,
					width="full",
				},
				frameAlpha={
					type="range",
					min=0,
					max=1,
					bigStep=0.1,
					name=L["Frame alpha"],
					order=4,
					set=function(info, value) GDKPd.opt.appearAlpha = value for _, f in ipairs(GDKPd.frames) do f:SetAlpha(value) end end,
					get=function() return GDKPd.opt.appearAlpha end,
				},
				frameScale={
					type="range",
					min=0.01,
					softMin=0.5,
					softMax=2,
					name=L["Frame scale"],
					order=5,
					set=function(info, value) GDKPd.opt.appearScale = value for _, f in ipairs(GDKPd.frames) do f:SetScale(value) end GDKPd_Anchor:SetScale(value) end,
					get=function() return GDKPd.opt.appearScale end,
				},
				bidButtonReenableDelay={
					type="range",
					min=0,
					max=10,
					softMax=1,
					softMin=0,
					name=L["Bid button re-enable delay"],
					order=6,
					set=function(info, value) GDKPd.opt.bidButtonReenableDelay = value end,
					get=function() return GDKPd.opt.bidButtonReenableDelay end,
				},
				controlScale={
					type="range",
					min=0.01,
					softMin=0.5,
					softMax=2,
					name=L["Control panel scale"],
					order=7,
					set=function(info, value)
						GDKPd.opt.controlScale = value
						GDKPd.status:SetScale(value)
						GDKPd.history:SetScale(value)
						GDKPd.version:SetScale(value)
					end,
					get=function() return GDKPd.opt.controlScale end,
				},
				useSlimML={
					type="toggle",
					set=function(info, value) if value and (not GDKPd.opt.slimMLConfirmed) then StaticPopup_Show("GDKPD_SLIMMLWARN") else GDKPd.opt.slimML = value end end,
					get=function() return GDKPd.opt.slimML end,
					name=L["Use slim bidding window even while Master Looter"],
					width="full",
					order=8,
				},
				forceHideShow={
					type="toggle",
					set=function(info, value) GDKPd.opt.forceHideShow = value for _,f in ipairs(GDKPd.frames) do f.hide:SetAlpha(value and 1 or 0) end end,
					get=function() return GDKPd.opt.forceHideShow end,
					order=8.5,
					width="full",
					name=L["Always show the \"Hide\" button on bid frames"],
				},
				anchorBalance={
					type="toggle",
					set=function(info, value) GDKPd.opt.anchorBalance = value GDKPd.balance:UpdatePosition() end,
					get=function() return GDKPd.opt.anchorBalance end,
					name=L["Anchor balance window to status window"],
					width="full",
					order=9,
				},
			},
			order=2,
		},
		notification={
			type="group",
			name=L["Notification options"],
			args={
				rules={
					type="input",
					name=L["Rules"],
					order=1,
					multiline=true,
					get=function() return GDKPd.opt.rulesString or "" end,
					set=function(info, value)
						GDKPd.opt.rulesString = strlen(value) > 0 and value
						if GDKPd.opt.rulesString then
							GDKPd.status.rules:Enable()
						else
							GDKPd.status.rules:Disable()
						end
					end,
					width="full",
				},
				notifyVersions={
					type="multiselect",
					name=L["Version notifications"],
					values={
						notifyCompatibleOutdated=L["Notify outdated versions that are compatible with your version"],
						notifyIncompatibleOutdated=L["Notify outdated versions that aren't compatible with your version"],
						notifyNotInstalled=L["Notify raid members that do not have GDKPd installed"],
					},
					set=function(info, key, value) GDKPd.opt.notifyVersions[key]=value end,
					get=function(info, key) return GDKPd.opt.notifyVersions[key] end,
					order=2,
					width="full",
				},
			},
			order=3,
		},
		visibility={
			type="group",
			name=L["Visibility settings"],
			args={
				hideCombatFrames={
					type="multiselect",
					name=L["Hide frames in combat"],
					values={
						status=L["Hide status and balance windows"],
						history=L["Hide history window"],
						vercheck=L["Hide version check window"],
					},
					set=function(info, key, value)
						GDKPd.opt.hideCombat[key]=value
						GDKPd.status:UpdateVisibility()
						GDKPd.playerBalance:UpdateVisibility()
						if InCombatLockdown() then
							if key == "history" and value then
								GDKPd.history:Hide()
							end
							if key == "vercheck" and value then
								GDKPd.version:Hide()
							end
						end
					end,
					get=function(info, key) return GDKPd.opt.hideCombat[key] end,
					order=1,
					width="full",
				},
			},
			order=4,
		},
	},
}

function GDKPd:OnProfileEnable()
	self.opt = self.db.profile
	for _, f in ipairs(self.frames) do
		f:SetAlpha(self.opt.appearAlpha)
		f:SetScale(self.opt.appearScale)
	end
	GDKPd_Anchor:SetScale(self.opt.appearScale)
end

GDKPd:SetScript("OnEvent", function(self, event, ...)
	local arg = emptytable(...)
	if event == "ADDON_LOADED" and arg[1] == "GDKPd" then
		self:UnregisterEvent("ADDON_LOADED")
		local isFirstLogin = not (GDKPd_PotData or GDKPd_BalanceData)
		GDKPd_PotData = GDKPd_PotData or {history={},potAmount=0}
		--seperate line for savedvar upgrading purposes
		GDKPd_PotData.curPotHistory = GDKPd_PotData.curPotHistory or {}
		GDKPd_PotData.playerBalance = GDKPd_PotData.playerBalance or {}
		setmetatable(GDKPd_PotData.playerBalance, {__index=function() return 0 end})
		GDKPd_BalanceData = GDKPd_BalanceData or {}
		setmetatable(GDKPd_BalanceData, {__index=function() return 0 end})
		self.status:Update()
		self.db = LibStub("AceDB-3.0"):New("GDKPd_DB", defaults or {})
		self.db.RegisterCallback(self,"OnProfileChanged","OnProfileEnable")
		self.db.RegisterCallback(self,"OnProfileCopied","OnProfileEnable")
		self.db.RegisterCallback(self,"OnProfileReset","OnProfileEnable")
		self.opt = self.db.profile
		if not self.db.global.shownPopupAddonMsg4_2 then
			self.db.global.shownPopupAddonMsg4_2 = true
			if not isFirstLogin then
				-- the user has moved the window, so he's already logged in
				-- at least i hope nobody will have their GDKPd windows in the center of their screen
				StaticPopup_Show("GDKPD_42_ADDONMSG")
			end
		end
		GDKPd_Anchor:SetScale(self.opt.appearScale)
		self.status:SetScale(self.opt.controlScale)
		if self.opt.rulesString then
			self.status.rules:Enable()
		else
			self.status.rules:Disable()
		end
		self.history:SetScale(self.opt.controlScale)
		self.version:SetScale(self.opt.controlScale)
		self.options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
		self.options.args.profiles.order = -1

		-- port old per-item and per-ilvl settings to the new custom rule engine
		do
			if self.opt.customItemSettings then
				local concatSets={}
				for id,settings in pairs(self.opt.customItemSettings) do
					local concatKey=("%d:%d"):format(settings.minBid or -1,settings.minIncrement or -1)
					concatSets[concatKey] = (concatSets[concatKey] and concatSets[concatKey].." "..id) or id
				end
				for key,ids in pairs(concatSets) do
					if key ~= "-1:-1" then -- do not port anything that does nothing
						local minBid,minIncrement = key:match("^(%-?%d+):(%-?%d+)")
						minBid = (minBid ~= "-1" and tonumber(minBid))
						minIncrement = (minIncrement ~= "-1" and tonumber(minIncrement))

						tinsert(GDKPd.opt.filteredSettings,{
							enable=true,
							setStartBid=not not minBid,
							startBid=minBid or GDKPd.opt.startBid,
							setIncrement=not not minIncrement,
							increment=minIncrement or GDKPd.opt.increment,
							rules={
								{
									ruleName="itemid",
									ruleArgs={
										idlist=ids,
									},
								},
							},
						})
					end
				end
				self.opt.customItemSettings = nil
			end

			if self.opt.itemLevelPricing then
				for _,d in ipairs(self.opt.itemLevelPricing) do
					if d.mininc or d.minbid then -- do not port anything that does nothing
						tinsert(GDKPd.opt.filteredSettings,{
							enable=true,
							setStartBid=not not d.minbid,
							startBid=d.minbid or GDKPd.opt.startBid,
							setIncrement=not not d.mininc,
							increment=d.mininc or GDKPd.opt.increment,
							rules={
								{
									ruleName="itemlevel",
									ruleArgs={
										lowerBound=d.min or 0,
										upperBound=d.max or 100000,
									},
								},
							},
						})
					end
				end
				self.opt.itemLevelPricing = nil
			end
		end
		-- port code done

		-- init special case rules' config page
		filtersettingsupdate()
		for i=1,#self.opt.filteredSettings do filtersettingsruleupdate(i) end

		LibStub("AceConfig-3.0"):RegisterOptionsTable("GDKPd", self.options)
		SlashCmdList["GDKPD"] = function(input)
			local cmd, link = input:match("(%S+)%s+(|c........|Hitem:.+|r)")
			if (cmd and cmd == "auction") and link then
				if self:PlayerIsML((UnitName("player")),true) then
					for itemLink in string.gmatch(link, "|c........|Hitem:.-|r") do
						self:QueueAuction(itemLink, GDKPd:GetStartBid(itemLink), GDKPd:GetMinIncrement(itemLink))
					end
				else
					print(L["Cannot start auction without Master Looter privileges."])
				end
			elseif input:lower() == "ver" then
				print(L["GDKPd version %s. Packaged %s."]:format(DEBUGFORCEVERSION or "@project-version@","@project-date-iso@"))
			elseif input:lower() == "history" then
				GDKPd.history:Show()
			elseif input:lower() == "wipe" then
				StaticPopup_Show("GDKPD_WIPEHISTORY")
			elseif input:lower() == "vercheck" then
				GDKPd.version:Show()
			else
				LibStub("AceConfigDialog-3.0"):Open("GDKPd")
			end
		end
		SLASH_GDKPD1 = "/gdkpd"
		SLASH_GDKPD2 = "/gdkp"
		anchor:SetPoint(self.opt.point.point, UIParent, self.opt.point.relative, self.opt.point.x, self.opt.point.y)
		self:SetMovable(self.opt.movable)
		self.status.header:SetPoint(self.opt.statuspoint.point, UIParent, self.opt.statuspoint.relative, self.opt.statuspoint.x, self.opt.statuspoint.y)
		--self.balance.header:SetPoint(self.opt.balancepoint.point, UIParent, self.opt.balancepoint.relative, self.opt.balancepoint.x, self.opt.balancepoint.y)
		self.balance:UpdatePosition()
		self.playerBalance.header:SetPoint(self.opt.playerbalancepoint.point, UIParent, self.opt.playerbalancepoint.relative, self.opt.playerbalancepoint.x, self.opt.playerbalancepoint.y)
		self.playerBalance:Update()
		self.status:UpdateVisibility()
	end
	if (event == "CHAT_MSG_RAID") or (event == "CHAT_MSG_RAID_LEADER") or (event == "CHAT_MSG_RAID_WARNING") then
		local msg,sender = arg[1],pruneCrossRealm(arg[2])
		--this is code for single-auction mode. put into a do branch to avoid local clashes.
		do
			local itemLink, minBid, bidIncrement, auctionTimer, auctionTimerRefresh = string.match(msg, "%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r). Please bid in raid chat, starting bid (%d+) gold, minimum increment (%d+) gold. TTL: (%d+)/(%d+)")
			if not itemLink then
				-- backwards comp number three
				itemLink, minBid, bidIncrement, auctionTimer, auctionTimerRefresh = string.match(msg, "%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r). Please bid in raid chat, starting bid (%d+) gold, minimum increment (%d+) gold. TTL until expire: (%d+) seconds, TTL after bid: (%d+) seconds.")
			end
			if not itemLink then
				-- backwords compability strikes again
				itemLink, minBid, bidIncrement, auctionTimer = string.match(msg, "%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r). Please bid in raid chat, starting bid (%d+) gold, minimum increment (%d+) gold. TTL after a bid is placed: (%d+) seconds.")
				auctionTimerRefresh=auctionTimer
			end
			if not itemLink then
				-- backwards version compability
				itemLink, minBid, bidIncrement = string.match(msg, "%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r). Please bid in raid chat, starting bid (%d+) gold, minimum increment (%d+) gold.")
				auctionTimer = 0
				auctionTimerRefresh=0
			end
			auctionTimer = tonumber(auctionTimer) or 0
			auctionTimerRefresh = tonumber(auctionTimerRefresh) or 0
			if itemLink and self:PlayerIsML(sender, false) then
				if not self.ignoredLinks[itemLink] then
					local f = GDKPd:FetchFrameFromLink(itemLink)
					if not f then
						f = self:GetUnoccupiedFrame()
						f:SetItem(itemLink)
						f.isActive = true
						f:Show()
					end
					f.isMultiBid = false
					self.InProgressBidFrame = f
					f.bidIncrement = bidIncrement
					f:SetCurBid(minBid, false, false, true)
					f:SetAuctionTimer(auctionTimer, auctionTimerRefresh)
					if f.maxAutoBid then
						local newBid = tonumber(minBid)
						if newBid < f.maxAutoBid then
							SendChatMessage(tostring(newBid),"RAID")
						end
					end
				else
					self.ignoredLinks[itemLink] = nil
				end
			end
			if self.curAuction.item and msg:find("%d+") == 1 then
				local newBid = tonumber(msg:match("([0-9]+%.?[0-9]*)[kK]"))
				if not newBid then
					newBid = tonumber(msg:match("%d+"))
				else
					newBid = math.floor(newBid*1000)
				end
				if (self.curAuction.curBid + self.curAuction.increment) <= newBid then
					GDKPd.curAuction.curBid = newBid
					if GDKPd.curAuction.bidders[sender] then
						GDKPd.curAuction.bidders[GDKPd.curAuction.bidders[sender]].bidAmount = newBid
					else
						tinsert(GDKPd.curAuction.bidders, {bidAmount=newBid, bidderName=sender})
						GDKPd.curAuction.bidders[sender] = #GDKPd.curAuction.bidders
					end
					SendChatMessage(("[GDKPd] New highest bidder: %s (%d gold)"):format(sender, newBid),(self.opt.announceBidRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
					self.curAuction.timeRemains = math.max(self.opt.auctionTimerRefresh, self.curAuction.timeRemains)
				end
			end
			local bidderName, newBid = string.match(msg, "%[GDKPd%] New highest bidder: (%S+) %((%d+) gold%)")
			if bidderName and self.InProgressBidFrame then
				local isSelf = pruneCrossRealm(bidderName) == (UnitName("player"))
				self.InProgressBidFrame:SetCurBid(newBid, bidderName, isSelf)
				self.InProgressBidFrame:ResetAuctionTimer()
				if not isSelf then
					if self.InProgressBidFrame.maxAutoBid then
						local myNewBid = newBid+self.InProgressBidFrame.bidIncrement
						if myNewBid <= self.InProgressBidFrame.maxAutoBid then
							SendChatMessage(tostring(myNewBid),"RAID")
						end
					end
				end
			end
			if msg:find("%[GDKPd%] Auction finished.") and GDKPd:PlayerIsML(sender,false) and self.InProgressBidFrame then
				self.InProgressBidFrame:Hide()
				self.InProgressBidFrame.isActive = false
				self.InProgressBidFrame = nil
				local winnerName, paymentString = msg:match("%[GDKPd%] Auction finished. Winner: (%S+). (.+).")
				if winnerName then
					if pruneCrossRealm(winnerName) == (UnitName("player")) then
						for targetAmount, targetName in paymentString:gmatch("(%d+) to (%S+)[%.,]") do
							local tarName = pruneCrossRealm(targetName)
							if GDKPd:PlayerIsML((UnitName("player")),true) then
								GDKPd_PotData.playerBalance[tarName == "pot" and sender or tarName] = GDKPd_PotData.playerBalance[tarName == "pot" and sender or tarName] + targetAmount
								GDKPd.balance:Update()
							else
								GDKPd_BalanceData[tarName == "pot" and sender or tarName] = GDKPd_BalanceData[tarName == "pot" and sender or tarName] + targetAmount
								GDKPd.playerBalance:Update()
							end
						end
					else
						for targetAmount, targetName in paymentString:gmatch("(%d+) to (%S+)[%.,]") do
							if pruneCrossRealm(targetName) == (UnitName("player")) then
								if GDKPd:PlayerIsML((UnitName("player")),true) then
									GDKPd_PotData.playerBalance[winnerName] = GDKPd_PotData.playerBalance[winnerName]-targetAmount
									GDKPd.balance:Update()
								else
									GDKPd_BalanceData[winnerName] = GDKPd_BalanceData[winnerName]-targetAmount
									GDKPd.playerBalance:Update()
								end
							end
						end
					end
				end
			end
			if msg:find("%[GDKPd%] Auction cancelled.") and GDKPd:PlayerIsML(sender, false) and self.InProgressBidFrame then
				self.InProgressBidFrame.isActive = false
				if GDKPd:PlayerIsML((UnitName("player")),true) then
					local f = self.InProgressBidFrame
					self.InProgressBidFrame = nil
					f.timer:Hide()
					f.timer.update:Hide()
					f.curbid:Hide()
					f.highestbidder:Hide()
					f.highestbid:Hide()
					f.bidbox:Hide()
					f.bid:Disable()
					f.autobid:Disable()
				else
					self.InProgressBidFrame:Hide()
				end
			end
		end
		-- this is new code for multi-auction. slight variations are used rl-side to indicate this.
		do
			local itemLink, minBid, bidIncrement, auctionTimer, auctionTimerRefresh = string.match(msg, "%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r). Bid using format '%[item%] 1000', starting bid (%d+) gold, minimum increment (%d+) gold. TTL: (%d+)/(%d+)")
			if not itemLink then
				-- backwards to non-shortened
				itemLink, minBid, bidIncrement, auctionTimer, auctionTimerRefresh = string.match(msg, "%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r). Bid using format '%[item%] 1000', starting bid (%d+) gold, minimum increment (%d+) gold. TTL until expire: (%d+) seconds, TTL after bid: (%d+) seconds.")
			end
			if not itemLink then
				itemLink, minBid, bidIncrement, auctionTimer = string.match(msg, "%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r). Please bid in raid chat, using format 'itemlink bid'. Starting bid (%d+) gold, minimum increment (%d+) gold. TTL after a bid is placed: (%d+) seconds.")
				auctionTimerRefresh = auctionTimer
			end
			auctionTimer = tonumber(auctionTimer) or 0
			auctionTimerRefresh = tonumber(auctionTimerRefresh) or 0
			if itemLink and self:PlayerIsML(sender,false) then
				if not self.ignoredLinks[itemLink] then
					local f = GDKPd:FetchFrameFromLink(itemLink)
					if not f then
						f = self:GetUnoccupiedFrame()
						f:SetItem(itemLink)
						f.isActive = true
						f:Show()
					end
					f.isMultiBid = true
					f.bidIncrement = bidIncrement
					f:SetCurBid(minBid, false, false, true)
					f:SetAuctionTimer(auctionTimer, auctionTimerRefresh)
					if f.maxAutoBid then
						local newBid = tonumber(minBid)
						if newBid < f.maxAutoBid then
							SendChatMessage(itemLink.." "..newBid)
						end
					end
				else
					self.ignoredLinks[itemLink] = nil
				end
			end
			local bidItemLink, bidAmount = msg:match("(|c........|Hitem:.+|r)%s*([0-9]+%.?[0-9]*)[kK]")
			if not bidItemLink then
				bidItemLink, bidAmount = msg:match("(|c........|Hitem:.+|r)%s*(%d+)")
			else
				bidAmount = math.floor(bidAmount*1000)
			end
			if bidItemLink then
				if self.curAuctions[bidItemLink] then
					local aucdata = self.curAuctions[bidItemLink]
					bidAmount = tonumber(bidAmount)
					if (aucdata.curBid+aucdata.increment) <= bidAmount then
						aucdata.curBid = bidAmount
						if aucdata.bidders[sender] then
							aucdata.bidders[aucdata.bidders[sender]].bidAmount = bidAmount
						else
							tinsert(aucdata.bidders, {bidAmount=bidAmount, bidderName=sender})
							aucdata.bidders[sender] = #aucdata.bidders
						end
						SendChatMessage(("[GDKPd] New highest bidder on %s: %s (%d gold)"):format(bidItemLink,sender,bidAmount),(self.opt.announceBidRaidWarning and (IsRaidOfficer() or IsRaidLeader())) and "RAID_WARNING" or "RAID")
						aucdata.timeRemains = math.max(aucdata.timeRemains, self.opt.auctionTimerRefresh)
					end
				end
			end
			local bidItem, bidderName, newBid = string.match(msg, "%[GDKPd%] New highest bidder on (|c........|Hitem:.+|r): (%S+) %((%d+) gold%)")
			if bidderName and self:FetchFrameFromLink(bidItem) then
				local isSelf = pruneCrossRealm(bidderName) == (UnitName("player"))
				local bidFrame = self:FetchFrameFromLink(bidItem)
				bidFrame:SetCurBid(newBid, bidderName, isSelf)
				bidFrame:ResetAuctionTimer()
				if not isSelf then
					if bidFrame.maxAutoBid then
						local myNewBid = newBid+bidFrame.bidIncrement
						if myNewBid <= bidFrame.maxAutoBid then
							SendChatMessage(bidItem.." "..myNewBid, "RAID")
						end
					end
				end
			end
			local auctionEndItem = msg:match("%[GDKPd%] Auction finished for (|c........|Hitem:.+|r).")
			if auctionEndItem and GDKPd:PlayerIsML(sender,false) and self:FetchFrameFromLink(auctionEndItem) then
				local f = self:FetchFrameFromLink(auctionEndItem)
				f.isActive = false
				f:Hide()
				local winnerName, paymentString = msg:match("%[GDKPd%] Auction finished for |c........|Hitem:.+|r%. Winner: (%S+)%. (.+)")
				if winnerName then
					if pruneCrossRealm(winnerName) == (UnitName("player")) then
						for targetAmount, targetName in paymentString:gmatch("(%d+) to (%S+)[%.,]") do
							local tarName = pruneCrossRealm(targetName)
							if GDKPd:PlayerIsML((UnitName("player")),true) then
								GDKPd_PotData.playerBalance[tarName == "pot" and sender or tarName] = GDKPd_PotData.playerBalance[tarName == "pot" and sender or tarName] + targetAmount
								GDKPd.balance:Update()
							else
								GDKPd_BalanceData[tarName == "pot" and sender or tarName] = GDKPd_BalanceData[tarName == "pot" and sender or tarName] + targetAmount
								GDKPd.playerBalance:Update()
							end
						end
					else
						for targetAmount, targetName in paymentString:gmatch("(%d+) to (%S+)[%.,]") do
							if pruneCrossRealm(targetName) == (UnitName("player")) then
								if GDKPd:PlayerIsML((UnitName("player")),true) then
									GDKPd_PotData.playerBalance[winnerName] = GDKPd_PotData.playerBalance[winnerName]-targetAmount
									GDKPd.balance:Update()
								else
									GDKPd_BalanceData[winnerName] = GDKPd_BalanceData[winnerName]-targetAmount
									GDKPd.playerBalance:Update()
								end
							end
						end
					end
				end
			end
			local auctionCancelItem = msg:match("%[GDKPd%] Auction cancelled for (|c........|Hitem:.+|r)%.")
			if auctionCancelItem and GDKPd:PlayerIsML(sender, false) and self:FetchFrameFromLink(auctionCancelItem) then
				local f = self:FetchFrameFromLink(auctionCancelItem)
				f.isActive = false
				if GDKPd:PlayerIsML((UnitName("player")), true) then
					f.timer:Hide()
					f.timer.update:Hide()
					f.curbid:Hide()
					f.highestbidder:Hide()
					f.highestbid:Hide()
					f.bidbox:Hide()
					f.bid:Disable()
					f.autobid:Disable()
				else
					f:Hide()
				end
			end
		end
		-- generic code for both auction modes
		do
			local potAmount = msg:match("%[GDKPd%] Distributing pot. Pot size: %d+ gold. Amount to distribute: %d+ gold. Players in raid: %d+. Share per player: (%d+) gold.")
			if not potAmount then
				potAmount = msg:match("%[GDKPd%] Distributing pot. Pot size: %d+ gold. Players in raid: %d+. Pot share per player: (%d+) gold.")
			end
			if potAmount and self:PlayerIsML(sender,false) then
				GDKPd_BalanceData[sender] = GDKPd_BalanceData[sender]-potAmount
				GDKPd.playerBalance:Update()
			end
		end
	end
	if (event == "CHAT_MSG_ADDON") then
		local sender = pruneCrossRealm(arg[4])
		if sender then
			if arg[1] == "GDKPD START" and self:PlayerIsML(sender,false) then
				if not self:FetchFrameFromLink(arg[2]) then
					local f = self:GetUnoccupiedFrame()
					f.isActive = true
					f:SetItem(arg[2])
					f:Show()
				end
			end
			if arg[1] == "GDKPD VREQ" then
				SendAddonMessage("GDKPD VDATA", DEBUGFORCEVERSION or "@project-version@", "WHISPER", arg[4])
			end
			if arg[1] == "GDKPD VDATA" then
				self.versions[sender] = arg[2]
				self.version:Update()
			end
			if arg[1] == "GDKPD MANADJ" and self:PlayerIsML(sender,false) then
				GDKPd_BalanceData[sender] = GDKPd_BalanceData[sender]+arg[2]
				GDKPd.playerBalance:Update()
			end
		end
	end
	if (event == "LOOT_CLOSED") then
		self.status.announcetext:Hide()
		self.status.announce1:Hide()
		self.status.announce2:Hide()
		self.status.noannounce:Hide()
		self.status:UpdateSize()
	end
	if (event == "LOOT_OPENED") and self:PlayerIsML((UnitName("player")), true) then
        local minQuality = (self.opt.minQuality == -1 and GetLootThreshold() or self.opt.minQuality)
        local has = false
        for numLoot=1, GetNumLootItems() do
            if LootSlotHasItem(numLoot) then
                local tex, item, quantity, currency, quality, isLocked = GetLootSlotInfo(numLoot)
                if quality >= minQuality then
                    has = true
                    break
                end
            end
        end

        if has then
            self.status.announcetext:Show()
            self.status.announce1:Show()
            self.status.announce2:Show()
            self.status.noannounce:Show()
            self.status:UpdateSize()
        end
	end
	if (event == "GROUP_ROSTER_UPDATE") or (event == "PARTY_LOOT_METHOD_CHANGED") then
		self.status:UpdateVisibility()
		--[[if self:PlayerIsML((UnitName("player")),true) then
			self.status:Show()
		else
			self.status:Hide()
		end--]]
	end
	if (event == "UNIT_NAME_UPDATE") then
		if UnitIsUnit("player",arg[1]) then
			self:UnregisterEvent("UNIT_NAME_UPDATE")
			self.status:UpdateVisibility()
		end
	end
	if (event == "TRADE_CLOSED") then
		self.isTrading = false
	end
	if (event == "TRADE_SHOW") then
		self.isTrading = true
		self.tradePartner = (GetUnitName("npc",true))
		self.tradeMoneySelf = 0
		self.tradeMoneyOther = 0
		self.balance:Update()
	end
	if (event == "TRADE_ACCEPT_UPDATE") and (arg[1] == 1) then
		self.tradeMoneySelf = GetPlayerTradeMoney()/10000
	end
	if (event == "TRADE_MONEY_CHANGED") then
		self.tradeMoneyOther = GetTargetTradeMoney()/10000
	end
	if (event == "UI_INFO_MESSAGE") then
		if arg[1] == ERR_TRADE_COMPLETE then
			--if self:PlayerIsML((UnitName("player")),true) and GDKPd_PotData.playerBalance[self.tradePartner] ~= 0 then
			if self:PlayerIsML((UnitName("player")),true) then
				if GDKPd_PotData.playerBalance[self.tradePartner] ~= 0 then
					local moneyChange = (self.tradeMoneyOther)-(self.tradeMoneySelf)
					local curBalancePot, curBalancePlayer = GDKPd_PotData.playerBalance[self.tradePartner], GDKPd_BalanceData[self.tradePartner]
					if moneyChange > 0 then
						--[[if curBalancePot+moneyChange > 0 then
							moneyChange = moneyChange-(curBalancePot*(-1))
							GDKPd_PotData.playerBalance[self.tradePartner] = 0
							if (curBalancePlayer ~= 0 or GetRealNumRaidMembers() > 0) then
								GDKPd_BalanceData[self.tradePartner] = curBalancePlayer+moneyChange
							end
						else--]]
							GDKPd_PotData.playerBalance[self.tradePartner] = curBalancePot+moneyChange
						--end
					elseif moneyChange < 0 then
						--[[if curBalancePot+moneyChange < 0 then
							moneyChange = moneyChange+(curBalancePot*(-1))
							GDKPd_PotData.playerBalance[self.tradePartner] = 0
							if (curBalancePlayer ~= 0 or GetRealNumRaidMembers() > 0) then
								GDKPd_BalanceData[self.tradePartner] = curBalancePlayer+moneyChange
							end
						else--]]
							GDKPd_PotData.playerBalance[self.tradePartner] = curBalancePot+moneyChange
						--end
					end
				end
			elseif GDKPd_BalanceData[self.tradePartner] ~= 0 then
				GDKPd_BalanceData[self.tradePartner] = GDKPd_BalanceData[self.tradePartner]-(self.tradeMoneySelf)+(self.tradeMoneyOther)
			end
			GDKPd.balance:Update()
			GDKPd.playerBalance:Update()
		end
	end
	if (event == "PLAYER_REGEN_ENABLED") then
		self.status:UpdateVisibility(false)
		self.playerBalance:UpdateVisibility(false)
	end
	if (event == "PLAYER_REGEN_DISABLED") then
		self.status:UpdateVisibility(true)
		self.playerBalance:UpdateVisibility(true)
	end
	if (event == "MAIL_SHOW") or (event == "MAIL_CLOSED") then
		self.balance:Update()
	end
	-- release table back into the pool of usable tables
	arg:Release()
end)
GDKPd:RegisterEvent("ADDON_LOADED")
GDKPd:RegisterEvent("CHAT_MSG_RAID")
GDKPd:RegisterEvent("CHAT_MSG_RAID_LEADER")
GDKPd:RegisterEvent("CHAT_MSG_RAID_WARNING")
GDKPd:RegisterEvent("LOOT_OPENED")
GDKPd:RegisterEvent("LOOT_CLOSED")
GDKPd:RegisterEvent("GROUP_ROSTER_UPDATE")
GDKPd:RegisterEvent("PARTY_LOOT_METHOD_CHANGED")
GDKPd:RegisterEvent("UNIT_NAME_UPDATE")
GDKPd:RegisterEvent("CHAT_MSG_ADDON")
GDKPd:RegisterEvent("TRADE_MONEY_CHANGED")
GDKPd:RegisterEvent("UI_INFO_MESSAGE")
GDKPd:RegisterEvent("TRADE_CLOSED")
GDKPd:RegisterEvent("TRADE_SHOW")
GDKPd:RegisterEvent("TRADE_ACCEPT_UPDATE")
GDKPd:RegisterEvent("PLAYER_REGEN_ENABLED")
GDKPd:RegisterEvent("PLAYER_REGEN_DISABLED")
GDKPd:RegisterEvent("MAIL_SHOW")
GDKPd:RegisterEvent("MAIL_CLOSED")

--chat filters
local function filterChat_CHAT_MSG_RAID(chatframe,event,msg)
	--auctionAnnounce newBid bidFinished
	if GDKPd.opt.hideChatMessages.auctionAnnounce and msg:match("%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r).")  then
		return true
	end
	if GDKPd.opt.hideChatMessages.newBid and msg:match("%[GDKPd%] New highest bidder(.*): (%S+) %((%d+) gold%)") then
		return true
	end
	if GDKPd.opt.hideChatMessages.bidFinished and msg:match("%[GDKPd%] Auction finished") then
		return true
	end
	if GDKPd.opt.hideChatMessages.secondsRemaining and msg:match("%[GDKPd%] (%d+) seconds remaining(.*)!") then
		return true
	end
	if GDKPd.opt.hideChatMessages.bidChats and (((msg:match("%d+") and (not msg:match("seconds remaining"))) and (GDKPd.InProgressBidFrame or GDKPd.curAuction.item)) or (msg:match("(|c........|Hitem:.+|r)%s*(%d+)") and (GDKPd:FetchFrameFromLink(msg:match("(|c........|Hitem:.+|r)")) or GDKPd.curAuctions[msg:match("(|c........|Hitem:.+|r)")]))) then
		return true
	end
	if GDKPd.opt.hideChatMessages.potValues and msg:match("%[GDKPd%] Current pot: (%d+) gold") then
		return true
	end
	if GDKPd.opt.hideChatMessages.auctionCancel and msg:match("%[GDKPd%] Auction cancelled") then
		return true
	end
	return false
end
--register chat filters
ChatFrame_AddMessageEventFilter("CHAT_MSG_RAID",filterChat_CHAT_MSG_RAID)
ChatFrame_AddMessageEventFilter("CHAT_MSG_RAID_WARNING",filterChat_CHAT_MSG_RAID)
ChatFrame_AddMessageEventFilter("CHAT_MSG_RAID_LEADER",filterChat_CHAT_MSG_RAID)
ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER_INFORM",function(chatframe,event,msg)
	if msg:find(L["[GDKPd] Your version of GDKPd is slightly outdated compared to the raid leader's. Full compability should be possible, however, you might want to take some time and update GDKPd."]:gsub("%[","%%["):gsub("%]","%%]")) then
		return true
	end
	if msg:find(L["[GDKPd] Your version of GDKPd is outdated and no longer compatible with the raid leader's in one or more functionalities. In order to ensure smooth performance, please update GDKPd."]:gsub("%[","%%["):gsub("%]","%%]")) then
		return true
	end
	if msg:find(L["[GDKPd] This raid uses GDKPd to faciliate its GDKP bidding process. While you can bid on items without having GDKPd installed, installing it provides you with a GUI bidding panel, auto bidding functions, auction timers, chat filtering and more!"]:gsub("%[","%%["):gsub("%]","%%]")) then
		return true
	end
end)
--chat filters done
--filter raid warning frame
do
	-- GLOBALS: RaidNotice_AddMessage
	local oldmessage = RaidNotice_AddMessage
	function RaidNotice_AddMessage(frame,text,...)
		if GDKPd.opt.hideChatMessages.auctionAnnounceRW and text:match("%[GDKPd%] Bidding starts on (|c........|Hitem:.+|r).") then
			return
		end
		if GDKPd.opt.hideChatMessages.auctionCancelRW and text:match("%[GDKPd%] Auction cancelled") then
			return
		end
		if GDKPd.opt.hideChatMessages.newBid and text:match("%[GDKPd%] New highest bidder(.*): (%S+) %((%d+) gold%)") then
			return
		end
		oldmessage(frame,text,...)
	end
end
--end raid warning frame filter
--register addon msg prefixes
RegisterAddonMessagePrefix("GDKPD START")
RegisterAddonMessagePrefix("GDKPD VREQ")
RegisterAddonMessagePrefix("GDKPD VDATA")
RegisterAddonMessagePrefix("GDKPD MANADJ")
--prefixes done