--[[ ---------------------------------------------------------------------------
Created:		7/20/2010 6:08:47 AM
Last Modified:	2011-04-29T08:44:39Z
Author:			orgevo
Version:		v1.3a

AtlasLootAdvancedSearch:	Main module for AtlasLoot_AdvancedSearch.

AtlasLoot_AdvancedSearch is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

AtlasLoot_AdvancedSearch is distributed WITHOUT ANY WARRANTY; without even the 
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with AtlasLoot_AdvancedSearch.	If not, see <http://www.gnu.org/licenses/>.

----------------------------------------------------------------------------- ]]

--[[
	Future:
		- create interactive dialog which allows the user to enter values for the various search parameters seperately
		-- i.e. dialog with a box for them to enter the Zone, box to enter the item slot name, etc.
		
		- "Whole words only" filter option (not sure if best to implement as a flag or as a search module...hummm)
--]]


local ADDON_TAG				= "AtlasLootAdvancedSearch"
local SETTINGS_TAG			= ADDON_TAG .. "Config";

-- create the proxy for this addon to use the Ace3 library
local ace_addon				= LibStub("AceAddon-3.0");
AtlasLootAdvancedSearch = ace_addon:NewAddon("AtlasLootAdvancedSearch",
	"AceConsole-3.0",
	"AceHook-3.0",
	"AceEvent-3.0"
	)
	
--@non-debug@
local alas_addon			= AtlasLootAdvancedSearch;
oe_internal					= false;
alas_addon.ENABLE_LOGGING	= false;
alas_addon.ALLOW_SLOW_FUNCS	= false;
alas_addon.ALLOW_SLOW_LOGS	= false;
--@end-non-debug@


--[===[@debug@
alas_addon					= AtlasLootAdvancedSearch;
local alas_addon = alas_addon;
oe_internal					= true;
local CORE_DEBUG			= false
alas_addon.ENABLE_LOGGING	= true;
alas_addon.ALLOW_SLOW_FUNCS	= false;
alas_addon.ALLOW_SLOW_LOGS	= false;
--@end-debug@]===]
local ALLOW_SLOW_FUNCS		= alas_addon.ALLOW_SLOW_FUNCS;
local ALLOW_SLOW_LOGS		= alas_addon.ALLOW_SLOW_LOGS;

local al_addon				= AtlasLoot;
_G[ADDON_TAG]				= alas_addon
local ENABLE_LOGGING		= alas_addon.ENABLE_LOGGING and CORE_DEBUG

-- localization
local L						= LibStub("AceLocale-3.0"):GetLocale(ADDON_TAG, true)
local AL					= LibStub("AceLocale-3.0"):GetLocale("AtlasLoot");
local ace_config			= LibStub("AceConfig-3.0")
local ace_reg				= LibStub("AceConfigRegistry-3.0")
local ADDON_NAME			= L["ADDON_NAME"]

-- needed by AtlasLoot code
alas_addon.GREY			= "|cff999999";
alas_addon.DARKGREY		= "|cff9d9d9d"; -- 0
alas_addon.WHITE		= "|cffffffff";--1
alas_addon.GREEN		= "|cff1eff00";--2
alas_addon.BLUE			= "|cff0070dd";--3
alas_addon.PURPLE		= "|cffa335ee";--4
alas_addon.ORANGE		= "|cffff8000";--5
alas_addon.RED			= "|cffff0000";--6
alas_addon.BROWN		= "|cffe6cc80"; --7

local RED = alas_addon.RED;
local WHITE = alas_addon.WHITE;
local GREEN = alas_addon.GREEN;
local RED_FONT_COLOR_CODE, GREEN_FONT_COLOR_CODE, FONT_COLOR_CODE_CLOSE = RED_FONT_COLOR_CODE, GREEN_FONT_COLOR_CODE, FONT_COLOR_CODE_CLOSE

local MAX_ITEMID_DIGITS = 5;
local RedirectOnClickScript, VerifyItemButtonClickHandlers;

_G["AL_SEARCHMODULES"] = {}		-- this is where we're look for additional modules
alas_addon.SearchModules = nil;
alas_addon.SearchParameters = nil;
alas_addon.CategorizedSearchResults = nil;
local registerModuleDefaults = true;

-- transition helpers; used to temporarily disable code that isn't yet ready in AL
local ATLASLOOT_SUPPORTS_MODULE_SELECTION = nil;

-- abbreviation
local tinsert, tconcat, tsort = table.insert, table.concat, table.sort
local strlen, strmatch, strfind, strsub, strformat, strlower, strupper, spad, strtrim = string.len, string.match, string.find, string.sub, string.format, string.lower, string.upper, string.rep, strtrim
local strgsub = string.gsub;
local pairs, ipairs, next, type, tostring = pairs, ipairs, next, type, tostring
local bit_ls, bit_rs, bit_or, bit_and, bit_not = bit.lshift, bit.rshift, bit.bor, bit.band, bit.bnot
local tonumber = tonumber;
local AtlasLoot_Data, AtlasLoot_TableNames = AtlasLoot_Data, AtlasLoot_TableNames
local debugprofilestart, debugprofilestop, GetItemInfo = debugprofilestart, debugprofilestop, GetItemInfo

--[[
CAUTION:
	this table's indexes are used for bit-shifting operations on the variable used for tracking whether a particular search module has
	processed an item's data, so it is very important that access to the searchModules table itself remain private to this file.
--]]
local searchModules, searchModuleIndex;
local LootTableItemCache = { }

alas_addon.options = nil;
alas_addon.defaults = nil;
alas_addon.dev_mode = false;

alas_addon.DebugProxy = {
	isEnabled = alas_addon.ENABLE_LOGGING,
	funcTraceIndent = 0,
	DebugOptionsTable = nil,
}

local dbgProxy = alas_addon.DebugProxy;

-- print wrappers
-- t_print (testing): what I use while developing....most of these will be commented out in the repository versions
-- dev_print (development): outputs only when AtlasLootAdvancedSearch.dev_mode is true
local function r_print(str)			alas_addon:Print(str); end
local function r_printf(str,...)	alas_addon:Print(strformat(str,...)); end

local function isDevMode()			return dbgProxy and dbgProxy:isDevMode() end
local function isInternal()			return dbgProxy and dbgProxy:isInternal() end

local function t_print(str)			if dbgProxy and ENABLE_LOGGING then dbgProxy:t_print(str) end end
local function t_printf(str,...)	if dbgProxy and ENABLE_LOGGING then dbgProxy:t_printf(str, ...) end end
local function dev_print(str)		if dbgProxy and ENABLE_LOGGING then dbgProxy:dev_print(str) end end
local function dev_printf(str, ...)	if dbgProxy and ENABLE_LOGGING then dbgProxy:dev_printf(str,...) end end
local function d_print(str)			if dbgProxy and ENABLE_LOGGING then dbgProxy:d_print(str) end end
local function d_printf(str,...)	if dbgProxy and ENABLE_LOGGING then dbgProxy:d_printf(str,...) end end
local function funcEnter(obj, funcName, formatStr, ...)
	if alas_addon.DebugProxy.isEnabled and ENABLE_LOGGING then
		if formatStr then alas_addon.DebugProxy:TraceEnter(obj,funcName,strformat(formatStr,...));
		else alas_addon.DebugProxy:TraceEnter(obj,funcName); end
	end
end

local function funcExit(obj, funcName, formatStr, ...)
	if alas_addon.DebugProxy.isEnabled and ENABLE_LOGGING then
		if formatStr then alas_addon.DebugProxy:TraceExit(obj,funcName,strformat(formatStr,...));
		else alas_addon.DebugProxy:TraceExit(obj,funcName); end
	end
end
local function funcEnterSlow(obj, funcName, formatStr, ...)
	if ALLOW_SLOW_FUNCS then funcEnter(obj, funcName, formatStr, ...); end
end
local function funcExitSlow(obj, funcName, formatStr, ...)
	if ALLOW_SLOW_FUNCS then funcExit(obj, funcName, formatStr, ...); end
end
local function t_printSlow(str)			if alas_addon.ALLOW_SLOW_LOGS then t_print(str)		end end
local function t_printfSlow(str,...)	if alas_addon.ALLOW_SLOW_LOGS then t_printf(str,...)	end end

--[[
local _G = _G;	-- save a reference to the global environment
setfenv(1, setmetatable( {}, {
	__index = function(t, k)
		local v = _G[k]
		_G.print("Accessing global variable " .. k .. "; current value: " .. _G.tostring(v))
		return v;
	end,
	__newindex = function(t, k, v)
		local oldValue = _G[k];
		print("Setting variable in global environment " .. k .. " to " .. _G.tostring(v) .. "; old value: " .. _G.tostring(oldvalue));
		_G[k] = v;
	end
}))
--]]
local function truefalse(cond)
	if cond then return GREEN_FONT_COLOR_CODE .. "true" .. FONT_COLOR_CODE_CLOSE
	else return RED_FONT_COLOR_CODE .. "false" .. FONT_COLOR_CODE_CLOSE; end
end
function toggledebug_core()
	CORE_DEBUG = not CORE_DEBUG;
end

function ALAS_IsUsingNewAtlasLootBossView()
	if AtlasLoot.db.profile.AtlasType == "Preview" then
		return true;
	end
	return false;
end


-- Addon authors should call this function to enable additional log messages which will be helpful in debugging during development of additional search modules.
function AtlasLootAdvancedSearch:EnableDeveloperMode( value )
	if not value then value = true; end
	if type(value) == "boolean" then
		if value then r_print("Enabling developer mode.");
		else r_print("Disabling developer mode."); end
		alas_addon.dev_mode = value;
		if alas_addon.dev_mode then
			-- reset any cached data that is now out of date.
			self:ClearCachedZoneData();
		end
	end
end

local defaults = {
	profile = {
		EnableAdvancedSearch = true,
		VerboseOutputEnabled = false,
	},
}
local searchDefaults = {
	profile = {
		SearchModules = {
		}
	}
}	

function AtlasLootAdvancedSearch:OnInitialize()
	r_print("....initialized.");
	
	RedirectOnClickScript = AtlasLootAdvancedSearch.RedirectOnClickScript;
	if isInternal() then
		r_print(" Initializing internal mode, registering slash commands.");
		self:RegisterChatCommand("rl", function() ReloadUI() end)
		self:RegisterChatCommand("showmodules", function() BrowseTable:DirectOpenTable(self.dbSearchModules,"Search Modules") end);
		self:RegisterChatCommand("altest", function()
			self:EnableDeveloperMode(true);
			AtlasLootDefaultFrame:Show();
			AtlasLootSearch_Box:SetText("boots");
			
			self:OnSearchRequested(AtlasLootSearch_Box);
			end
		);
	end

	self:HookAtlasLootSearchUI();

	-- register options; this will register the options table with both AceConfigRegistry & AceConfigCmd
	ace_config:RegisterOptionsTable(ADDON_TAG, self.options, {"AtlasLootAdvancedSearch","alas"})

	-- Database
	-- create proxy for interacting with persistent data
	local useDefaultProfile = true;
	self.db = LibStub("AceDB-3.0"):New(SETTINGS_TAG, defaults, useDefaultProfile);
	self.dbSearchModules = self.db:RegisterNamespace("ModuleSettings", searchDefaults);
--	self:RegisterProfileCallbacks()
	
	-- add the main options page for this addon to the blizzard interface menu, under the addons tab
--	self.optionsFrame = ace_config_dlg:AddToBlizOptions(ADDON_TAG, L["ADDON_NAME"])

	ace_config:RegisterOptionsTable("ATAS_DebugProxy", alas_addon.DebugProxy.DebugOptionsTable, {"DebugAtlasLootAdvancedSearch","debugalas"})
end

function AtlasLootAdvancedSearch:OnEnable()
	funcEnter(self,"OnEnable");
	self:InitializeSearchModules();
	self:RegisterEvents();
	self:HookAtlasLootSearch();
	funcExit(self,"OnEnable");
end

function AtlasLootAdvancedSearch:OnDisable()
	self:RestoreAtlasLootSearch();
	self:UnregisterEvents();
end

--[[
	Events
--]]
function AtlasLootAdvancedSearch:ADDON_LOADED(event, addon)
	if addon ~= "AtlasLoot" and addon ~= ADDON_TAG then
		
		-- search through the list of AtlasLoot modules and see if this is one of them
		-- the table containing the data about the available AtlasLoot modules appears to be put together like this (as usual, no documentation)
		--[[
			[1]: [string]	internal ID
			[2]: [string]	AddOn name (i.e. would correspond to name of folder in windows)
			[3]: [bool]		indicates if this module is loaded/available
			[4]: [string]	additional information regarding the module's status (i.e. if couldn't be loaded, why not)
			[5]: [string]	localized name (display name)
			[4]: appears to be an input value
			} --]]
		if AtlasLoot.Modules then
			t_printf("Received notification that new addon has now loaded:'%s'.  Checking against list of %i registered AtlasLoot modules.", addon, #AtlasLoot.Modules);
			local moduleAddOnName;
			for sourceModuleIdx, tbl_ModuleMetadata in ipairs(AtlasLoot.Modules) do
				moduleAddOnName = tbl_ModuleMetadata[2];
				if ( addon == moduleAddOnName ) then
					self:ClearCachedZoneData();
					break;
				end
			end
		else
			t_printf("Received notification that new addon has now loaded:'%s'.  Unable to check against list of AtlasLoot modules: Modules table not initialized.", addon);
		end
	end
	VerifyItemButtonClickHandlers();
end

function AtlasLootAdvancedSearch:RegisterEvents()
-- we'll need to use this event to know when atlas loot has loaded modules.
	self:RegisterEvent("ADDON_LOADED");
end
function AtlasLootAdvancedSearch:UnregisterEvents()
	self:UnregisterEvent("ADDON_LOADED");
end


--[[=======================================================================
	Profile stuff
========================================================================--]]
function AtlasLootAdvancedSearch:ToggleAdvancedSearch( value )
	if value == nil then
		value = not alas_addon:IsAdvancedSearchEnabled();
	end
	if type(value) ~= "boolean" then
		t_printf("ERROR: ToggleAdvancedSearch called with invalid value (type:%s) - only boolean true/false/nil are supported!", type(value));
	else
		alas_addon.db.profile.EnableAdvancedSearch = value;
		alas_addon:UpdateAttachmentStatus();
	end
end
function AtlasLootAdvancedSearch:EnableAdvancedSearch()
	alas_addon:ToggleAdvancedSearch(true);
end
function AtlasLootAdvancedSearch:DisableAdvancedSearch()
	alas_addon:ToggleAdvancedSearch(false);
end

-- simple wrapper for our enabled flag.
function AtlasLootAdvancedSearch:IsAdvancedSearchEnabled()
	if alas_addon and alas_addon.db and alas_addon.db.profile and alas_addon.db.profile.EnableAdvancedSearch then
		return true;
	end
	return false;
end

function AtlasLootAdvancedSearch:ToggleVerboseOutput(newValue)
	if newValue == nil then newValue = not self:IsVerboseOutputEnabled(); end
	if type(newValue) ~= "boolean" then
		error(strformat("ToggleVerboseOutput called with invalid value (type:%s) - only boolean true/false/nil are supported!", type(newValue)), 2);
	else
		alas_addon.db.profile.VerboseOutputEnabled = newValue;
	end
end
function AtlasLootAdvancedSearch:EnableVerboseOuptut()
	self:ToggleVerboseOutput(true);
end
function AtlasLootAdvancedSearch:DisableVerboseOutput()
	self:ToggleVerboseOutput(false);
end
function AtlasLootAdvancedSearch:IsVerboseOutputEnabled()
	if alas_addon and alas_addon.db and alas_addon.db.profile and alas_addon.db.profile.VerboseOutputEnabled then
		return true;
	end
	return false;
end

function AtlasLootAdvancedSearch:ToggleSearchModule( searchModuleID, value )
	if searchModuleID then
		if value == nil then value = not self:IsSearcherEnabled(searchModuleID); end
		local moduleData = searchModules[searchModuleID];
		if moduleData then
			self.dbSearchModules.profile.SearchModules[searchModuleID].enabled = value;
		end
	end
end

-- SearchModuleID should correspond to a key in the SearchModules table, i.e. "ATSEARCH_ITEMNAME"
function AtlasLootAdvancedSearch:IsSearcherEnabled(SearchModuleID)
	local isEnabled;
	
	if type(SearchModuleID) == "string" then
		local moduleData = searchModules[SearchModuleID];
		if moduleData then
			isEnabled = alas_addon.dbSearchModules.profile.SearchModules[SearchModuleID].enabled;
		end
	else
		t_printf("Invalid argument of type %s passed to AtlasLootAdvancedSearch:IsSearcherEnabled (%s).  SearchModuleID must be a string or number.", type(SearchModuleID), tostring(SearchModuleID));
	end
	
	return isEnabled;
end

-- Indicates whether the specified search module is allowed to be enabled.
function AtlasLootAdvancedSearch:IsSearcherBanned( SearchModuleID )
	local isBanned;
	
	if type(SearchModuleID) == "string" then
		local moduleData = searchModules[SearchModuleID];
		if moduleData then
			isBanned = moduleData.banned;
		end
	else
		t_printf("Invalid argument of type %s passed to AtlasLootAdvancedSearch:IsSearcherBanned (%s).  SearchModuleID must be a string or number.", type(SearchModuleID), tostring(SearchModuleID));
	end
	
	return isBanned;
end

-- checks the value of our enabled flag and ensures the addon is in that state.
function AtlasLootAdvancedSearch:UpdateAttachmentStatus()
	if self:IsAdvancedSearchEnabled() then
		self:RegisterEvents();
		self:HookAtlasLootSearch();
		self:ClearCachedZoneData();
	else
		self:RestoreAtlasLootSearch();
		self:UnregisterEvents();
	end
end

function AtlasLootAdvancedSearch:InitializeSearchModules()
	if not alas_addon.SearchParameters then
		alas_addon.SearchParameters = {
			SearchText = nil,
			SearchParser = nil,
			PreviousSearchData = {
				Valid = false,
				SearchText = nil,
				-- indexes of the search modules that were enabled in the last viable search
				EnabledModules = {},
				-- the filter that was in place for the previous search
				AppliedFilter = nil,
			},
			
		}
	end

	searchModules = {};
	searchModuleIndex = {};
	searchParms = alas_addon.SearchParameters;
	
	-- register modules
	local moduleIdx = 0;
	for moduleTag, moduleTable in pairs(_G["AL_SEARCHMODULES"]) do
		if moduleTag and moduleTable then
			-- verify that we don't already have one with this name
			if searchModules[moduleTag] == nil then
				if not moduleTable.ModuleName then
					dev_printf("Failed to register %s - no ModuleName specified in registration table.", tostring(moduleTag));
				elseif not moduleTable.LocKey then
					dev_printf("Failed to register %s - no LocKey specified in registration table.", tostring(moduleTag));
				elseif not moduleTable.LocValue then
					dev_printf("Failed to register %s - no LocValue specified in registration table.", tostring(moduleTag));
				elseif not moduleTable.Func then
					dev_printf("Failed to register %s - no search function (Func) specified in registration table.", tostring(moduleTag));
				else
					dev_printf("Successfully registered search module: %s", moduleTable.LocKey);
					registerModuleDefaults = true;
					searchModules[moduleTag] = moduleTable;
					searchModuleIndex[moduleTable] = moduleIdx;
					moduleIdx = moduleIdx + 1;
				end
			end
		end
	end
	
	if registerModuleDefaults then
		alas_addon:InitSearchModuleDefaults();
	end
end

function AtlasLootAdvancedSearch:InitSearchModuleDefaults()
	dev_printf(L["MSG_NOTIFY_INIT_MODULES"]);
	registerModuleDefaults = false;

	-- initialize the default value for any new modules.
	local resetSearchModuleSettings = false;
	local currentSearchModuleSettings = {}
	
	-- in case we have to reset the search module db
	for moduleID, moduleData in pairs(self.dbSearchModules.profile.SearchModules) do
		local value;
		if type(moduleData) == "table" then
			value = self.dbSearchModules.profile.SearchModules[moduleID].enabled;
			currentSearchModuleSettings[moduleID] = {enabled = value}
		end
		--[[
		for moduleDataKey, moduleDataVal in pairs(moduleData) do
			currentSearchModuleSettings[moduleID][moduleDataKey] = self.dbSearchModules.profile.SearchModules[moduleDatakey];
		end
		--]]
	end
	
	local searchModuleDefaults = {
		profile = {
			SearchModules = {
				['*'] = { enabled = true }
			}
		}
	}
	for moduleID, data in pairs(searchModules) do
		if type(data) == "table" and data.ModuleName then
			if data.defaultValue == nil then data.defaultValue = true; end;
			searchModuleDefaults.profile.SearchModules[moduleID] = { enabled = data.defaultValue };
			if self.dbSearchModules.profile.SearchModules[moduleID] == nil then
				resetSearchModuleSettings = true;
			end
		end
	end

	if resetSearchModuleSettings then
		--t_printf("Registering defaults for search modules.");
		self.dbSearchModules:RegisterDefaults(searchModuleDefaults);
		
		-- do we need to call ResetProfile?
		
		
		-- now restore the previous settings
		for moduleID, moduleData in pairs(currentSearchModuleSettings) do
			self.dbSearchModules.profile.SearchModules[moduleID].enabled = currentSearchModuleSettings[moduleID].enabled;
		end
	end
end

--[[=======================================================================
	Hooks
========================================================================--]]
function AtlasLootAdvancedSearch:OnShowLastSearchResults(sender)
	AtlasLoot:ShowSearchResult();
end

-- Handler for the search button's OnEnter event.  Displays a tooltip.
function AtlasLootAdvancedSearch:OnMouseOverSearchButton( sender )
    if sender:IsEnabled() then
        GameTooltip:ClearLines();
        GameTooltip:SetOwner(sender, "ANCHOR_RIGHT", -(sender:GetWidth() / 2), 5);
        GameTooltip:SetText(L["TOOLTIP_TOKENIZED_SEARCH"], nil, nil, nil, nil, 1);
        GameTooltip:Show();
        
        --@TODO - add more delay to this once I integrate the timer module.
        GameTooltip:FadeOut(4);
    end
end
function AtlasLootAdvancedSearch:OnMouseLeaveSearchButton( sender )
    if ( GameTooltip:IsVisible() ) then
        GameTooltip:Hide();
    end
end

-- Handler for AtlasLootDefaultFrame.AtlasLootSearch_Box.OnEnterPressed, AtlasLootDefaultFrameSearchButton.OnClick and
-- AtlasLootDefaultFrameSearchOptionsButton.OnClick
-- Exact same code as what's in those handlers, but soemthing about the way lua code embedded in .xml files get bound to the actual
-- lua code requires me to do this in .lua in order for my other hooks to remain in place once the user closes the frame
function AtlasLootAdvancedSearch:OnSearchRequested(sender)
	AtlasLoot:Search(AtlasLoot.SearchBox:GetText());
	AtlasLootSearch_Box:ClearFocus();
end
function AtlasLootAdvancedSearch:OnSearchOptionsRequested(sender)
	AtlasLoot:ShowSearchOptions(sender);
end
function AtlasLootAdvancedSearch:OnAtlasLootClosed(sender)
	AtlasLootAdvancedSearch:ClearCachedZoneData();
end
--[[
function AtlasLootAdvancedSearch:OnFilterOptionsChecked(sender)
	AtlasLoot_FilterEnableButton();
end
function AtlasLootAdvancedSearch:OnNavButtonClicked(sender)
	AtlasLoot_NavButton_OnClick(sender);
end
--]]

function AtlasLootAdvancedSearch:HookAtlasLootSearchUI()
	-- new search panel
	--t_printf("AtlasLootAdvancedSearch:HookAtlasLootSearchUI - AtlasLoot.AtlasInfoFrame:%s", tostring(AtlasLoot.AtlasInfoFrame:GetName()));
	if not self:IsHooked(AtlasLootPanel, "OnShow") then
	--	self:HookScript(AtlasLootPanel, "OnShow", "ShowAdvancedSearchPanel");
	end
	if not self:IsHooked(AtlasLootPanel, "OnHide") then
	--	self:HookScript(AtlasLootPanel, "OnHide", "HideAdvancedSearchPanel");
	end

	
	-- Calls to AtlasLoot:Search
	if not self:IsHooked(AtlasLoot.SearchBox, "OnEnterPressed") then
		self:RawHookScript(AtlasLoot.SearchBox, "OnEnterPressed", "OnSearchRequested");
	end
	
	local ALSearchButton = _G["AtlasLootSearch_SearchButton"];
	if not self:IsHooked(ALSearchButton, "OnClick") then
		self:RawHookScript(ALSearchButton, "OnClick", "OnSearchRequested");
	end
	local ALLastResultButton = _G["AtlasLootSearch_LastResultButton"];
	if ALLastResultButton and not self:IsHooked(ALLastResultButton, "OnClick") then
		self:RawHookScript(ALLastResultButton, "OnClick", "OnShowLastSearchResults");
	end
	
	-- this lets us clear out our loot table cache
	if not self:IsHooked(AtlasLootDefaultFrame, "OnHide") then
		self:HookScript(AtlasLootDefaultFrame, "OnHide", "OnAtlasLootClosed");
	end
--[[
	if AtlasLootFilterCheck and not self:IsHooked(AtlasLootFilterCheck, "OnClick") then
		self:RawHookScript(AtlasLootFilterCheck, "OnClick", "OnFilterOptionsChecked");
	end


	if AtlasLootItemsFrame_NEXT and not self:IsHooked(AtlasLootItemsFrame_NEXT, "OnClick") then
		self:RawHookScript(AtlasLootItemsFrame_NEXT, "OnClick", "OnNavButtonClicked");
	end
	if AtlasLootItemsFrame_PREV and not self:IsHooked(AtlasLootItemsFrame_PREV, "OnClick") then
		self:RawHookScript(AtlasLootItemsFrame_PREV, "OnClick", "OnNavButtonClicked");
	end
	
	if AtlasLootItemsFrame_BACK and not self:IsHooked(AtlasLootItemsFrame_BACK, "OnClick") then
		self:RawHookScript(AtlasLootItemsFrame_BACK, "OnClick", "OnNavButtonClicked");
	end
--]]
end

local AdvancedSearchFunction = "ALAS_Search";
function AtlasLootAdvancedSearch:HookAtlasLootSearch()
	if AtlasLoot then
		if self:IsAdvancedSearchEnabled() then
			t_print(L["MSG_HOOK_NOTIFY_ATTACH"]);
			if not self:IsHooked(AtlasLoot, "Search") then
				self:RawHook(AtlasLoot, "Search", AdvancedSearchFunction);
			end
		end
		-- we do this here instead of HookAtlasLootUI because we only want the tooltip to be shown when we're enabled
		-- and everything that gets hooked in HookAtlasLootUI remains hooked forever.
		if AtlasLootSearch_SearchButton then
			if not self:IsHooked(AtlasLootSearch_SearchButton, "OnEnter") then
				self:HookScript(AtlasLootSearch_SearchButton, "OnEnter", "OnMouseOverSearchButton");
			end
			if not self:IsHooked(AtlasLootSearch_SearchButton, "OnLeave") then
				self:HookScript(AtlasLootSearch_SearchButton, "OnLeave", "OnMouseLeaveSearchButton");
			end
		end
		
		
		-- ok, here we replace the AtlasLoot methods which were preventing ALAS from working at all
		-- the replacement versions remain as true as possible to the original intent of the function
		-- (for better or worse), but I attempt to rectify whatever the particular issue was that I
		-- needed to override.
		local isHooked, hookedFunc = self:IsHooked(AtlasLoot, "CreateItemButton");
		if not isHooked then
			self:RawHook(AtlasLoot, "CreateItemButton", "CreateAtlasLootItemButton");
		end		
	
		-- add our buttons to the AtlasLoot panel
		local info = {};
		info.text = L["OPT_ADVANCED_SEARCH"];
		info.func = AtlasLootAdvancedSearch.ShowAdvancedSearchOptions;
		info.order = 150;
		AtlasLoot:PanelAddButton("AdvancedSearch", info);
	else
		t_print(L["MSG_HOOK_ATLASLOOT_MISSING"]);
	end
end

-- we need to leave the search options hooked or they won't be able to re-enable us, so only do that the caller passes true for the parm
function AtlasLootAdvancedSearch:RestoreAtlasLootSearch( unhookSearchOptions )
	if AtlasLootSearch_SearchButton then
		if self:IsHooked(AtlasLootSearch_SearchButton, "OnEnter") then
			self:Unhook(AtlasLootSearch_SearchButton, "OnEnter");
		end
		if self:IsHooked(AtlasLootSearch_SearchButton, "OnLeave") then
			self:Unhook(AtlasLootSearch_SearchButton, "OnLeave");
		end
	end

	if unhookSearchOptions == nil then unhookSearchOptions = false; end
	t_printf(L["MSG_HOOK_NOTIFY_DETACH"], tostring(unhookSearchOptions));
	local isHooked, hookFunc = self:IsHooked(AtlasLoot, "Search");
	if isHooked and hookFunc == AdvancedSearchFunction then
		dev_print(L["MSG_HOOK_DETACH_SEARCH"]);
		self:Unhook(AtlasLoot, "Search");
	end
	
	-- note that we do NOT unhook our custom CreateLootItemButton.  This is because the reason for interfering in that function is completely
	-- seperarate from the search functionality (I just happened to discover it while working in AtlasLoot).  The AtlasLoot code inavertently
	-- breaks many areas of the default UI dealing with "modified clicks" for item buttons; this change is to undo that breakage.
	isHooked, hookFunc = self:IsHooked(AtlasLoot, "CreateItemButton");
	if isHooked and hookFunc == AtlasLootAdvancedSearch.CreateAtlasLootItemButton then
		-- nothing
	end
	
	-- this is my super-fragilistic way to clear the local variable "SearchResult" from AtlasLoot's Search.lua file  ;)	
	--[[
	if self:IsHooked("AtlasLoot_FilterEnableButton") then
		dev_print(L["MSG_HOOK_DETACH_FILTERCHECKBOX"]);
		self:Unhook("AtlasLoot_FilterEnableButton");
	end
	
	if self:IsHooked("AtlasLoot_NavButton_OnClick") then
		self:Unhook("AtlasLoot_NavButton_OnClick");
	end

	isHooked, hookFunc = self:IsHooked(AtlasLoot, "ShowSearchOptions");
	if isHooked and hookFunc == "ALAS_ShowAdvancedSearchOptions" then
		if unhookSearchOptions then
			dev_print(L["MSG_HOOK_DETACH_SEARCHOPTIONS"]);
			self:Unhook(AtlasLoot, "ShowSearchOptions");
		else
			dev_print(L["MSG_HOOK_SKIPDETACH_SEARCHOPTIONS"]);
		end
	end
	isHooked, hookFunc = self:IsHooked(AtlasLoot, "ShowSearchResult");
	if isHooked and hookFunc == "ALAS_OnShowLastSearchResult" then
		dev_print(L["MSG_HOOK_DETACH_SHOWLASTSEARCH"]);
		self:Unhook(AtlasLoot, "ShowSearchResult");
	end
	--]]
end

--[[=======================================================================
	Search functions and related
========================================================================--]]

function AtlasLootAdvancedSearch:PopulateSearchPanelModuleControl( moduleDropdown )
	local moduleList, listOrder = {}, {};
	
	for key, data in pairs(searchModules) do
		--print("ADDING ITEM TO DROPDOWN KEY:" .. tostring(data.ModuleName) .. "  VALUE:" .. tostring(data.LocKey));
		moduleList[data.ModuleName] = data.LocKey;
		listOrder[#listOrder + 1] = data.ModuleName;
	end
	
	moduleDropdown:SetList(moduleList, listOrder);
	return moduleDropdown;
end

local function BuildSearchOptionsMenu(frame, level, menuList)
	local info;
	if level == 1 then
		info = UIDropDownMenu_CreateInfo();
		info.text = AL["Search options"];
		info.isTitle = true;
		info.notCheckable = true;
		UIDropDownMenu_AddButton(info, level);

		info = UIDropDownMenu_CreateInfo();
		info.text = L["OPT_ENABLED_NAME"];
		info.checked = alas_addon:IsAdvancedSearchEnabled();
		info.tooltipTitle = L["OPT_ENABLED_NAME"];
		info.tooltipText = L["OPT_ENABLED_DESC"];
		info.func = function()
			alas_addon:ToggleAdvancedSearch()
		end
		UIDropDownMenu_AddButton(info, level);

		if alas_addon:IsAdvancedSearchEnabled() then
		--[[
			tsort(searchModules, function(A, B)
				local function IsValidPriority(val) return (val ~= nil) and (type(val) == "number") and (val >= 0); end
				if not IsValidPriority(A.Priority) then return false; end
				if not IsValidPriority(B.Priority) then return true; end
				return A.Priority < B.Priority;
			end);
		--]]

			info = UIDropDownMenu_CreateInfo();
			info.text = L["OPT_TIMING_INFO_NAME"];
			info.checked = alas_addon:IsVerboseOutputEnabled();
			info.tooltipTitle = L["OPT_TIMING_INFO_NAME"];
			info.tooltipText = L["OPT_TIMING_INFO_DESC"];
			info.func = function() alas_addon:ToggleVerboseOutput() end
			UIDropDownMenu_AddButton(info, level);
			
			info = UIDropDownMenu_CreateInfo();
			info.text = "-";
			info.notClickable = true;
			info = UIDropDownMenu_CreateInfo();

			for key, data in pairs(searchModules) do
				if data.ValidValues and type(data.ValidValues) == "table" then
					info.text = data.LocKey;
					info.checked = alas_addon:IsSearcherEnabled(key);
					
					info.tooltipOnButton = true;
					info.tooltipTitle = data.LocChoices;--data.LocKey;
					info.tooltipText = ""--data.LocValue;	don't worry, this long description will make the tooltip too wide
					for _, displayName in pairs(data.ValidValues) do
						info.tooltipText = info.tooltipText .. "\n * " .. displayName;
					end
					
					info.hasArrow = false;
					info.value = data.ValidValues;
					info.func = function() 
						alas_addon:ToggleSearchModule(key);
					end
					info.keepShownOnClick = true;
					info.disabled = alas_addon:IsSearcherBanned(key);
					if info.disabled then
						info.checked = false;
						info.func = nil;
						info.value = nil;
					end
					UIDropDownMenu_AddButton(info, level);
				else
					info.text = data.LocKey;
					info.checked = alas_addon:IsSearcherEnabled(key);
					info.tooltipTitle = data.LocKey;
					info.tooltipText = data.LocValue;
					info.func = function() 
						alas_addon:ToggleSearchModule(key);
					end
					info.keepShownOnClick = true;
					info.disabled = alas_addon:IsSearcherBanned(key);
					if info.disabled then
						info.checked = false;
						info.func = nil;
						info.value = nil;
					end
					UIDropDownMenu_AddButton(info, level);
				end
			end		
			-- check 
		end
	elseif level == 2 then
		info = UIDropDownMenu_CreateInfo();
		for _, val in ipairs(UIDROPDOWNMENU_MENU_VALUE) do
			info.text = val;
			info.notCheckable = true;
			info.notClickable = true;	--@todo we might need this sort of functionality at some point, clickable submenu values....
			UIDropDownMenu_AddButton(info, level);
		end
	end
end

-- duplicated from AtlasLoot Search.lua =>>
local lootTableTypes = {"Normal", "Heroic", "25Man", "25ManHeroic"}

-- <<==

-- replaces AtlasLoot:ShowSearchOptions
function AtlasLootAdvancedSearch.ShowAdvancedSearchOptions(buttonFrame, buttonName)
	if ( buttonName == "LeftButton" ) then
		if not buttonFrame.alas_optionsmenu then
			local dropdown = CreateFrame("Frame", "ALAS_SearchOptionsMenu", buttonFrame, "UIDropDownMenuTemplate");
			UIDropDownMenu_Initialize(dropdown, BuildSearchOptionsMenu, "MENU", nil);
			buttonFrame.alas_optionsmenu = dropdown;
		end
		ToggleDropDownMenu(nil, nil, buttonFrame.alas_optionsmenu, buttonFrame);
	end
end

function AtlasLootAdvancedSearch_GetLootItemMetadata(loot_item)
	local shortDescription, additionalInfo;
	
	if loot_item and type(loot_item) == "table" then
		if #loot_item > 4 and loot_item[5] and type(loot_item[5]) == "string" then
			shortDescription = loot_item[5];
		end
		
		if #loot_item > 5 and loot_item[6] and type(loot_item[6]) == "string" then
			if not shortDescription or shortDescription == "" then
				shortDescription = loot_item[6];
			else
				additionalInfo = loot_item[6];
			end
		end
	end
	
	return shortDescription, additionalInfo;
end


--[[	AtlasLootAdvancedSearch_GetFormattedName
 *
 * This is a utility function for encapsulating the process of parsing a item data table or tokenized item name string (such as =ds=Name of Item).
 * The primary purpose of this method is to extract the bare item name (minus formatting markup) from the rest of the information provided, but it
 * will also attempt to parse fields 4 & 5 of the item data, if passed an item data table as the value for ID, instead of a number.
 *
 * @param	ID		should be either a number (item ID) or the entire item data table.  If passing the item ID value, you should also specify a value
 *					for encodedName.  If passing an item data table for the value of ID, the value of encodedName is irrelevant because it will be
 *					overwritten with the value of the 4th field of the table you passed in for the value of ID.
 *
 * @return	string, string, string
 *			- the name of the item, stripped of any formatting marks.
 *			- the name of the item, including all formatting markup needed to display the item correctly in WoW
 *			- an additional piece of information about the item; ideally the most important thing about the item
 *
--]]
local AtlasLootAdvancedSearch_GetLootItemMetadata = AtlasLootAdvancedSearch_GetLootItemMetadata;
function AtlasLootAdvancedSearch_GetFormattedName(ID, encodedName)
	local normalName, formattedName, item_data, description, additionalInfo;

	if ID then
		if type(ID) == "table" then
			--[[
			we were passed the entire block of data, which should be laid out like so:

	Examples:
		{ 7,              47517,                                "",         "=q4=Blade of the Unbroken Covenant",                            "=ds=#h3#,    #w10#"};
		{ 2,"EMBLEMOFFROSTMENU",         "inv_misc_frostemblem_01",        "=ds="..AL["Emblem of Frost Rewards"], "=q5="..AL["Wrath of the Lich King"]};
		{ 1,                  0, "inv_misc_tournaments_symbol_orc", "=q6="..BabbleFaction["Orgrimmar"].." #j30#",                          "=ec1=#m6#"};
		{ 2,              18796,                                "",           "=q4=Horn of the Swift Brown Wolf",                          "=ds=#e12#"};
		  1                 2                                 3                                               4                                      5         6          7
				[1]: index into whatever table it was being stored in.....not important
				[2]: 0 (category header), numeric value (item ID), or string referring to another key in the main data table
				[3]: icon name (no path)
				[4]: [qualityColorCode][name]  (i.e. =q4=Some Item that Is Cool
				[5]: [colorCode]context specific meta data (this will be different depending on the type of data)
						in the case of equippable items, will also contain a code indicating which slot it matches
				[6]: context specific data; for vendor items, might be the item price; for weapons, might be the code for the weapon category
				[7]: drop percentage
				[8]: used at runtime, usually filled with other info like zone it came from or something.
			--]]
			item_data = ID;
			ID = item_data[2];	-- ensure that ID is a string, because we treat it as such later on
			encodedName = item_data[4];
		end

		local originalID = ID;
		-- ok, verify that we got a valid item ID (and not some random value)
		local isItem, isSpell = true, false;
		local isCategoryHeader, isSubMenuHeader = false, false;
		if type(ID) == "number" then
			if ID == 0 then
				isCategoryHeader = true;
				isItem = false;
			end
		-- another possibility is that this is a spell ID, which has the format "s#####", 
		elseif type(ID) == "string" and ID ~= "" then
			isItem = false;
			if strmatch(ID, "^s%d+") ~= nil then
				-- appears to be a spell ID
				isSpell = true;
			else
				local testID = tonumber(ID)
				if testID then
					ID = testID;
					if ID == 0 then
						isCategoryHeader = true;
						isItem = false;
					end
				else
					isSubMenuHeader = true;
				end
			end
		elseif type(ID) == "table" then
			t_printf("  AtlasLootAdvancedSearch_GetFormattedName received table value for ID: %s", tostring(ID));
		end
--[===[@debug@
funcEnterSlow(alas_addon,"GetFormattedName","type(ID):%s isItem:%s  isSpell:%s  isCategoryHeader:%s  isSubmenuHeader:%s",
	type(originalID), tostring(isItem), tostring(isSpell), tostring(isCategoryHeader), tostring(isSubMenuHeader));
--@end-debug@]===]
		if isItem then
			local itemID = tonumber(ID);
			if itemID ~= nil and itemID > 0 then
				-- returns valid value only if the item is cached.
				normalName = GetItemInfo(itemID);
			end
			
			local qualityCode;
			if not normalName then
				-- if we got the item name from the ID, we'll need to prepend the color code, so strip the color code here first
				qualityCode, normalName = strmatch(encodedName, "^(=q%d=)(.*)");
			end
			if not qualityCode then 
				qualityCode = strmatch(encodedName, "^=q%d=") or "";
			end
			--[[
			if not normalName then
				t_printf("  GetFormattedName  ID:%s  encodedName:%s   item_data[4]:%s    qualityCode:%s", tostring(ID), tostring(encodedName), tostring(item_data[4]), tostring(qualityCode));
			end
			--]]
			
			if normalName then
				if not qualityCode then qualityCode = ""; end
				formattedName = qualityCode .. normalName;
			end
		else
			if isSpell then
				local spellID = strsub(ID, 2);
				
				-- spell name
				normalName = GetSpellInfo(spellID);
			end
			local qualityCode;
			if not normalName then
				qualityCode, normalName = strmatch(encodedName, "^(=ds=)(.*)");
				if not qualityCode then
					qualityCode, normalName = strmatch(encodedName, "^(=q%d=)(.*)");
				end
			end
			if not qualityCode then
				qualityCode = strmatch(encodedName, "^=q%d=") or strmatch(encodedName, "^=ds=") or "";
			end

			if normalName then
				if not qualityCode then qualityCode = ""; end
				formattedName = qualityCode .. normalName;
			end
		end
		
		-- if normalName is nil, it means that encodedName didn't contain a quality code, so we won't have a formattedName
		if not normalName then
			normalName = encodedName;
			assert(not formattedName);
			formattedName = normalName;
		end

		-- not really sure if there will be any differences between what we need to do for category headers
		-- and subheaders, but it seems like there should be.		
		if item_data then
			description = AtlasLootAdvancedSearch_GetLootItemMetadata(item_data);
		end
--[===[@debug@
funcExitSlow(alas_addon,"GetFormattedName","ID:%s  encodedName:%s   normalName:%s   formattedName:%s   desc:%s",
	tostring(ID), tostring(encodedName), tostring(normalName), tostring(formattedName), tostring(description));
--@end-debug@]===]
	end
	
	-- the content of additionalInfo is defined by each item's definition (they can literally put anything there), but for most items, this
	-- holds the token for the armor type/category, if it's a wearable item.
	-- for other items, it will contain the price of the item.
	return normalName, formattedName, description;
end

function AtlasLootAdvancedSearch:GetSearchModulesForLootQuery( searchModuleSortFunc )
	local searchers = {}
	for moduleID, moduleData in pairs(searchModules) do
		--@non-debug@
		if self:IsVerboseOutputEnabled() then
			r_printf("  moduleID:%s   moduleType:%s   moduleFunc:%s", moduleID, type(moduleData), tostring(moduleData.Func));
		end
		--@end-non-debug@
		--[===[@debug@
		t_printf("  moduleID:%s   moduleType:%s   moduleFunc:%s", moduleID, type(moduleData), tostring(moduleData.Func));
		--@end-debug@]===]
		if type(moduleData) == "table" and moduleData.Func and self:IsSearcherEnabled(moduleID) and
			(not self:IsSearcherBanned(moduleID)) then
			moduleData.foundMatchTbl = nil;
			searchers[#searchers + 1] = moduleData;
		end
	end
	
	if #searchers > 0 then
		local function ComparePriority(A, B)
			local function IsValidPriority(val) return (val ~= nil) and (type(val) == "number") and (val >= 0); end
--			t_printf("A:%s   B:%s    A.Priority:%s    B.Priority:%s", tostring(A.ModuleName), tostring(B.ModuleName), tostring(A.Priority), tostring(B.Priority));
			if not IsValidPriority(A.Priority) then return false; end
			if not IsValidPriority(B.Priority) then return true; end
			return A.Priority < B.Priority;
		end
		if searchModuleSortFunc == nil then searchModuleSortFunc = ComparePriority; end 
		--@fixme - if the modules are sorted, need to update the module's index so that the flag masks work
		-- (that is, need to go in and move the elements of the index array around to match the order that the modules are in now, so that
		-- the value at element 1 is the index that the module at element 1 originally had when it was registered)
		tsort(searchers, searchModuleSortFunc);
	end
	return searchers;
end

local function verifyModuleFlagParms(searchModule, item_data, needValue, createIfNecessary)
	if not searchModule then error("Invalid value specified for 'searchModule' in call to verifyModuleFlagParms.", 2); end
	if not searchModuleIndex[searchModule] then error("Search module missing entry in searchModuleIndex array:" .. tostring(searchModule.ModuleName), 2); end
	if needValue and not item_data then error("Invalid value specified for item data in call to verifyModuleFlagParms.", 2) end
	if needValue and not item_data.ALAS_ModuleProcessedMask then
		if not createIfNecessary then error("ALAS_ModuleProcessedMask not initialized in item data:" .. tostring(item_data[4]), 2);
		else item_data.ALAS_ModuleProcessedMask = 0; end
	end
end
local function verifySearchResultFlagParms(item_data, needValue, createIfNecessary)
	if needValue and not item_data then error("Invalid value specified for item data in call to verifyModuleFlagParms.", 2) end
	if needValue and not item_data.ALAS_SearchResultMask then
		if not createIfNecessary then error("ALAS_SearchResultMask not initialized in item data:" .. tostring(item_data[4]), 2);
		else item_data.ALAS_SearchResultMask = 0; end
	end
end

local function ALAS_GetModuleFlagMask( searchModule )
	verifyModuleFlagParms(searchModule);
	local result = bit_ls(1, searchModuleIndex[searchModule]);
	return result;
end

local function ALAS_GetModuleItemEntry(dataID, item_data)
	local result;
	
	if dataID and item_data then
		local itemTableCache = LootTableItemCache[dataID];
		if itemTableCache == nil then LootTableItemCache[dataID] = {}; itemTableCache = LootTableItemCache[dataID]; end
		
		local function determineTableCacheKey()
			local rawValue, value = item_data[2];
			if rawValue and type(rawValue) == "number" then
				value = tostring(rawValue);
			elseif rawValue and type(rawValue) == "string" and substr(rawValue, 1, 1) == "s" then
				value = rawValue;
			else
				rawValue = rawValue[4];
				if rawValue and type(rawValue) == "string" then
					value = rawValue;
				else
					value = tostring(rawValue);
				end
			end
			return value;
		end
		
		local itemTableCacheKey = determineTableCacheKey();
		if itemTableCache[itemTableCacheKey] == nil then itemTableCache[itemTableCacheKey] = {} end
		result = itemTableCache[itemTableCacheKey];
	end
	return result;
end
local function ALAS_HasModuleSeenItem( searchModule, dataID, item_data )
	item_data = ALAS_GetModuleItemEntry(dataID, item_data);
	verifyModuleFlagParms(searchModule,item_data);
	local mask = ALAS_GetModuleFlagMask(searchModule);
	local result =	item_data.ALAS_ModuleProcessedMask ~= nil
			and		bit_and(mask, item_data.ALAS_ModuleProcessedMask) ~= 0;
	
--t_printf("ALAS_IsModuleFlagSetOnItem searchModule:%i  item_data mask:0x%08X   moduleFlagMask:0x%08X  result:%s",searchModuleIndex[searchModule],item_data.ALAS_ModuleProcessedMask,mask,tostring(result));
	return result;
end
local function ALAS_MarkModuleSawItem( searchModule, dataID, item_data )
	item_data = ALAS_GetModuleItemEntry(dataID, item_data);
	verifyModuleFlagParms(searchModule,item_data,true,true);
--[===[@debug@
--dev_printf("    Marking %s|r as processed by search module %s%s|r", al_addon:FixText(item_data[4]), RED_FONT_COLOR_CODE, searchModule.ModuleName);
--@end-debug@]===]
	local mask = ALAS_GetModuleFlagMask(searchModule);
	
--t_printf("        OldValue:0x%02X   NewValue:0x%02X ((1<<%i) | 0x%02X)", item_data.ALAS_ModuleProcessedMask, bit_or(mask, item_data.ALAS_ModuleProcessedMask), searchModuleIndex[searchModule], item_data.ALAS_ModuleProcessedMask);
	item_data.ALAS_ModuleProcessedMask = bit_or(mask, item_data.ALAS_ModuleProcessedMask);
end

local function ALAS_IsItemInResultSet( dataID, item_data, foundMatch )
	item_data = ALAS_GetModuleItemEntry(dataID, item_data);
	verifySearchResultFlagParms(item_data);
	local result =	item_data.ALAS_SearchResultMask ~= nil 
				and	bit_and(0xFF,item_data.ALAS_SearchResultMask) ~= 0;
if foundMatch then
--[===[@debug@
t_printf("ALAS_IsItemInResultSet item_data   %s   mask:0x%08X", al_addon:FixText(item_data[4]), item_data.ALAS_SearchResultMask or 0);
--@end-debug@]===]
end
	return result;
end

local function ALAS_IsSearchResultFlagSet( searchModule, dataID, item_data )
	item_data = ALAS_GetModuleItemEntry(dataID, item_data);
	verifySearchResultFlagParms(item_data);
	local mask = ALAS_GetModuleFlagMask(searchModule);
	local result =	item_data.ALAS_SearchResultMask ~= nil
			and		bit_and(mask, item_data.ALAS_SearchResultMask) ~= 0;
--t_printf("ALAS_IsModuleFlagSetOnItem searchModule:%i  item_data mask:0x%08X   moduleFlagMask:0x%08X  result:%s",searchModuleIndex[searchModule],item_data.ALAS_SearchResultMask,mask,tostring(result));
	return result;
end
local function ALAS_SetItemSearchResultFlag( searchModule, dataID, item_data )
	item_data = ALAS_GetModuleItemEntry(dataID, item_data);
	verifySearchResultFlagParms(item_data,true,true);
--[===[@debug@
t_printfSlow("    Marking %s|r as included in result set by search module %s%s|r", al_addon:FixText(item_data[4]), RED_FONT_COLOR_CODE, searchModule.ModuleName);
--@end-debug@]===]
	local mask = ALAS_GetModuleFlagMask(searchModule);
--t_printf("        OldValue:0x%02X   NewValue:0x%02X ((1<<%i) | 0x%02X)", item_data.ALAS_SearchResultMask, bit_or(mask, item_data.ALAS_SearchResultMask), searchModuleIndex[searchModule], item_data.ALAS_SearchResultMask);
	item_data.ALAS_SearchResultMask = bit_or(mask, item_data.ALAS_SearchResultMask);
end
local function ALAS_ClearItemSearchResultFlag( searchModule, dataID, item_data )
	item_data = ALAS_GetModuleItemEntry(dataID, item_data);
	verifySearchResultFlagParms(item_data);
	local inv_mask = bit_not(ALAS_GetModuleFlagMask(searchModule));
	if item_data.ALAS_SearchResultMask ~= nil then
		item_data.ALAS_SearchResultMask = bit_and(inv_mask, item_data.ALAS_SearchResultMask);
	end
end
 
local function ALAS_ResetItemFlagMasks( dataID, optional_single_item )
	if optional_single_item then optional_single_item = ALAS_GetModuleItemEntry(dataID, item_data); end
	if optional_single_item and optional_single_item.ALAS_SearchResultMask ~= nil then
		optional_single_item.ALAS_SearchResultMask = 0;
		optional_single_item.ALAS_ModuleProcessedMask = 0;
	else
		-- clear the value for the tracking mark we set inside the atlasloot data
		for kA, itemTableCache in pairs(LootTableItemCache) do
			for kB, item_data in pairs(itemTableCache) do
			--t_printf("kA:%s (%s)   itemTableCache:%s  (%s)     kB:%s (%s)    item_data:%s (%s)",
			--	tostring(kA), type(kA), tostring(itemTableCache), type(itemTableCache), tostring(kB), type(kB), tostring(item_data), type(item_data));
				item_data.ALAS_SearchResultMask = 0;
				item_data.ALAS_ModuleProcessedMask = 0;
			end
		end
		--[[
		for lootSourceID, lootSourceContents in pairs(AtlasLoot_Data) do
			for lootSourceCategoryIndex, lootSourceCategoryName in ipairs(lootTableTypes) do
				if lootSourceContents.info and (lootSourceContents.info.instance == nil or lootSourceCategoryName == "Normal" or lootSourceCategoryName == "Heroic") then
					local function IterateLootTableItems(dataID)
t_printfSlow("   Retrieving loot page table for dataID:%s", tostring(dataID));
						local lootTableItems = AtlasLoot:GetLootPageFromDataID(dataID);
						for tableIdx, item_data in ipairs(lootTableItems) do
							item_data.ALAS_SearchResultMask = 0;
							item_data.ALAS_ModuleProcessedMask = 0;
						end
					end
					
					local dataID = lootSourceID .. "#" .. lootSourceCategoryName;
					local dataIDStrLength = strlen(dataID);
					IterateLootTableItems(dataID);
					
					-- each page is contained within its own subtable
					local nextPage = AtlasLoot:GetNextPrevPage(dataID);
					while ( nextPage ) do
						if strsub(nextPage, 1, dataIDStrLength) ~= dataID then
							break;
						end
						IterateLootTableItems(nextPage);
						nextPage = AtlasLoot:GetNextPrevPage(nextPage);
					end
				end
			end
		end
		--]]
	end
end

VerifyItemButtonClickHandlers = function()
	local frm = AtlasLoot.ItemFrame;
	if frm and frm.ItemButtons then
		for buttonIdx = 1, 50 do
			local btn = frm.ItemButtons[buttonIdx];
			if btn ~= nil then
				RedirectOnClickScript(btn);
			end
		end
	end
end

local SEARCHRESULT_TAG			= "ALAS_SearchResult";
local FILTERED_SEARCHRESULT_TAG = "FilteredSearchResult";
local FILTERRESULT_TAG			= "FilterList";

--[===[@debug@
--debugALASResults_Unsorted = nil;
--debugALASResults_Sorted = nil;
--@end-debug@]===]

-- sender would either be AtlasLootSearchBox (from OnEnterPressed) or AtlasLootSearchButton (from OnClick)
function AtlasLootAdvancedSearch:ALAS_Search(al_frame, inSearchText)
	--[===[@debug@
	funcEnter(self, "ALAS_Search", inSearchText);
	if alas_addon.DebugDataSet then
		alas_addon.DebugDataSet();
		AtlasLoot_Data = _G["AtlasLoot_Data"];
	end
	--@end-debug@]===]

	--[===[@debug@
	--self:UpdateMyMemoryUsage("Before everything");
	--@end-debug@]===]
	if ( inSearchText == nil ) then
		funcExit(Self, "ALAS_Search", "Early out due to invalid value for search text (nil).");
		return;
	end

	inSearchText = strtrim(inSearchText);
	if ( inSearchText == "" ) then
		funcExit(self, "ALAS_Search", "Early out due to empty string specified for search text.");
		return;
	end

	local lcSearchText, previousSearchText = strlower(inSearchText), "";
	if searchParms.PreviousSearchData.Valid then
		previousSearchText = searchParms.PreviousSearchData.SearchText;
		
		-- now clear the tracking variables
		searchParms.PreviousSearchData.SearchText = "";
		searchParms.PreviousSearchData.Valid = false;
		--searchParms.PreviousSearchData.AppliedFilter = nil;
	end
	
	-- before we begin, make sure that the context menu is closed, because some of these operations take a few seconds, and it doesn't look very polished to
	-- have the menu hanging around that whole time.  Also, it stops counting while the game is processing these instructions, so once your search is done,
	-- you still have to wait a few more seconds for the menu to disappear.
	--[[
	do
		local contextMenuParent = AtlasLootDefaultFrameSearchOptionsButton;
		if contextMenuParent then
			local dewdrop = AceLibrary("Dewdrop-2.0");
			if dewdrop and dewdrop:IsOpen(contextMenuParent) then
				dewdrop:Close(1);
			end	
		end
	end 
	--]]



	-- here we verify that we actually have at least one table of source data to search from
	local hasSourceData = nil;
	if AtlasLoot.Modules then
		local moduleID;
		for sourceModuleIdx, tbl_ModuleMetadata in ipairs(AtlasLoot.Modules) do
			moduleID = tbl_ModuleMetadata[1];
			if AtlasLoot:GetModuleEnabled(moduleID) then
				t_printf("Found that module %s is enabled, so proceeding with search.", moduleID);
				hasSourceData = true;
				break;
			end
		end
	end
	
	--[===[@debug@
	if not hasSourceData then
		t_printf("No luck checking whether atlasloot modules were enabled.");
		for m_idx, moduleTbl in ipairs(AtlasLoot.Modules) do
			t_printf("module %i =>   [1]:%s, [2]:%s,  [3]:%s,  [4]:%s,  [5]:%s", m_idx, tostring(moduleTbl[1]), tostring(moduleTbl[2]), tostring(moduleTbl[3]), tostring(moduleTbl[4]), tostring(moduleTbl[5]));
		end
	end
	--@end-debug@]===]

	-- if we do this here, it doesn't cleanup previous searches properly in the UI - if this search finds no results, the UI isn't updated
	-- but as soon as the user clicks a nav button, all the [previous] search results suddenly disappear....which I find very confusing
	-- Instead, I'll store this search's results in a temp table and copy it to the db if the search succeeds.
	local tempResultsTable = {}
	if not hasSourceData then
		DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..FONT_COLOR_CODE_CLOSE..AL["You don't have any module selected to search on!"]);

--@todo need to consider previous search invalid if the user changed other options, like which search modules to use
	elseif previousSearchText ~= lcSearchText then
	
		searchParms.SearchText = lcSearchText;
		searchParms.SearchParser = AtlasLootAdvancedSearch:TokenizeSearchString(searchParms.SearchText);
		
		-- build the list of search modules to use for this query
		local searchers = self:GetSearchModulesForLootQuery();
		if #searchers > 0 then
			local function isValidItemID(itemID)
				if itemID then
					if type(itemID) == "string" then
						-- item ids are 5 or less, spell ids are 6 (prepended with s) so add 1
						return strlen(itemID) <= MAX_ITEMID_DIGITS + 1;
						
					elseif type(itemID) == "number" then
						return itemID > 0;
					end
				end
				return false;
			end
			
			
			local searchTimes = {}
			
			debugprofilestart();
			self:BuildZoneTable();
			--@non-debug@
			if self:IsVerboseOutputEnabled() then
				t_printf("Populating Zone Cache took %i ms.", debugprofilestop());
			end
			--@end-non-debug@
			--[===[@debug@
			r_printf("Populating Zone Cache took %i ms.", debugprofilestop());
			--@end-debug@]===]
			
			-- and away we go!
			--[===[@debug@
			funcEnter(alas_addon,"ALAS_Search: finding matches",inSearchText);
			--@end-debug@]===]
--******************************************************************************************************************************
			ALAS_ResetItemFlagMasks();
			for searchIdx = 1, #searchers do
				local searchModule = searchers[searchIdx];
				dev_printf("Beginning item iteration for search module %s", tostring(searchModule.ModuleName));
				debugprofilestart();
	
				self:PerformSearchModuleItemIteration(searchIdx, searchers, tempResultsTable);
	
				searchTimes[searchModule.ModuleName] = debugprofilestop();
				--[===[@debug@
				r_printf("Completed item iteration for search module %s in %i ms.", tostring(searchModule.ModuleName), searchTimes[searchModule.ModuleName]);
				--@end-debug@]===]
			end
--******************************************************************************************************************************
			--@non-debug@
			searchParms.SearchParser = nil;
			searchParms.SearchText = nil;
			--@end-non-debug@

			--[===[@debug@
			funcExit(alas_addon,"ALAS_Search: finding matches","%i matches found",#tempResultsTable);
			funcEnter(alas_addon,"ALAS_Search: sorting results");
			--@end-debug@]===]
			if #tempResultsTable == 0 then
				-- searchParms.PreviousSearchData.SearchText is cleared at the start of this function if the user
				-- specified different text, so we don't need to worry about showing stale searches if the new search
				-- comes back with 0 results
				DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..FONT_COLOR_CODE_CLOSE..AL["No match found for"].." \""..inSearchText.."\".");
			else
				searchParms.PreviousSearchData.SearchText = lcSearchText;
				searchParms.PreviousSearchData.Valid = true;
				--@todo searchParms.PreviousSearchData.EnabledModules = GetActiveSearchModuleIndexes();

				--@fixme cata: PresentSearchResults was responsible for applying filters and such to the search results
				--				need to figure out how that's handled now...
				--self:PresentSearchResults(searchPageRefreshParameters,nil,searchTimes);
				--@todo searchParms.PreviousSearchData.AppliedFilter = GetActiveFilter();
				
				DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..FONT_COLOR_CODE_CLOSE.."Found " .. #tempResultsTable .. " results.");
				
				--[===[@debug@
				--t_printf("refreshOri[1]:%s   refreshOri[2]:%s    refreshOri[3]:%s   refreshOri[4]:%s", tostring(AtlasLootItemsFrame.refreshOri[1]),
				--	tostring(AtlasLootItemsFrame.refreshOri[2]),tostring(AtlasLootItemsFrame.refreshOri[3]),tostring(AtlasLootItemsFrame.refreshOri[4]));
				--@end-debug@]===]
			end
			if not alas_addon.CategorizedSearchResults then
				alas_addon.CategorizedSearchResults = al_frame:AddLootTableSort(SEARCHRESULT_TAG);
			end
			-- now we have a new set of results, pass our table of items to the sorting methods
			--[===[@debug@
			--DevTools_Dump(tempResultsTable);
			--@end-debug@]===]
			alas_addon.CategorizedSearchResults:ShowSortedTable(inSearchText, tempResultsTable);
			VerifyItemButtonClickHandlers();
			
			--@non-debug@
			if self:IsVerboseOutputEnabled() then
				for moduleName, ms in pairs(searchTimes) do
					r_printf("Took %i ms for module %s to complete processing.", ms, moduleName);
				end
			end
			--@end-non-debug@
		else
			-- no search modules performed the search
			if #searchModules > 0 then
				r_printf(L["ERR_NOSEARCHERS_SELECTED"]);
			elseif dbgProxy and dbgProxy:isDevMode() then
				dev_print(L["ERR_NOSEARCHERS_REGISTERED_DEV"]);
			else
				r_printf(L["ERR_NOSEARCHERS_REGISTERED"]);
			end
		end
	elseif previousSearchText ~= "" then
		t_printf("Instructing AtlasLoot to display previous search results.");
		AtlasLoot_Data[alas_addon.CategorizedSearchResults.name] = alas_addon.CategorizedSearchResults.lootpage;
		al_frame:ShowLootPage(alas_addon.CategorizedSearchResults.name);
	else
		if #searchModules > 0 then
			r_printf(L["ERR_NOSEARCHERS_SELECTED"]);
		elseif dbgProxy and dbgProxy:isDevMode() then
			dev_print(L["ERR_NOSEARCHERS_REGISTERED_DEV"]);
		else
			r_printf(L["ERR_NOSEARCHERS_REGISTERED"]);
		end
		local emptyResultsTable = {}
		if not alas_addon.CategorizedSearchResults then
			alas_addon.CategorizedSearchResults = al_frame:AddLootTableSort(SEARCHRESULT_TAG);
		end
		-- now we have a new set of results, pass our table of items to the sorting methods
		alas_addon.CategorizedSearchResults:ShowSortedTable("0 items found", emptyResultsTable);
	end
	--[===[@debug@
	funcExit(alas_addon,"ALAS_Search: sorting results");
	funcExit(alas_addon, "ALAS_Search", inSearchText);
	--@end-debug@]===]
end


--[[
		so each lootSourceID in AtlasLoot_Data corresponds to a unique key which identifies a particular encounter (in the case of instance loot)
		or << TODO >> in the case of vendor or misc. loot
		
		the actual lootSourceContents should look something like this:
		{
			"Normal" = {
				{
					{normal_header},
					{first_itemdata_table},
					{}
				}
			},
			info = { name = <loc_name_of_encounter_boss>, module = <addon_module_name, i.e. Cataclysm>, instance = <key_used_to_index_instance> in
				the AtlasLoot_LootTableRegister table, which is essentially a mapping of instance UniqueID => list of keys for the encounters from that instance},
		}
--]]

function AtlasLootAdvancedSearch:PerformSearchModuleItemIteration(searchIdx, searchers, tempResultsTable)
	local searchModule = searchers[searchIdx];
	
	-- let the search module know that we're about to start sending it item data to check
	local searchModulePerformedIteration = false;
	if searchModule.PreSearchFunc then
		searchModulePerformedIteration = searchModule:PreSearchFunc();
	end
	if not searchModulePerformedIteration then

--if lootSourceContents.info and lootSourceContents.info.module and lootSourceContents.info.module == "AtlasLootCataclysm" then
		for lootSourceID, lootSourceContents in pairs(AtlasLoot_Data) do
			local zoneTableID = lootSourceID;
			for lootSourceCategoryIndex, lootSourceCategoryName in ipairs(lootTableTypes) do
				
				-- lootSourceDataCompartment will typically be a mapping of instance difficulty (i.e. Normal, Heroic) to the loot table for that encounter under that difficulty.
				if lootSourceContents.info and (lootSourceContents.info.instance == nil or lootSourceCategoryName == "Normal" or lootSourceCategoryName == "Heroic") then
					local function IterateLootTableItems( dataID )
						local al_lootTableType = AtlasLoot:GetLootTableType(dataID);
t_printfSlow("%s>>  Iterating loot source ID %s with %s (al_lootTableType:%s)", RED_FONT_COLOR_CODE, dataID, searchModule.ModuleName, tostring(al_lootTableType));
						if al_lootTableType ~= lootSourceCategoryName then
							return;
						end
						local lootTableItems = AtlasLoot:GetLootPageFromDataID(dataID);
						for tableIdx, item_data in ipairs(lootTableItems) do
							if not ALAS_HasModuleSeenItem(searchModule, dataID, item_data) then
								local foundMatch, itemID, displayText, extraInfo;
								local function MatchSearchPhraseRemainder( searchPhrase )
									--[===[@debug@
t_printfSlow("  %s> >  %s beginning search for search module to match remaining text '%s%s' (current search index:%i  total searchers:%i)",RED_FONT_COLOR_CODE, searchModule.ModuleName, YELLOW_FONT_COLOR_CODE, tostring(searchPhrase), searchIdx, #searchers);
									--@end-debug@]===]
									local tempParameters = {
										SearchText = "",
										SearchParser = searchPhrase,
										pendingMatches = searchParms.pendingMatches,
										OriginalValue = searchParms,
									}
									searchParms = tempParameters;
									for connectedSearchIdx = 1, #searchers do
										if connectedSearchIdx ~= searchIdx then
											local connectedSearchModule = searchers[connectedSearchIdx];
											if not ALAS_HasModuleSeenItem(connectedSearchModule, dataID, item_data) then
												local prevMatch = ALAS_IsSearchResultFlagSet(connectedSearchModule, dataID, item_data);
												
												local foundConnectionMatch, connectionItemID, connectionDisplayText, connectionExtraInfo, additionalOrphenPhrases = connectedSearchModule:Func(dataID, item_data, true);
												ALAS_MarkModuleSawItem(connectedSearchModule, dataID, item_data);
												
												local additionalTermCount = 0;
												if additionalOrphenPhrases then
													additionalTermCount = additionalOrphenPhrases:CountTokens();
													if additionalTermCount > 0 then
														MatchSearchPhraseRemainder(additionalOrphenPhrases);
													end
												end;
--[===[@debug@
t_printfSlow("      Finished processing connectedModule[%i] (%s%s|r):    displayText:%s     processed:(connected:%s | self:%s)  newPendingTokens:%i    %sisMatch:%s|r", 
	connectedSearchIdx, RED_FONT_COLOR_CODE, connectedSearchModule.ModuleName, tostring(connectionDisplayText), tostring(ALAS_IsSearchResultFlagSet(connectedSearchModule, dataID, item_data)),
	tostring(ALAS_IsSearchResultFlagSet(searchModule, dataID,item_data)), additionalTermCount, GREEN_FONT_COLOR_CODE, tostring(foundConnectionMatch));
--@end-debug@]===]
												if foundConnectionMatch and additionalTermCount == 0 then
													foundMatch = true;
													itemID = connectionItemID;
													displayText = connectionDisplayText;
													extraInfo = connectionExtraInfo;
												end
											end		-- ALAS_HasModuleSeenItem
										end
									end
									
									searchParms = tempParameters.OriginalValue;
								end


								local searchFunc = searchModule.Func;
								-- if the searcher returns a valid value for searchPhraseRemainder, it means that only part of the search string could be
								-- matched by this search module, and a predicate was specified.  i.e. if a user specifies the search term 'feet and "trial of the crusader"',
								-- only those search results which match both conditions can be shown, but each of the conditions in the search are recognized by
								-- different search modules.
								local searchPhraseRemainder;
								searchParms.pendingMatches = {};
								foundMatch, itemID, displayText, extraInfo, searchPhraseRemainder = searchFunc(searchModule, dataID, item_data);
--[===[@debug@
t_printfSlow("    itemID:%s  displayText:%s|r   extraInfo:%s    searchPhraseRemainder:%s   foundMatch:%s",
	tostring(itemID), tostring(displayText), tostring(extraInfo), tostring(searchPhraseRemainder), tostring(foundMatch));
--@end-debug@]===]

								if searchPhraseRemainder and searchPhraseRemainder:CountTokens() > 0 then
--[===[@debug@
t_printfSlow("    %sSearch module [%i] ('%s') needs to combine search terms with another module to produce a result for |r%s|r:", RED_FONT_COLOR_CODE, searchIdx, searchModule.ModuleName, al_addon:FixText(item_data[4]));
--@end-debug@]===]
									MatchSearchPhraseRemainder(searchPhraseRemainder);
								end
								searchParms.pendingMatches = nil;
--[===[@debug@
t_printfSlow("  searcher:%s%s|r   foundMatch:%s    processed:%s    displayText:%s", GREEN_FONT_COLOR_CODE, searchModule.ModuleName, truefalse(foundMatch), truefalse(ALAS_IsItemInResultSet(dataID, item_data)), tostring(displayText));
--@end-debug@]===]
								-- the intent is to allow searchers to override other searchers' searches, if necessary
								if foundMatch ~= nil and type(foundMatch) == "boolean" then
									if not ALAS_IsItemInResultSet(dataID, item_data, foundMatch) then
										if foundMatch and displayText then
											ALAS_SetItemSearchResultFlag(searchModule, dataID, item_data);
--[===[@debug@								
local tracking_data = ALAS_GetModuleItemEntry(dataID, item_data);
t_printfSlow("      %sInserting result into results table - itemID:%s (%s)    displayText:%s    zoneTableID:%s    dataID:%s   0x%08X (%s)",
	RED_FONT_COLOR_CODE, tostring(itemID), tostring(item_data), displayText, tostring(zoneTableID), tostring(dataID), tracking_data.ALAS_SearchResultMask, tostring(item_data));
--@end-debug@]===]
																																																							--tinsert(tempResultsTable, { 0, itemID, item_data[3], displayText, lootpage, extraInfo, item_data[6], zoneTableID .. "|" .. scope, ["ALAS_SearchResultMask"] = item_data.ALAS_SearchResultMask});
																																																							--[[
																																																							local heroicCheckNumber = AtlasLoot:CheckHeroic(lootTableList);
																																																							if heroicCheckNumber and heroicCheckNumber < tableIdx then
																																																								lootSourceCategoryName = "Heroic";
																																																							end
																																																							
																																																							if type(itemID) ~= "string" and type(itemID) ~= "number" then
																																																								error(strformat("Detected unhandled case, itemID not a string or number. {[1]=%s,[2]=%s,[3]=%s,[4]=%s,[5]=%s,[6]=%s}",
																																																									tostring(item_data[1]), tostring(item_data[2]), tostring(item_data[3]),
																																																									tostring(item_data[4]), tostring(item_data[5]), tostring(item_data[6]))
																																																								);
																																																								break;
																																																							end
																																																							--]]
											ALAS_MarkModuleSawItem(searchModule, dataID, item_data);
											tinsert(tempResultsTable, {0, itemID, item_data[3], displayText, item_data[5], dataID});
										end
									--[===[@debug@
									else
											t_printf("FOUND AN EXISTING ENTRY FOR %s%s%s:\"%s\"%s   ===>  (%szoneTableID:%s%s   %stableIdx:%s%i)",
												YELLOW_FONT_COLOR_CODE, tostring(itemID), FONT_COLOR_CODE_CLOSE,
												tostring(displayText), FONT_COLOR_CODE_CLOSE,
												RED_FONT_COLOR_CODE, FONT_COLOR_CODE_CLOSE, tostring(dataID),--zoneTableID),
												RED_FONT_COLOR_CODE, FONT_COLOR_CODE_CLOSE, tableIdx); 
									--@end-debug@]===]
									end
								end	-- foundMatch ~= nil and....
								ALAS_MarkModuleSawItem(searchModule, dataID, item_data);
							end		-- if not ALAS_HasModuleSeenItem
						end	-- ipairs(lootTableList)
					end -- local function IterateLootTableItems


					-- i.e. HellscreamsReach#Normal
					local dataID = lootSourceID .. "#" .. lootSourceCategoryName;
					local dataIDStrLength = strlen(dataID);
					IterateLootTableItems(dataID);
					
					-- each page is contained within its own subtable
					local nextPage = AtlasLoot:GetNextPrevPage(dataID);
					while ( nextPage ) do
						local nameToCheckForMatch = strsub(nextPage, 1, dataIDStrLength);
						
					--[===[@debug@
						t_printfSlow("CHECKING WHETHER MORE PAGES EXIST FOR %s - by checking whether that matches the beginning of the word: %s (%s = %s ?)", dataID, nextPage, dataID, nameToCheckForMatch);
					--@end-debug@]===]
						if nameToCheckForMatch ~= dataID then
							break;
						end
						IterateLootTableItems(nextPage);
						nextPage = AtlasLoot:GetNextPrevPage(nextPage);
					end
				end	-- ipairs(lootSourceDataCompartment)
			end
--end
		end
    
		-- let the search module know that the list is complete
		if searchModule.PostSearchFunc then
			searchModule:PostSearchFunc();
		end
	--[===[@debug@
	--self:UpdateMyMemoryUsage("  ...completed processing for search module " .. searchModule.ModuleName);					

	--r_printf("...copying UNSORTED results table into persistent debug storage (this might take a while).");
	--debugALASResults_Unsorted = ALAS_CopyTable(tempResultsTable);
	--r_printf("***************    UNsorted Table    ***********************");
	--ALAS_DumpObj(tempResultsTable, "Unsorted Search Results");
	--@end-debug@]===]
	end
	
end


-- Main method for clearing and resetting any data caches in our system.  Called whenever the set of loaded modules changes (or we change debugging filters).
function AtlasLootAdvancedSearch:ClearCachedZoneData()
	self:CleanupZoneNameSearch();
end








