--[[
		ADDON  INFORMATION
		Name: AuctionFilterPlus
		Purpose: Adds flyout filters and a reset button to the auction house.
		Command-line: NONE
		Author: Dsanai of The Crimson Knights on Whisperwind

Thank you to the authors of AuctionFilterRL (Joshaze), AH_Reset (AnduinLothar), and AH_Wipe (Neriak), as these mods formed the base for this extension.

I've added a few more filters that I always wished I'd had when shopping (such as only-20-piece stacks, and exact search), changed it to a low-clutter Flyout display, added the ability to clear and save one's filter settings,  merged the two mods into one, and added tooltips so users have more information about what each filter does.

FEATURES
-- Adds a Filter button and a Reset button to the AuctionHouse frame.
-- Pressing the Filter button will cause a Flyout menu to appear.
-- The filter checkboxes on the flyout allow you to limit your AH results or change the display of certain information.
-- You can clear your filter settings with a single click.
-- You can clear your Auction House search boxes with a single click.
-- You can save your filter settings as your default setup, which will persist across sessions, characters, and servers.
-- You can clear your settings temporarily and then reload them without relogging.
-- Each of the filter checkboxes has an explanatory tooltip.
-- Ready for localization (please help do so, if you are German- or French-speaking). You will be credited!
-- Compatible with Auctioneer.

NOT DONE YET
-- Fixed Dressing Room bug. Should now show the correct item even if filters are turned on.
-- Fixed Chat Link bug. Should now link the correct item in chat.

VERSION HISTORY

v10900-1
-- Fixed slash command (courtesy Aingnale@WorldOfWar)
-- Added "Grey Out Unbid Items" option. Will grey out the prices for items that have not been bid on yet. (idea courtesy myShowBid by mhsin)
-- Show Best Deals now takes into account Greater Essences (will be valued as 3 items when competing against Lesser Essences)
-- Fixed so that Auctioneer Beta will also be supported (variable name courtesy barryj@Curse)

v1800-6
-- Added AuctionSort functionality (courtesy Abraha)
-- Added Show Best Deals, which will evaluate prices and tell you how an item fares against the average for the search results.
-- Show Best Deals will also take into account how many pieces of cloth were used to create bolts of cloth, when rating its value.

v1800-5
-- DE translation reworked (courtesy dan2507@Curse)
-- Increased the width of the flyout panel, and of the Clear button, so localized strings should fit.
-- Can be set to color known recipes, plans, schematics, etc. (courtesy LeisureLarry@Curse)
-- Added command-line to open flyout panel, if the button is unclickable due to other mods.

v1800-4
-- Really disables itself when KC_Items is scanning. Thanks, Sharky@Curse.
-- Globalized the "Already Known" string, so all clients should now be able to use that filter. Thanks, Olivier@Curse.

v1800-3
-- Disables itself when KC_Items is scanning.
-- German localization completed (courtesy Dan2507 and Naboradd)
-- Localized checkbox description text.
-- Attempt to fix the occasional tooltip error on line 492. Let me know if tooltips show the wrong item.

v1800-2
-- Disables itself when Auctioneer is scanning.

v1800-1
-- Initial release

POTENTIAL FUTURE ADDITIONS (Subject to change)
-- Filter: Don't show auctions listed by people I've Ignored. (Don't fund the idiots.)
-- Filter: Only show items that haven't been bid on yet. (Try to find ones I can snag at a bargain, without a bidding war.)
-- Filter: Only show XX quality items. (Blizzard quality filter shows that level AND higher.) NOTE: Read Blizzard dropdown.

]]

afp_OriginalAuctionFrameBrowse_Update = nil;
afp_BrowseList = {};
local afp_OldSetWidth = nil;

function AuctionFilterPlus_OnLoad()
	this:RegisterEvent("AUCTION_ITEM_LIST_UPDATE");
	this:RegisterEvent("VARIABLES_LOADED");
	this:RegisterEvent("AUCTION_HOUSE_SHOW");
	-- Set localization for buttons (NOW DONE INTERNALLY)
	-- if (afp_FlyoutButton) then afp_FlyoutButton:SetText(AFP_BUTTON_TEXT_FILTER); end
	SlashCmdList["AUCTIONFILTERPLUS"] = afp_SlashHandler;
	SLASH_AUCTIONFILTERPLUS1 = "/auctionfilterplus"; -- Fixed by Aingnale@WorldOfWar
	SLASH_AUCTIONFILTERPLUS2 = "/afp";
end

function AuctionFilterPlus_OnEvent()

	if (event == "AUCTION_ITEM_LIST_UPDATE") then
		afp_AuctionFrameBrowse_Update();
		
	elseif event == "VARIABLES_LOADED" then
		afp_FlyoutLoad_OnClick();

	elseif (event == "AUCTION_HOUSE_SHOW" and IsAddOnLoaded("Blizzard_AuctionUI")) then
		if (not afp_OriginalAuctionFrameBrowse_Update) then
			afp_OriginalAuctionFrameBrowse_Update = AuctionFrameBrowse_Update;
			AuctionFrameBrowse_Update = afp_AuctionFrameBrowse_Update;

			afp_OriginalBrowseButton_OnClick = BrowseButton_OnClick;
			BrowseButton_OnClick = afp_BrowseButton_OnClick;
	
			afp_OriginalAuctionFrameItem_OnEnter = AuctionFrameItem_OnEnter;
			AuctionFrameItem_OnEnter = afp_AuctionFrameItem_OnEnter;

			afp_OptionButton_PricePerUnit:SetParent(afp_FlyoutFrame);
			afp_OptionButton_HideNoBuyout:SetParent(afp_FlyoutFrame);
			afp_OptionButton_HideUnaffordable:SetParent(afp_FlyoutFrame);
			afp_OptionButton_HideKnown:SetParent(afp_FlyoutFrame);
			afp_OptionButton_StacksOf20:SetParent(afp_FlyoutFrame);
			afp_OptionButton_StacksOf10:SetParent(afp_FlyoutFrame);
			afp_OptionButton_StacksOf5:SetParent(afp_FlyoutFrame);
			afp_OptionButton_ExactName:SetParent(afp_FlyoutFrame);
			afp_OptionButton_ColorKnown:SetParent(afp_FlyoutFrame);
			afp_OptionButton_ShowBestDeals:SetParent(afp_FlyoutFrame);
			afp_OptionButton_GreyUnbid:SetParent(afp_FlyoutFrame);
			
			afp_FlyoutButton:ClearAllPoints()
			afp_FlyoutButton:SetParent(AuctionFrameBrowse);
			afp_FlyoutButton:SetPoint("TOPRIGHT","AuctionFrameBrowse","TOPRIGHT",-13,-14);
			afp_FlyoutButton:Show();
			
			if (AH_ResetButton and AH_ResetButton:IsVisible()) then
				AH_ResetButton:Hide();
			end
			afp_ResetButton:ClearAllPoints()
			afp_ResetButton:SetParent(afp_FlyoutButton);
			afp_ResetButton:SetPoint("LEFT","afp_FlyoutButton","RIGHT",-1,0);
			afp_ResetButton:Show();
		end
		
		-- AuctionSort
		if (not afp_OldSetWidth and BrowseCurrentBidSort) then
			BrowseBuyoutSort:ClearAllPoints();
			BrowseBuyoutSort:SetParent(AuctionFrameBrowse);
			BrowseBuyoutSort:SetPoint("LEFT","BrowseCurrentBidSort","RIGHT",-2,0);
			BrowseBuyoutSort:Show();

			BrowseNameSort:ClearAllPoints();
			BrowseNameSort:SetParent(AuctionFrameBrowse);
			BrowseNameSort:SetPoint("TOPLEFT", "AuctionFrameBrowse", "TOPLEFT", 186, -82);
			BrowseNameSort:Show();

			BrowseQualitySort:ClearAllPoints();
			BrowseQualitySort:SetPoint("LEFT","BrowseNameSort","RIGHT",-2,0);
			BrowseQualitySort:Show();

			afp_OldSetWidth = BrowseCurrentBidSort.SetWidth;

			BrowseCurrentBidSort.SetWidth = afp_SetWidth;
			BrowseCurrentBidSort:SetWidth(207);
			BrowseQualitySort:SetWidth(BrowseQualitySort:GetWidth() - BrowseNameSort:GetWidth());
    end
	end
	
end

function afp_SetWidth(obj, width)
  if (width >= 184) then
    width = width - BrowseBuyoutSort:GetWidth() + 2;
  end
  afp_OldSetWidth(obj, width);
end

function SortBuyoutButton_UpdateArrow(button, type, sort)
	if ( not IsAuctionSortReversed(type, sort) ) then
		getglobal(button:GetName().."Arrow"):SetTexCoord(0, 0.5625, 1.0, 0);
	else
		getglobal(button:GetName().."Arrow"):SetTexCoord(0, 0.5625, 0, 1.0);
	end
end

function afp_FixParents()
	afp_OptionText_HideUnaffordable:ClearAllPoints()
	afp_OptionText_HideKnown:ClearAllPoints()
	afp_OptionText_HideNoBuyout:ClearAllPoints()
	afp_OptionText_PricePerUnit:ClearAllPoints()
	afp_OptionText_StacksOf20:ClearAllPoints()
	afp_OptionText_StacksOf10:ClearAllPoints()
	afp_OptionText_StacksOf5:ClearAllPoints()
	afp_OptionText_ExactName:ClearAllPoints()
	afp_OptionText_ColorKnown:ClearAllPoints()
	afp_OptionText_ShowBestDeals:ClearAllPoints()
	afp_OptionText_GreyUnbid:ClearAllPoints()

	afp_OptionText_HideUnaffordable:SetPoint("LEFT","afp_OptionButton_HideUnaffordable","RIGHT",2,1);
	afp_OptionText_HideKnown:SetPoint("LEFT","afp_OptionButton_HideKnown","RIGHT",2,1);
	afp_OptionText_HideNoBuyout:SetPoint("LEFT","afp_OptionButton_HideNoBuyout","RIGHT",2,1);
	afp_OptionText_PricePerUnit:SetPoint("LEFT","afp_OptionButton_PricePerUnit","RIGHT",2,1);
	afp_OptionText_StacksOf20:SetPoint("LEFT","afp_OptionButton_StacksOf20","RIGHT",2,1);
	afp_OptionText_StacksOf10:SetPoint("LEFT","afp_OptionButton_StacksOf10","RIGHT",2,1);
	afp_OptionText_StacksOf5:SetPoint("LEFT","afp_OptionButton_StacksOf5","RIGHT",2,1);
	afp_OptionText_ExactName:SetPoint("LEFT","afp_OptionButton_ExactName","RIGHT",2,1);
	afp_OptionText_ColorKnown:SetPoint("LEFT","afp_OptionButton_ColorKnown","RIGHT",2,1);
	afp_OptionText_ShowBestDeals:SetPoint("LEFT","afp_OptionButton_ShowBestDeals","RIGHT",2,1);
	afp_OptionText_GreyUnbid:SetPoint("LEFT","afp_OptionButton_GreyUnbid","RIGHT",2,1);
end

function afp_Tooltip(arg1,arg2,arg3,arg4,arg5,arg6)
	if (not arg3) then arg3 = "ANCHOR_LEFT"; end
	if (not arg4) then arg4 = 0; end
	if (not arg5) then arg5 = -40; end
	if (not arg6) then arg6 = afp_FlyoutFrame; end -- can use the reserved word "this" as arg6 if you want
	GameTooltip:SetOwner(arg6, arg3, arg4, arg5);
  GameTooltip:SetText(arg1);
  GameTooltip:AddLine("\n"..arg2, .75, .75, .75, 1);
  GameTooltip:Show();
end

function afp_AuctionFrameBrowse_OnEnter()
	local frame = this:GetName();
	if (not frame) then return; end
	if (frame == "afp_OptionButton_HideUnaffordable") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_UNAFFORD, AFP_TOOLTIP_TEXT_UNAFFORD);
	elseif (frame == "afp_OptionButton_HideKnown") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_HIDEKNOWN, AFP_TOOLTIP_TEXT_HIDEKNOWN);
	elseif (frame == "afp_OptionButton_HideNoBuyout") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_NOBUYOUT, AFP_TOOLTIP_TEXT_NOBUYOUT);
	elseif (frame == "afp_OptionButton_PricePerUnit") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_PERUNIT, AFP_TOOLTIP_TEXT_PERUNIT);
	elseif (frame == "afp_OptionButton_StacksOf20") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_STACK20, AFP_TOOLTIP_TEXT_STACK20);
	elseif (frame == "afp_OptionButton_StacksOf10") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_STACK10, AFP_TOOLTIP_TEXT_STACK10);
	elseif (frame == "afp_OptionButton_StacksOf5") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_STACK5, AFP_TOOLTIP_TEXT_STACK5);
	elseif (frame == "afp_OptionButton_ExactName") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_EXACTNAME, AFP_TOOLTIP_TEXT_EXACTNAME);
	elseif (frame == "afp_OptionButton_ColorKnown") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_COLORKNOWN, AFP_TOOLTIP_TEXT_COLORKNOWN);
	elseif (frame == "afp_OptionButton_ShowBestDeals") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_SHOWBESTDEALS, AFP_TOOLTIP_TEXT_SHOWBESTDEALS);
	elseif (frame == "afp_OptionButton_GreyUnbid") then
		afp_Tooltip(AFP_TOOLTIP_TITLE_GREYUNBID, AFP_TOOLTIP_TEXT_GREYUNBID);
	end
end

function afp_Reset_OnClick()
		PlaySound("igMainMenuOptionCheckBoxOn")
		IsUsableCheckButton:SetChecked()
		UIDropDownMenu_SetSelectedValue(BrowseDropDown, -1)
		AuctionFrameBrowse.selectedClass = nil
		AuctionFrameBrowse.selectedClassIndex = nil
		AuctionFrameFilters_Update()
		BrowseName:SetText("")
		--BrowseName:SetFocus()
		BrowseMinLevel:SetText("")
		BrowseMaxLevel:SetText("")
		AuctionDressUpModel:Dress()
		if (false) then
			ShowOnPlayerCheckButton:SetChecked()
			SHOW_ON_CHAR = "0"
			HideUIPanel(AuctionDressUpFrame)
		end
		afp_Print(AFP_OPTEXT_RESET);
end

function afp_FlyoutClear_OnClick()
	afp_OptionButton_PricePerUnit:SetChecked(0);
	afp_OptionButton_HideNoBuyout:SetChecked(0);
	afp_OptionButton_HideUnaffordable:SetChecked(0);
	afp_OptionButton_HideKnown:SetChecked(0);
	afp_OptionButton_StacksOf20:SetChecked(0);
	afp_OptionButton_StacksOf10:SetChecked(0);
	afp_OptionButton_StacksOf5:SetChecked(0);
	afp_OptionButton_ExactName:SetChecked(0);
	afp_OptionButton_ColorKnown:SetChecked(0);
	afp_OptionButton_ShowBestDeals:SetChecked(0);
	afp_OptionButton_GreyUnbid:SetChecked(0);
	afp_Print(AFP_OPTEXT_CLEARED);
end

function afp_FlyoutSave_OnClick()
	afp_SavedSettings = {};
	afp_SavedSettings["afp_OptionButton_PricePerUnit"] = afp_OptionButton_PricePerUnit:GetChecked();
	afp_SavedSettings["afp_OptionButton_HideNoBuyout"] = afp_OptionButton_HideNoBuyout:GetChecked();
	afp_SavedSettings["afp_OptionButton_HideUnaffordable"] = afp_OptionButton_HideUnaffordable:GetChecked();
	afp_SavedSettings["afp_OptionButton_HideKnown"] = afp_OptionButton_HideKnown:GetChecked();
	afp_SavedSettings["afp_OptionButton_StacksOf20"] = afp_OptionButton_StacksOf20:GetChecked();
	afp_SavedSettings["afp_OptionButton_StacksOf10"] = afp_OptionButton_StacksOf10:GetChecked();
	afp_SavedSettings["afp_OptionButton_StacksOf5"] = afp_OptionButton_StacksOf5:GetChecked();
	afp_SavedSettings["afp_OptionButton_ExactName"] = afp_OptionButton_ExactName:GetChecked();
	afp_SavedSettings["afp_OptionButton_ColorKnown"] = afp_OptionButton_ColorKnown:GetChecked();
	afp_SavedSettings["afp_OptionButton_ShowBestDeals"] = afp_OptionButton_ShowBestDeals:GetChecked();
	afp_SavedSettings["afp_OptionButton_GreyUnbid"] = afp_OptionButton_GreyUnbid:GetChecked();
	afp_Print(AFP_OPTEXT_SAVED);
end

function afp_FlyoutLoad_OnClick()
		if (afp_SavedSettings) then
			if (afp_SavedSettings["afp_OptionButton_PricePerUnit"]) then
				afp_OptionButton_PricePerUnit:SetChecked(afp_SavedSettings["afp_OptionButton_PricePerUnit"]);
			end
			if (afp_SavedSettings["afp_OptionButton_HideNoBuyout"]) then
				afp_OptionButton_HideNoBuyout:SetChecked(afp_SavedSettings["afp_OptionButton_HideNoBuyout"]);
			end
			if (afp_SavedSettings["afp_OptionButton_HideUnaffordable"]) then
				afp_OptionButton_HideUnaffordable:SetChecked(afp_SavedSettings["afp_OptionButton_HideUnaffordable"]);
			end
			if (afp_SavedSettings["afp_OptionButton_HideKnown"]) then
				afp_OptionButton_HideKnown:SetChecked(afp_SavedSettings["afp_OptionButton_HideKnown"]);
			end
			if (afp_SavedSettings["afp_OptionButton_StacksOf20"]) then
				afp_OptionButton_StacksOf20:SetChecked(afp_SavedSettings["afp_OptionButton_StacksOf20"]);
			end
			if (afp_SavedSettings["afp_OptionButton_StacksOf10"]) then
				afp_OptionButton_StacksOf10:SetChecked(afp_SavedSettings["afp_OptionButton_StacksOf10"]);
			end
			if (afp_SavedSettings["afp_OptionButton_StacksOf5"]) then
				afp_OptionButton_StacksOf5:SetChecked(afp_SavedSettings["afp_OptionButton_StacksOf5"]);
			end
			if (afp_SavedSettings["afp_OptionButton_ExactName"]) then
				afp_OptionButton_ExactName:SetChecked(afp_SavedSettings["afp_OptionButton_ExactName"]);
			end
			if (afp_SavedSettings["afp_OptionButton_ColorKnown"]) then
				afp_OptionButton_ColorKnown:SetChecked(afp_SavedSettings["afp_OptionButton_ColorKnown"]);
			end
			if (afp_SavedSettings["afp_OptionButton_ShowBestDeals"]) then
				afp_OptionButton_ShowBestDeals:SetChecked(afp_SavedSettings["afp_OptionButton_ShowBestDeals"]);
			end
			if (afp_SavedSettings["afp_OptionButton_GreyUnbid"]) then
				afp_OptionButton_GreyUnbid:SetChecked(afp_SavedSettings["afp_OptionButton_GreyUnbid"]);
			end
		end
end

function afp_AuctionFrameBrowse_Update()

	-- Trap for, and prevent, filters from doing anything while Auctioneer is scanning.
	if ((Auctioneer_isScanningRequested and Auctioneer_isScanningRequested==true) or (Auctioneer and Auctioneer.Scanning and Auctioneer.Scanning.IsScanningRequested and Auctioneer.Scanning.IsScanningRequested==true)) then
		return;
	end
	-- Trap for, and prevent, filters from doing anything while KCI is scanning.
	if (KC_ItemsAuction and KC_ItemsAuction.scanning) then
		return;
	end
	
	local numBatchAuctions, totalAuctions = GetNumAuctionItems("list");
	local button, buttonName, iconTexture, itemName, color, itemCount, moneyFrame, buyoutMoneyFrame, buyoutText, buttonHighlight;
	local offset = FauxScrollFrame_GetOffset(BrowseScrollFrame);
	local index;
	local isLastSlotEmpty;
	local name, texture, count, quality, canUse, minBid, minIncrement, buyoutPrice, duration, bidAmount, highBidder, owner;
	BrowseBidButton:Disable();
	BrowseBuyoutButton:Disable();
	-- Update sort arrows
	SortButton_UpdateArrow(BrowseQualitySort, "list", "quality");
	SortButton_UpdateArrow(BrowseLevelSort, "list", "level");
	SortButton_UpdateArrow(BrowseDurationSort, "list", "duration");
	SortButton_UpdateArrow(BrowseHighBidderSort, "list", "status");
	SortButton_UpdateArrow(BrowseCurrentBidSort, "list", "bid");

	-- Show the no results text if no items found
	if ( numBatchAuctions == 0 ) then
		BrowseNoResultsText:Show();
	else
		BrowseNoResultsText:Hide();
	end
	
	local baseAve = 0; bestAve = 0; worstAve = 0;
	local baseAveTable = {};
	-- Get the highest non-outlier value (only when Exact Name is turned on)
	if (afp_OptionButton_ShowBestDeals:GetChecked()) then
	--if (afp_OptionButton_ExactName:GetChecked() and BrowseName and BrowseName:GetText() ~= "") then
		for i=1, NUM_BROWSE_TO_DISPLAY do
			--for n=1,NUM_AUCTION_ITEMS_PER_PAGE do
				name,_,count,_,_,_,minBid,_,buyoutPrice,bidAmount,_,_ =  GetAuctionItemInfo("list", i); -- name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner
				if (name and BrowseName and string.lower(name) == string.lower(BrowseName:GetText())) or not afp_OptionButton_ExactName:GetChecked() then
					-- Account for crafted Bolts of Cloth
					if (name==AFP_ITEM_BOLT_LINEN) then
						count = count * 2;
					elseif (name==AFP_ITEM_BOLT_WOOL) then
						count = count * 3;
					elseif (name==AFP_ITEM_BOLT_SILK) then
						count = count * 4;
					elseif (name==AFP_ITEM_BOLT_MAGEWEAVE) then
						count = count * 5;
					elseif (name==AFP_ITEM_BOLT_RUNECLOTH) then
						count = count * 5;
					elseif (name==AFP_ITEM_ESSENCE_ETERNAL) then
						count = count * 3;
					elseif (name==AFP_ITEM_ESSENCE_NETHER) then
						count = count * 3;
					elseif (name==AFP_ITEM_ESSENCE_MYSTIC) then
						count = count * 3;
					elseif (name==AFP_ITEM_ESSENCE_ASTRAL) then
						count = count * 3;
					elseif (name==AFP_ITEM_ESSENCE_MAGIC) then
						count = count * 3;
					end
					if ( buyoutPrice > 0 ) then
						table.insert(baseAveTable, buyoutPrice/count);
					elseif (not afp_OptionButton_HideNoBuyout:GetChecked()) then
						-- Don't use bids if HideNoBuyout is on!
						if ( bidAmount == 0 ) then
							table.insert(baseAveTable, minBid/count);
						else
							table.insert(baseAveTable, bidAmount/count);
						end
					end
				end
			--end
		end
	--end
	end
	if (table.getn(baseAveTable) > 0) then
		table.sort(baseAveTable);
		baseAve = baseAveTable[math.floor(table.getn(baseAveTable)/2)];
		bestAve = baseAveTable[1];
		worstAve = baseAveTable[table.getn(baseAveTable)];
--afp_Print("baseAveTable rows="..table.getn(baseAveTable)..", baseAve="..baseAve..", bestAve="..bestAve..", worstAve="..worstAve);
	end
	if (not baseAve) then baseAve = 0; end
	
	for i=1, NUM_BROWSE_TO_DISPLAY do
		if (afp_OptionButton_HideKnown:GetChecked() or afp_OptionButton_HideNoBuyout:GetChecked() or afp_OptionButton_HideUnaffordable:GetChecked() or afp_OptionButton_StacksOf20:GetChecked() or afp_OptionButton_StacksOf10:GetChecked() or afp_OptionButton_StacksOf5:GetChecked() or afp_OptionButton_ExactName:GetChecked() or afp_OptionButton_ColorKnown:GetChecked() or afp_OptionButton_GreyUnbid:GetChecked()) then
			local skipItem;
			for n=1,NUM_AUCTION_ITEMS_PER_PAGE do
				AFHiddenTooltip:ClearLines();
				name,_,count,quality,_,_,_,_,buyoutPrice,_,_,owner =  GetAuctionItemInfo("list", offset + i); -- name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner
				AFHiddenTooltip:SetAuctionItem("list", offset + i);
				skipItem = 0;
				if (afp_OptionButton_HideKnown:GetChecked()) then
					if ((AFHiddenTooltipTextLeft3:GetText() == ITEM_SPELL_KNOWN) and (AFHiddenTooltip:NumLines() >= 3)) then
						skipItem = 1;
					elseif ((AFHiddenTooltipTextLeft4:GetText() == ITEM_SPELL_KNOWN) and (AFHiddenTooltip:NumLines() >= 4)) then
						skipItem = 1;
					end
				end
				if ((buyoutPrice == 0) and (afp_OptionButton_HideNoBuyout:GetChecked())) then
					skipItem = 1;
				end
				if ((GetMoney() < buyoutPrice) and (afp_OptionButton_HideUnaffordable:GetChecked())) then
					skipItem = 1;
				end
				if (count ~= 20 and afp_OptionButton_StacksOf20:GetChecked()) then
					skipItem = 1;
				end
				if (count ~= 10 and afp_OptionButton_StacksOf10:GetChecked()) then
					skipItem = 1;
				end
				if (count ~= 5 and afp_OptionButton_StacksOf5:GetChecked()) then
					skipItem = 1;
				end
				if (BrowseName and name and BrowseName:GetText() and string.lower(name) ~= string.lower(BrowseName:GetText()) and afp_OptionButton_ExactName:GetChecked()) then
					skipItem = 1;
				end
				if (skipItem == 1) then
					offset = offset + 1;
				else
					afp_BrowseList[i] = offset;
				end
			end
		else
			for n=1,NUM_BROWSE_TO_DISPLAY do
				afp_BrowseList[n] = offset;
			end
		end
		index = offset + i + (NUM_AUCTION_ITEMS_PER_PAGE * AuctionFrameBrowse.page);
		button = getglobal("BrowseButton"..i);
		-- Show or hide auction buttons
		if ( index > (numBatchAuctions + (NUM_AUCTION_ITEMS_PER_PAGE * AuctionFrameBrowse.page)) ) then
			button:Hide();
			--button:SetVertexColor(0,0,0);
			-- If the last button is empty then set isLastSlotEmpty var
			if ( i == NUM_BROWSE_TO_DISPLAY ) then
				isLastSlotEmpty = 1;
			end
		else -- EMERALD: BlackOut (if skipItem==1 then BlackOut)
			button:Show();
			buttonName = "BrowseButton"..i;
			name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner =  GetAuctionItemInfo("list", offset + i);
			duration = GetAuctionItemTimeLeft("list", offset + i);
			-- Resize button if there isn't a scrollbar
			buttonHighlight = getglobal("BrowseButton"..i.."Highlight");
			if ( numBatchAuctions <= NUM_BROWSE_TO_DISPLAY ) then
				button:SetWidth(625);
				buttonHighlight:SetWidth(589);
				BrowseCurrentBidSort:SetWidth(207);
			elseif ( numBatchAuctions == NUM_BROWSE_TO_DISPLAY and totalAuctions <= NUM_BROWSE_TO_DISPLAY ) then
				button:SetWidth(625);
				buttonHighlight:SetWidth(589);
				BrowseCurrentBidSort:SetWidth(207);
			else
				button:SetWidth(600);
				buttonHighlight:SetWidth(562);
				BrowseCurrentBidSort:SetWidth(184);
			end
			-- Set name and quality color
			color = ITEM_QUALITY_COLORS[quality];
			itemName = getglobal(buttonName.."Name");
			local newName;
			local thisPrice = 0;
			local thisCount = 0;
			newName = GetHex(color.r,color.g,color.b)..name..FONT_COLOR_CODE_CLOSE;
			if (afp_OptionButton_ShowBestDeals:GetChecked()) then
				if (baseAve ~= 0) then
					-- Account for crafted Bolts of Cloth
					if (name==AFP_ITEM_BOLT_LINEN) then
						thisCount = count * 2;
					elseif (name==AFP_ITEM_BOLT_WOOL) then
						thisCount = count * 3;
					elseif (name==AFP_ITEM_BOLT_SILK) then
						thisCount = count * 4;
					elseif (name==AFP_ITEM_BOLT_MAGEWEAVE) then
						thisCount = count * 5;
					elseif (name==AFP_ITEM_BOLT_RUNECLOTH) then
						thisCount = count * 5;
					else
						thisCount = count;
					end
					if ( buyoutPrice > 0 ) then
						thisPrice = afp_Round(buyoutPrice/thisCount);
					else
						if ( bidAmount == 0 ) then
							thisPrice = afp_Round(minBid/thisCount);
						else
							thisPrice = afp_Round(bidAmount/thisCount);
						end
					end
					newName = newName.." ";
--afp_Print("thisPrice="..thisPrice..", best="..(bestAve * 1.2)..", worst="..(worstAve / 1.2)..", base="..baseAve);
--afp_Print("thisPrice="..thisPrice..", base="..baseAve);
					--if (thisPrice <= bestAve * 1.05) then -- Best Price
					--if (thisPrice <= bestAve) then -- Best Price
					if (thisPrice <= (baseAve / 2.2) or thisPrice <= bestAve) then -- Best Price
						newName = newName..GetHex(0.6,1,0.6).."(Best)";
					--elseif (thisPrice >= worstAve / 1.05) then -- Worst Price
					--elseif (thisPrice >= worstAve) then -- Worst Price
					elseif (thisPrice) >= (baseAve * 2.5) then -- Worst Price
						newName = newName..GetHex(1,0,0).."(Worst)+"..math.floor((thisPrice/baseAve)*100).."%";
					elseif (thisPrice) >= (baseAve * 1.8) then -- Bad Price
						newName = newName..GetHex(1,0.3,0.3).."(Worse)+"..math.floor((thisPrice/baseAve)*100).."%";
					elseif (thisPrice) >= (baseAve * 1.4) then -- Bad Price
						newName = newName..GetHex(1,0.6,0.6).."(Bad)+"..math.floor((thisPrice/baseAve)*100).."%";
					elseif (thisPrice <= (baseAve / 1.5)) then -- Great Price
						newName = newName..GetHex(0.3,1,0.3).."(Great)";
					elseif (thisPrice < baseAve) then -- Good Price
						newName = newName..GetHex(0,1,0).."(Good)";
					else -- Median Price
						newName = newName..GetHex(1,1,0).."(Average)";
					end
					newName = newName..FONT_COLOR_CODE_CLOSE;
				end
			end
			itemName:SetText(newName);
			--itemName:SetVertexColor(color.r, color.g, color.b);
			--if (skipItem==1) then itemName:SetVertexColor(0,0,0); end
			-- Set level
			if ( level > UnitLevel("player") ) then
				getglobal(buttonName.."Level"):SetText(RED_FONT_COLOR_CODE..level..FONT_COLOR_CODE_CLOSE);
			else
				getglobal(buttonName.."Level"):SetText(level);
			end
			--if (skipItem==1) then getglobal(buttonName.."Level"):SetVertexColor(0,0,0); end
			-- Set closing time
			getglobal(buttonName.."ClosingTimeText"):SetText(AuctionFrame_GetTimeLeftText(duration));
			getglobal(buttonName.."ClosingTime").tooltip = AuctionFrame_GetTimeLeftTooltipText(duration);
			--if (skipItem==1) then getglobal(buttonName.."ClosingTimeText"):SetVertexColor(0,0,0); end
			--if (skipItem==1) then getglobal(buttonName.."ClosingTime"):SetVertexColor(0,0,0); end
			-- Set item texture, count, and usability
			iconTexture = getglobal(buttonName.."ItemIconTexture");
			iconTexture:SetTexture(texture);
			if ( not canUse ) then
				iconTexture:SetVertexColor(1.0, 0.1, 0.1);
			else
				iconTexture:SetVertexColor(1.0, 1.0, 1.0);
			end
			itemCount = getglobal(buttonName.."ItemCount");
			if ( count > 1 ) then
				itemCount:SetText(count);
				itemCount:Show();
			else
				itemCount:Hide();
			end
			-- Color known recipe (courtesy LeisureLarry@Curse)
			if (afp_OptionButton_ColorKnown:GetChecked() and (AFHiddenTooltip:NumLines() >= 3)) then
				if (AFHiddenTooltipTextLeft3:GetText() == ITEM_SPELL_KNOWN) then
					-- Set color of icon to blue to make it easy to see that you already know it.
					iconTexture = getglobal("BrowseButton"..i.."ItemIconTexture");
					iconTexture:SetVertexColor(0, 0, 0.8);
				elseif ((AFHiddenTooltip:NumLines() >= 4) and (AFHiddenTooltipTextLeft4:GetText() == ITEM_SPELL_KNOWN)) then
					-- Set color of icon to blue to make it easy to see that you already know it.
					iconTexture = getglobal("BrowseButton"..i.."ItemIconTexture");
					iconTexture:SetVertexColor(0, 0, 0.8);
				end
			end
			--if (skipItem==1) then iconTexture:SetVertexColor(0,0,0); end
			-- Set high bid
			moneyFrame = getglobal(buttonName.."MoneyFrame");
			yourBidText = getglobal(buttonName.."YourBidText");
			buyoutMoneyFrame = getglobal(buttonName.."BuyoutMoneyFrame");
			buyoutText = getglobal(buttonName.."BuyoutText");
			-- If not bidAmount set the bid amount to the min bid
			if ( bidAmount == 0 ) then
				if (afp_OptionButton_PricePerUnit:GetChecked()) then
					MoneyFrame_Update(moneyFrame:GetName(), afp_Round(minBid/count));
				else
					MoneyFrame_Update(moneyFrame:GetName(), minBid);
				end
			else
				if (afp_OptionButton_PricePerUnit:GetChecked()) then
					MoneyFrame_Update(moneyFrame:GetName(), afp_Round(bidAmount/count));
				else
					MoneyFrame_Update(moneyFrame:GetName(), bidAmount);
				end
				if (afp_OptionButton_GreyUnbid:GetChecked()) then -- myShowBid functionality
					moneyFrame:SetAlpha(0.5);
				else
					moneyFrame:SetAlpha(1.0);
				end
			end
--if (skipItem==1) then moneyFrame:Hide(); end
			if ( highBidder ) then
				yourBidText:Show();
			else
				yourBidText:Hide();
			end
--if (skipItem==1) then yourBidText:Hide(); end
			if ( buyoutPrice > 0 ) then
				moneyFrame:SetPoint("RIGHT", buttonName, "RIGHT", 10, 10);
				if (afp_OptionButton_PricePerUnit:GetChecked()) then
					MoneyFrame_Update(buyoutMoneyFrame:GetName(), afp_Round(buyoutPrice/count));
				else
					MoneyFrame_Update(buyoutMoneyFrame:GetName(), buyoutPrice);
				end
				buyoutMoneyFrame:Show();
				buyoutText:Show();
			else
				moneyFrame:SetPoint("RIGHT", buttonName, "RIGHT", 10, 3);
				buyoutMoneyFrame:Hide();
				buyoutText:Hide();
			end
--if (skipItem==1) then buyoutMoneyFrame:Hide(); buyoutText:Hide(); end
			-- Set high bidder
			--if ( not highBidder ) then
			--	highBidder = RED_FONT_COLOR_CODE..NO_BIDS..FONT_COLOR_CODE_CLOSE;
			--end
			getglobal(buttonName.."HighBidder"):SetText(owner);
			--if (skipItem==1) then getglobal(buttonName.."HighBidder"):SetVertexColor(0,0,0); end
			-- Set highlight
			if ( GetSelectedAuctionItem("list") and (offset + i) == GetSelectedAuctionItem("list") ) then
				button:LockHighlight();

				if ( buyoutPrice > 0 and buyoutPrice >= minBid and GetMoney() >= buyoutPrice ) then
					BrowseBuyoutButton:Enable();
					AuctionFrame.buyoutPrice = buyoutPrice;
				else
					AuctionFrame.buyoutPrice = nil;
				end
				-- Set bid
				if ( bidAmount > 0 ) then
					bidAmount = bidAmount + minIncrement ;
					MoneyInputFrame_SetCopper(BrowseBidPrice, bidAmount);
				else
					MoneyInputFrame_SetCopper(BrowseBidPrice, minBid);
				end

				if ( not highBidder and GetMoney() >= MoneyInputFrame_GetCopper(BrowseBidPrice) ) then
					BrowseBidButton:Enable();
				end
			else
				button:UnlockHighlight();
			end
			
		end
	end

	-- Update scrollFrame
	-- If more than one page of auctions show the next and prev arrows when the scrollframe is scrolled all the way down
	if ( totalAuctions > NUM_AUCTION_ITEMS_PER_PAGE ) then
		if ( isLastSlotEmpty ) then
			BrowsePrevPageButton:Show();
			BrowseNextPageButton:Show();
			BrowseSearchCountText:Show();
			local itemsMin = AuctionFrameBrowse.page * NUM_AUCTION_ITEMS_PER_PAGE + 1;
			local itemsMax = itemsMin + numBatchAuctions - 1;
			BrowseSearchCountText:SetText(format(NUMBER_OF_RESULTS_TEMPLATE, itemsMin, itemsMax, totalAuctions ));
			if ( AuctionFrameBrowse.page == 0 ) then
				BrowsePrevPageButton.isEnabled = nil;
			else
				BrowsePrevPageButton.isEnabled = 1;
			end
			if ( AuctionFrameBrowse.page == (ceil(totalAuctions/NUM_AUCTION_ITEMS_PER_PAGE) - 1) ) then
				BrowseNextPageButton.isEnabled = nil;
			else
				BrowseNextPageButton.isEnabled = 1;
			end
		else
			BrowsePrevPageButton:Hide();
			BrowseNextPageButton:Hide();
			BrowseSearchCountText:Hide();
		end

		-- Artifically inflate the number of results so the scrollbar scrolls one extra row
		numBatchAuctions = numBatchAuctions + 1;
	else
		BrowsePrevPageButton:Hide();
		BrowseNextPageButton:Hide();
		BrowseSearchCountText:Hide();
	end
	FauxScrollFrame_Update(BrowseScrollFrame, numBatchAuctions, NUM_BROWSE_TO_DISPLAY, AUCTIONS_BUTTON_HEIGHT);
end

function afp_BrowseButton_OnClick(button)
	if ( not button ) then
		button = this;
	end
	--afp_Print("OnClick");
	--if ( IsControlKeyDown() ) then -- Dressing Room (THIS DOESN'T WORK, and I don't know why)
		--DressUpItemLink(GetAuctionItemLink("list", button:GetID() + afp_BrowseList[button:GetID()]));
		--afp_Print("DressUpItemLink");
	--elseif ( IsShiftKeyDown() ) then -- Text link
		--if ( ChatFrameEditBox:IsVisible() ) then
			--ChatFrameEditBox:Insert(GetAuctionItemLink("list", button:GetID() + afp_BrowseList[button:GetID()]));
			--afp_Print("ChatFrameEditBox");
		--end
	--else
		SetSelectedAuctionItem("list", button:GetID() + afp_BrowseList[button:GetID()]);
		afp_AuctionFrameBrowse_Update();
		--afp_Print("Else");
	--end
end

function afp_AuctionFrameItem_OnEnter(type, index)
	if (this:GetParent():GetID()) then -- EMERALD: Test
		index = this:GetParent():GetID();
	end
	if (afp_BrowseList and afp_BrowseList[this:GetParent():GetID()]) then
		index = index + afp_BrowseList[this:GetParent():GetID()];
	end
  afp_OriginalAuctionFrameItem_OnEnter(type, index)
end

function afp_FlyoutButton_OnClick()
	if (afp_FlyoutButton and afp_FlyoutButton:IsVisible()) then
		if (afp_FlyoutFrame and afp_FlyoutFrame:IsVisible()) then
			afp_FlyoutFrame:Hide();
			afp_FlyoutClear:Hide();
			afp_FlyoutSave:Hide();
			--afp_Print("afDEBUG: Hiding Flyout");
		elseif (afp_FlyoutFrame) then
			--CHANGE SIZE BASED ON NUMBER OF VISIBLE LINES (height=lines*19)
			afp_FlyoutFrame:SetHeight(13*19); -- Currently: 13 Lines
			afp_FlyoutFrame:SetParent(AuctionFrameBrowse);
			--afp_FlyoutFrame:SetPoint("TOPLEFT","AuctionFrameBrowse","TOPRIGHT",70,40);
			afp_FlyoutFrame:SetPoint("TOPLEFT","AuctionFrame","TOPRIGHT",4,-9);
			afp_FlyoutFrame:Show();
			afp_FlyoutClear:SetParent(afp_FlyoutFrame);
			afp_FlyoutClear:SetPoint("TOPLEFT","afp_FlyoutFrame","BOTTOMLEFT",1,0);
			afp_FlyoutClear:Show();
			afp_FlyoutSave:SetParent(afp_FlyoutFrame);
			afp_FlyoutSave:SetPoint("TOPRIGHT","afp_FlyoutFrame","BOTTOMRIGHT",-1,0);
			afp_FlyoutSave:Show();
			afp_FlyoutLoad:SetParent(afp_FlyoutFrame);
			afp_FlyoutLoad:SetPoint("TOPRIGHT","afp_FlyoutSave","BOTTOMRIGHT",0,0);
			afp_FlyoutLoad:Show();
			--afp_Print("afDEBUG: Showing Flyout");
		else
			--afp_Print("afDEBUG: ERROR: NO STATE!");
		end
	end
end

--[[ COMMON FUNCTIONS ]]

function afp_SlashHandler(msg)
	if (msg=="show" or msg=="hide") then msg = ""; end
	if (not msg or msg=="") then
		--Base command
		if (afp_FlyoutButton and afp_FlyoutButton:IsVisible()) then
			afp_FlyoutButton_OnClick();
		else
			afp_Print("The Flyout cannot be shown if the Auction window is not on the Browse tab.");
		end
	end
end

function afp_Print(message) -- Send Message to Chat Frame
	DEFAULT_CHAT_FRAME:AddMessage("[AuctionFilterPlus] "..message, 1.0, 1.0, 1.0);
end

function afp_PrintError(message) -- Send Error to Chat Frame
	DEFAULT_CHAT_FRAME:AddMessage("[AuctionFilterPlus] ERROR: "..message, 1.0, 0, 0);
end

function afp_Round(x)
	if (x - math.floor(x) > 0.5) then
		x = x + 0.5;
	end
	return math.floor(x);
end

--courtesy watchdog:
function GetHex(r,g,b)

	if g then
		return string.format("|cFF%02X%02X%02X", (255*r), (255*g), (255*b));
	elseif r then
		return string.format("|cFF%02X%02X%02X", (255*r.r), (255*r.g), (255*r.b));
	else
		return "";
	end

end
