local _G, _ = _G or getfenv()

local ACHIEVER_ADDON_DEBUG = false

local function debug(msg)
	if achieverDBpc.debug == "enabled" then
		DEFAULT_CHAT_FRAME:AddMessage('|cffc663fcDEBUG: |cffff55ff'.. (msg or 'nil'))
	end
end
local function warn(msg)
	if achieverDBpc.debug == "enabled" then
		DEFAULT_CHAT_FRAME:AddMessage('|cf3f3f66cWARN: |cffff55ff'.. (msg or 'nil'))
	end
end

SLASH_ACHIEVER1 = "/ac"
SlashCmdList.ACHIEVER = function()
    AchievementFrame_ToggleAchievementFrame()
end

local function toggleDebug()
    if achieverDBpc.debug == "enabled" then
        achieverDBpc.debug = "disabled"
        DEFAULT_CHAT_FRAME:AddMessage('Achiever DEBUG mode disabled')
    else
        achieverDBpc.debug = "enabled"
        DEFAULT_CHAT_FRAME:AddMessage('Achiever DEBUG mode enabled')
    end
end

SLASH_ACHIEVERDEBUG1 = "/acdebug"
SlashCmdList.ACHIEVERDEBUG = function()
    toggleDebug()
end

-- Criteria Types
CRITERIA_TYPE_ACHIEVEMENT = 8;

-- Achievement Flags
ACHIEVEMENT_FLAGS_STATISTIC				= 1;
ACHIEVEMENT_FLAGS_HIDDEN				= 2;
ACHIEVEMENT_FLAGS_HAS_PROGRESS_BAR 		= 128;
ACHIEVEMENT_FLAG_SUMM                   = 8
NUM_ACHIEVEMENT_FLAGS			        = 4;

-- Criteria Flags
ACHIEVEMENT_CRITERIA_PROGRESS_BAR		= 1;
ACHIEVEMENT_CRITERIA_HIDDEN				= 2;
ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER = 32;
NUM_ACHIEVEMENT_CRITERIA_FLAGS			= 3;



ACCOUNT_WIDE_ACHIEVEMENT = "Progress on any of your characters\nwill count towards this achievement.";
ACCOUNT_WIDE_ACHIEVEMENT_COMPLETED = "All of your characters have credit\nfor earning this achievement.";
ACHIEVEMENT = "Achievement Announce";
ACHIEVEMENTFRAME_FILTER_ALL = "All";
ACHIEVEMENTFRAME_FILTER_COMPLETED = "Earned";
ACHIEVEMENTFRAME_FILTER_INCOMPLETE = "Incomplete";
ACHIEVEMENTS = "Achievements";
ACHIEVEMENTS_COMPLETED = "Achievements Earned";
ACHIEVEMENTS_COMPLETED_CATEGORY = "%s Achievements Earned";
ACHIEVEMENTS_GUILD_TAB = "Guild";
ACHIEVEMENT_BROADCAST = "%s has earned the achievement %s!";
ACHIEVEMENT_BROADCAST_SELF = "You have earned the achievement %s!";
ACHIEVEMENT_BUTTON = "Achievements";
ACHIEVEMENT_CATEGORY_PROGRESS = "Progress Overview";
ACHIEVEMENT_COMPLETED_BY = "Completed by: |cffffffff%s|r";
ACHIEVEMENT_EARNED_BY = "Earned by: |cffffffff%s|r";
ACHIEVEMENT_FILTER_ALL_EXPLANATION = "Show all achievements";
ACHIEVEMENT_FILTER_COMPLETE_EXPLANATION = "Show achievements completed on your account";
ACHIEVEMENT_FILTER_INCOMPLETE_EXPLANATION = "Show achievements this character can complete";
ACHIEVEMENT_FILTER_TITLE = "Achievement Filter";
ACHIEVEMENT_META_COMPLETED_DATE = "Completed %s";
ACHIEVEMENT_NOT_COMPLETED_BY = "|cffff2020Not completed by:|r |cffffffff%s|r";
ACHIEVEMENT_POINTS = "Achievement Points";
ACHIEVEMENT_PROGRESSED = "Achievement Progress";
ACHIEVEMENT_REQUIRES_GUILD_REPUTATION = "|cffffffffRequires guild reputation:|r %s";
ACHIEVEMENT_SUMMARY_CATEGORY = "Summary";
ACHIEVEMENT_TITLE = "Achievement Points";
ACHIEVEMENT_TOOLTIP_COMPLETE = "Achievement earned by %1$s on %2$d/%3$02d/20%4$02d";
ACHIEVEMENT_TOOLTIP_IN_PROGRESS = "Achievement in progress by %s";
ACHIEVEMENT_UNLOCKED = "Achievement Earned";
ACHIEVEMENT_UNLOCKED_CHAT_MSG = "Achievement Earned: %s";
ACHIEVEMENT_WATCH_TOO_MANY = "You may only track %d achievements at a time.";
CHAT_MSG_ACHIEVEMENT = "Achievement Announce";
INSTANCE_UNAVAILABLE_OTHER_ACHIEVEMENT_NOT_COMPLETED = "%s has not yet completed the required achievement."
INSTANCE_UNAVAILABLE_SELF_ACHIEVEMENT_NOT_COMPLETED = "You have not yet completed the required achievement."
ITEM_REQ_PURCHASE_ACHIEVEMENT = "Requires achievement: %s";
LATEST_UNLOCKED_ACHIEVEMENTS = "Recent Achievements";
NEW_ACHIEVEMENT_EARNED = "You have earned the achievement '%s'.";
NO_COMPLETED_ACHIEVEMENTS = "You have not earned any achievements recently";
NO_ROSTER_ACHIEVEMENT_POINTS = "-";
PLAYER_SERVER_FIRST_ACHIEVEMENT = "|Hplayer:%s|h[%s]|h has earned the achievement $a!";
SERVER_FIRST_ACHIEVEMENT = "%s has earned the achievement $a!";
STATISTICS = "Statistics"
TRACK_ACHIEVEMENT = "Track";
UNTRACK_ACHIEVEMENT_TOOLTIP = "Uncheck to stop tracking this achievement.";
TRACK_ACHIEVEMENT_TOOLTIP = "Check to track this achievement.";
FEAT_OF_STRENGTH_DESCRIPTION = "Feats of Strength achievements represent the player's various glories of Azeroth, and as such, they are very difficult — if not impossible — to earn. They are worth no points, and unlike normal achievements, unearned feats are not displayed in the achievements interface. Feats include obtaining rare mounts, special titles, and more. Some Feats of Strength can still be obtained, while others are no longer possible to get.";

ACHIEVEMENT_FUNCTIONS = {
	categoryAccessor = GetCategoryList,
	clearFunc = AchievementFrameAchievements_ClearSelection,
	updateFunc = AchievementFrameAchievements_Update,
	selectedCategory = "summary";
}

STAT_FUNCTIONS = {
	categoryAccessor = GetStatisticsCategoryList,
	clearFunc = nil,
	updateFunc = AchievementFrameStats_Update,
	selectedCategory = "summary";
}

COMPARISON_ACHIEVEMENT_FUNCTIONS = {
	categoryAccessor = GetCategoryList,
	clearFunc = AchievementFrameComparison_ClearSelection,
	updateFunc = AchievementFrameComparison_Update,
	selectedCategory = -1,
}

COMPARISON_STAT_FUNCTIONS = {
	categoryAccessor = GetStatisticsCategoryList,
	clearFunc = AchievementFrameComparison_ClearSelection,
	updateFunc = AchievementFrameComparison_UpdateStats,
	selectedCategory = -2,
}

local USE_FUNCTIONS = 'ACHIEVEMENT_FUNCTIONS'

UIPanelWindows["AchievementFrame"] = { area = "doublewide", pushable = 0, width = 840, xoffset = 80, whileDead = 1 };

ACHIEVEMENTUI_CATEGORIES = {};

ACHIEVEMENTUI_GOLDBORDER_R = 1;
ACHIEVEMENTUI_GOLDBORDER_G = 0.675;
ACHIEVEMENTUI_GOLDBORDER_B = 0.125;
ACHIEVEMENTUI_GOLDBORDER_A = 1;

ACHIEVEMENTUI_REDBORDER_R = 0.7;
ACHIEVEMENTUI_REDBORDER_G = 0.15;
ACHIEVEMENTUI_REDBORDER_B = 0.05;
ACHIEVEMENTUI_REDBORDER_A = 1;

ACHIEVEMENTUI_CATEGORIESWIDTH = 175;

ACHIEVEMENTUI_PROGRESSIVEHEIGHT = 50;
ACHIEVEMENTUI_PROGRESSIVEWIDTH = 42;

ACHIEVEMENTUI_MAX_SUMMARY_ACHIEVEMENTS = 4;

ACHIEVEMENTUI_MAXCONTENTWIDTH = 330;
local ACHIEVEMENTUI_FONTHEIGHT;						-- set in AchievementButton_OnLoad
local ACHIEVEMENTUI_MAX_LINES_COLLAPSED = 3;		-- can show 3 lines of text when achievement is collapsed

ACHIEVEMENTUI_DEFAULTSUMMARYACHIEVEMENTS = {6, 503, 116, 1017, 238};-- {6, 503, 116, 545, 1017};

ACHIEVEMENT_CATEGORY_NORMAL_R = 0;
ACHIEVEMENT_CATEGORY_NORMAL_G = 0;
ACHIEVEMENT_CATEGORY_NORMAL_B = 0;
ACHIEVEMENT_CATEGORY_NORMAL_A = .9;

ACHIEVEMENT_CATEGORY_HIGHLIGHT_R = 0;
ACHIEVEMENT_CATEGORY_HIGHLIGHT_G = .6;
ACHIEVEMENT_CATEGORY_HIGHLIGHT_B = 0;
ACHIEVEMENT_CATEGORY_HIGHLIGHT_A = .65;

ACHIEVEMENTBUTTON_LABELWIDTH = 320;

ACHIEVEMENT_COMPARISON_SUMMARY_ID = -1
ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID = -2

ACHIEVEMENT_FILTER_ALL = 1;
ACHIEVEMENT_FILTER_COMPLETE = 2;
ACHIEVEMENT_FILTER_INCOMPLETE = 3;

local FEAT_OF_STRENGTH_ID = 81;

local trackedAchievements = {};
local function updateTrackedAchievements (list)
	-- local count = arg.n; --select("#", ...);
	local count = table.getn(list)
	debug('updateTrackedAchievements ' .. count)
	if (count > 0) then
		for i = 1, count do
			trackedAchievements[select(i, arg)] = true;
		end
	end
end


-- [[ AchievementFrame ]] --

function AchievementFrame_ToggleAchievementFrame(toggleStatFrame)
	AchievementFrameComparison:Hide();
	AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;
	if ( not toggleStatFrame ) then
		if ( AchievementFrame:IsShown() and AchievementFrame.selectedTab == 1 ) then
			HideUIPanel(AchievementFrame);
		else
			ShowUIPanel(AchievementFrame);
			AchievementFrameTab_OnClick(1);
		end
		debug('AchievementFrameAchievements:GetWidth ' .. AchievementFrameAchievements:GetWidth());
		return;
	end
	if ( AchievementFrame:IsShown() and AchievementFrame.selectedTab == 2 ) then
		HideUIPanel(AchievementFrame);
	else
		ShowUIPanel(AchievementFrame);
		AchievementFrameTab_OnClick(2);
	end

end

function AchievementFrame_DisplayComparison (unit)
	AchievementFrame.wasShown = nil;
	AchievementFrameTab_OnClick = AchievementFrameComparisonTab_OnClick;
	AchievementFrameTab_OnClick(1);
	ShowUIPanel(AchievementFrame);
	--AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameSummary);
	AchievementFrameComparison_SetUnit(unit);
	AchievementFrameComparison_ForceUpdate();
end

function AchievementFrame_OnLoad (self)
	debug('AchievementFrame_OnLoad')
	myPanelTemplates_SetNumTabs(self, 2);
	self.selectedTab = 1;
	myPanelTemplates_UpdateTabs(self);
end

function AchievementFrame_OnShow (self)
	PlaySoundFile([[Interface\AddOns\Achiever\sounds\AchievementMenuOpen.wav]], 'SFX');
	AchievementFrameHeaderPoints:SetText(GetTotalAchievementPoints());
	if ( not AchievementFrame.wasShown ) then
		AchievementFrame.wasShown = true;
		AchievementCategoryButton_OnClick(AchievementFrameCategoriesContainerButton1);
	end
	-- UpdateMicroButtons();
	AchievementFrame_LoadTextures();
	UpdateAchievementsButton();
end

function AchievementFrame_OnHide (self)
	PlaySoundFile([[Interface\AddOns\Achiever\sounds\AchievementMenuClose.wav]], 'SFX');
	-- UpdateMicroButtons();
	AchievementFrame_ClearTextures();
	UpdateAchievementsButton();
end

function AchievementFrame_ForceUpdate ()
	if ( AchievementFrameAchievements:IsShown() ) then
		AchievementFrameAchievements_ForceUpdate();
	elseif ( AchievementFrameStats:IsShown() ) then
		AchievementFrameStats_Update();
	elseif ( AchievementFrameComparison:IsShown() ) then
		AchievementFrameComparison_ForceUpdate();
	end
end

function AchievementFrameBaseTab_OnClick (id)
	myPanelTemplates_Tab_OnClick(_G["AchievementFrameTab"..id], AchievementFrame);

	local isSummary = false
	if ( id == 1 ) then
		USE_FUNCTIONS = 'ACHIEVEMENT_FUNCTIONS'
		AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES); -- This needs to happen before AchievementFrame_ShowSubFrame (fix for bug 157885)
		if (ACHIEVEMENT_FUNCTIONS.selectedCategory == "summary") then
			isSummary = true;
			AchievementFrame_ShowSubFrame(AchievementFrameSummary);
		else
			AchievementFrame_ShowSubFrame(AchievementFrameAchievements);
		end
		AchievementFrameWaterMark:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-AchievementWatermark");
	else
		USE_FUNCTIONS = 'STAT_FUNCTIONS'
		AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES);
		if (STAT_FUNCTIONS.selectedCategory == "summary") then
			AchievementFrame_ShowSubFrame(AchievementFrameStats);
			STAT_FUNCTIONS.selectedCategory = ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID;
			AchievementFrameStatsContainerScrollBar:SetValue(0);
		else
			AchievementFrame_ShowSubFrame(AchievementFrameStats);
		end
		AchievementFrameWaterMark:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-StatWatermark");
	end

	AchievementFrameCategories_Update();

	if ( not isSummary ) then
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
			AchievementFrameAchievements_Update();
		elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
			AchievementFrameStats_Update();
		elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			AchievementFrameComparison_Update();
		elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
			AchievementFrameComparison_UpdateStats();
		end
	end
end

AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;

function AchievementFrameComparisonTab_OnClick (id)
	if ( id == 1 ) then
		USE_FUNCTIONS = 'COMPARISON_ACHIEVEMENT_FUNCTIONS'
		AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonContainer);
		AchievementFrameWaterMark:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-AchievementWatermark");
	else
		USE_FUNCTIONS = 'COMPARISON_STAT_FUNCTIONS'
		AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonStatsContainer);
		AchievementFrameWaterMark:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-StatWatermark");
	end

	AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES);
	AchievementFrameCategories_Update();
	myPanelTemplates_Tab_OnClick(_G["AchievementFrameTab"..id], AchievementFrame);

	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		AchievementFrameAchievements_Update();
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		AchievementFrameStats_Update();
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		AchievementFrameComparison_Update();
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		AchievementFrameComparison_UpdateStats();
	end
end

ACHIEVEMENTFRAME_SUBFRAMES = {
	"AchievementFrameSummary",
	"AchievementFrameAchievements",
	"AchievementFrameStats",
	"AchievementFrameComparison",
	"AchievementFrameComparisonContainer",
	"AchievementFrameComparisonStatsContainer"
};

function AchievementFrame_ShowSubFrame(...)
	local subFrame, show;
	for _, name in next, ACHIEVEMENTFRAME_SUBFRAMES  do
		subFrame = _G[name];
		show = false;
		for i=1, arg.n do
			-- if ( subFrame ==  select(i, arg)) then
			if ( subFrame ==  arg[i]) then
				show = true
			end
		end
		if ( show ) then
			subFrame:Show();
		else
			subFrame:Hide();
		end
	end
end

-- [[ AchievementFrameCategories ]] --

function AchievementFrameCategories_OnLoad (self)
	debug('AchievementFrameCategories_OnLoad')
	self:SetBackdropBorderColor(ACHIEVEMENTUI_GOLDBORDER_R, ACHIEVEMENTUI_GOLDBORDER_G, ACHIEVEMENTUI_GOLDBORDER_B, ACHIEVEMENTUI_GOLDBORDER_A);
	self.buttons = {};
	self:RegisterEvent("ADDON_LOADED");
	-- self:SetScript("OnEvent", AchievementFrameCategories_OnEvent);
end

function AchievementFrameCategories_OnEvent(self, event, ...)
	local arg1 = ...
	if ( event == "ADDON_LOADED" ) then
		local addonName = arg1
		if ( addonName and addonName ~= ACHIEVER_ADDON_NAME ) then
			return;
		end

		AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES);

		AchievementFrameCategoriesContainerScrollBar.ShowOriginal = AchievementFrameCategoriesContainerScrollBar.Show
		AchievementFrameCategoriesContainerScrollBar.Show =
			function (self)
				ACHIEVEMENTUI_CATEGORIESWIDTH = 175;
				AchievementFrameCategories:SetWidth(175);
				AchievementFrameCategoriesContainer:GetScrollChild():SetWidth(175);
				AchievementFrameAchievements:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 22, 0);
				AchievementFrameStats:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 22, 0);
				AchievementFrameComparison:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 22, 0)
				AchievementFrameWaterMark:SetWidth(145);
				AchievementFrameWaterMark:SetTexCoord(0, 145/256, 0, 1);
                for _, button in next, AchievementFrameCategoriesContainer.buttons do
					AchievementFrameCategories_DisplayButton(button, button.element)
                end
				self:ShowOriginal(self)
				-- getmetatable(self).__index.Show(self);
				-- log(self:GetName())
				-- self:Show()
			end

		AchievementFrameCategoriesContainerScrollBar.HideOriginal = AchievementFrameCategoriesContainerScrollBar.Hide
		AchievementFrameCategoriesContainerScrollBar.Hide =
			function (self)
				ACHIEVEMENTUI_CATEGORIESWIDTH = 197;
				AchievementFrameCategories:SetWidth(197);
				AchievementFrameCategoriesContainer:GetScrollChild():SetWidth(197);
				AchievementFrameAchievements:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 0, 0);
				AchievementFrameStats:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 0, 0);
				AchievementFrameComparison:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 0, 0)
				AchievementFrameWaterMark:SetWidth(167);
				AchievementFrameWaterMark:SetTexCoord(0, 167/256, 0, 1);
                for _, button in next, AchievementFrameCategoriesContainer.buttons do
                    -- log('cycle 2 ')
					AchievementFrameCategories_DisplayButton(button, button.element);
                end
				-- log(self:GetName())
				-- self:Hide()
				self:HideOriginal(self)
				-- getmetatable(self).__index.Hide(self);
			end

		AchievementFrameCategoriesContainerScrollBarBG:Show();
		AchievementFrameCategoriesContainer.update = AchievementFrameCategories_Update;
		HybridScrollFrame_CreateButtons(AchievementFrameCategoriesContainer, "AchievementCategoryTemplate", 0, 0, "TOP", "TOP", 0, 0, "TOP", "BOTTOM");
		AchievementFrameCategories_Update();
		AchievementFrameCategories:UnregisterEvent(event)
	end
end

function AchievementFrameCategories_OnShow (self)
	AchievementFrameCategories_Update();
end

function AchievementFrameCategories_GetCategoryList ()
	local cats = nil;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		cats = GetCategoryList();
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		cats = GetStatisticsCategoryList();
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		cats = GetCategoryList();
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		cats = GetStatisticsCategoryList();
	end


	for i in next, ACHIEVEMENTUI_CATEGORIES do
		ACHIEVEMENTUI_CATEGORIES[i] = nil;
	end

	-- Insert the fake Summary category
	tinsert(ACHIEVEMENTUI_CATEGORIES, 1, { ["id"] = "summary" });

	for i, id in next, cats do
		local name, parent, order = GetCategoryInfo(id);
		local rootParent = -1
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS' or USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			rootParent = -1
		else
			rootParent = 1
		end
		if ( parent == rootParent ) then
			tinsert(ACHIEVEMENTUI_CATEGORIES, order + 1, { ["id"] = id, ['order'] = order });
		end
	end

	local name, parent, order;
	local catsSize = table.getn(cats);
	for i = catsSize, 1, -1 do
		name, parent, order = GetCategoryInfo(cats[i]);
		for j, category in next, ACHIEVEMENTUI_CATEGORIES do
			if ( category.id == parent ) then
				category.parent = true;
				category.collapsed = true;
				tinsert(ACHIEVEMENTUI_CATEGORIES, j + 1, { ["id"] = cats[i], ["parent"] = category.id, ["hidden"] = true, ['order'] = order });
			end
		end
	end
end

local displayCategories = {};
function AchievementFrameCategories_Update ()
	local scrollFrame = AchievementFrameCategoriesContainer

	local categories = ACHIEVEMENTUI_CATEGORIES;
	local offset = HybridScrollFrame_GetOffset(scrollFrame);
	local buttons = scrollFrame.buttons;

	-- local displayCategories = displayCategories;
	displayCategories = {}

	for i in next, displayCategories do
		displayCategories[i] = nil;
	end

	local selection;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		selection = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		selection = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		selection = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		selection = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	if ( selection == ACHIEVEMENT_COMPARISON_SUMMARY_ID or selection == ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID ) then
		selection = 'summary';
	end

	local parent;
	if (selection) then
		for i, category in next, categories do
			if ( category.id == selection ) then
				parent = category.parent;
			end
		end
	end

	for i, category in next, categories do
		if ( not category.hidden ) then
			tinsert(displayCategories, category);
		elseif ( parent and category.id == parent ) then
			category.collapsed = false;
			tinsert(displayCategories, category);
		elseif ( parent and category.parent and category.parent == parent ) then
			category.hidden = false;
			tinsert(displayCategories, category);
		end
	end

	local numCategories = table.getn(displayCategories) -- #displayCategories;
	local numButtons = table.getn(buttons) -- #buttons;


	local totalHeight = numCategories * buttons[1]:GetHeight();
	local displayedHeight = 0;

	local element
	for i = 1, numButtons do
		element = displayCategories[i + offset];
		displayedHeight = displayedHeight + buttons[i]:GetHeight();
		if ( element ) then
			AchievementFrameCategories_DisplayButton(buttons[i], element);
			if ( selection and element.id == selection ) then
				buttons[i]:LockHighlight();
			else
				buttons[i]:UnlockHighlight();
			end
			buttons[i]:Show();
		else
			buttons[i].element = nil;
			buttons[i]:Hide();
		end
	end

	HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);

	return displayCategories;
end

function AchievementFrameCategories_DisplayButton (button, element)
	if ( not element ) then
		button.element = nil;
		button:Hide();
		return;
	end

	button:Show();
	if ( type(element.parent) == "number" ) then
		button:SetWidth(ACHIEVEMENTUI_CATEGORIESWIDTH - 25);
		button.label:SetFontObject("GameFontHighlight");
		button.parentID = element.parent;
		button.background:SetVertexColor(0.6, 0.6, 0.6);
	else
		button:SetWidth(ACHIEVEMENTUI_CATEGORIESWIDTH - 10);
		button.label:SetFontObject("GameFontNormal");
		button.parentID = element.parent;
		button.background:SetVertexColor(1, 1, 1);
	end

	local categoryName, parentID, flags;
	local numAchievements, numCompleted;

	local id = element.id;

	-- kind of janky
	if ( id == "summary" ) then
		categoryName = ACHIEVEMENT_SUMMARY_CATEGORY;
		numAchievements, numCompleted = GetNumCompletedAchievements();
		debug('AchievementFrameCategories_DisplayButton '.. numAchievements .. ' /' .. numCompleted)
	else
		categoryName, parentID, flags = GetCategoryInfo(id);
		numAchievements, numCompleted = AchievementFrame_GetCategoryTotalNumAchievements(id, true);
	end
	button.label:SetText(categoryName .. "    ");
	button.categoryID = id;
	button.flags = flags;
	button.element = element;

	-- For the tooltip
	button.name = categoryName;
	if ( id == FEAT_OF_STRENGTH_ID ) then
		-- This is the feat of strength category since it's sorted to the end of the list
		button.text = FEAT_OF_STRENGTH_DESCRIPTION;
		button.showTooltipFunc = AchievementFrameCategory_FeatOfStrengthTooltip;
	elseif ( AchievementFrame.selectedTab == 1 ) then
		button.text = nil;
		button.numAchievements = numAchievements;
		button.numCompleted = numCompleted;
		button.numCompletedText = numCompleted.."/"..numAchievements;
		button.showTooltipFunc = AchievementFrameCategory_StatusBarTooltip;
	else
		button.showTooltipFunc = nil;
	end
end

function GameTooltip_ShowStatusBar(self, min, max, value, text)
	-- self:AddLine(" ", 1.0, 1.0, 1.0);
	-- local numLines = self:NumLines();
	-- if ( not self.numStatusBars ) then
	-- 	self.numStatusBars = 0;
	-- end
	-- if ( not self.shownStatusBars ) then
	-- 	self.shownStatusBars = 0;
	-- end
	-- local index = self.shownStatusBars+1;
	-- local name = self:GetName().."StatusBar"..index;
	-- local statusBar = _G[name];
	-- if ( not statusBar ) then
	-- 	self.numStatusBars = self.numStatusBars+1;
	-- 	statusBar = CreateFrame("StatusBar", name, self, "TooltipStatusBarTemplate");
	-- end
	-- if ( not text ) then
	-- 	text = "";
	-- end
	-- _G[name.."Text"]:SetText(text);
	-- statusBar:SetMinMaxValues(min, max);
	-- statusBar:SetValue(value);
	-- statusBar:Show();
	-- statusBar:SetPoint("LEFT", self:GetName().."TextLeft"..numLines, "LEFT", 0, -2);
	-- statusBar:SetPoint("RIGHT", self, "RIGHT", -9, 0);
	-- statusBar:Show();
	-- self.shownStatusBars = index;
	-- self:SetMinimumWidth(140);
end

function AchievementFrameCategory_StatusBarTooltip(self)
	GameTooltip_SetDefaultAnchor(GameTooltip, self);
	GameTooltip:SetMinimumWidth(128, 1);
	-- GameTooltip:SetText(self.name, 1, 1, 1, nil, 1);
	debug('AchievementFrameCategory_StatusBarTooltip ' .. self.name)
	GameTooltip:SetText(self.name, 1, 1, 1);
	GameTooltip_ShowStatusBar(GameTooltip, 0, self.numAchievements, self.numCompleted, self.numCompletedText);
	GameTooltip:Show();
end

function AchievementFrameCategory_FeatOfStrengthTooltip(self)
	GameTooltip_SetDefaultAnchor(GameTooltip, self);
	-- GameTooltip:SetText(self.name, 1, 1, 1);
	GameTooltip:SetText(self.name, 1, 1, 1);
	GameTooltip:AddLine(self.text, nil, nil, nil, 1);
	GameTooltip:Show();
end

function AchievementFrameCategories_UpdateTooltip()
	local container = AchievementFrameCategoriesContainer;
	if ( not container:IsVisible() or not container.buttons ) then
		return;
	end

	for _, button in next, AchievementFrameCategoriesContainer.buttons do
		if ( button.mouseOver and button.showTooltipFunc ) then
			button:showTooltipFunc();
			break;
		end
	end
end

function AchievementFrameCategories_SelectButton (button)
	local id = button.element.id;

	if (type(button.element.parent) ~= "number") then
		-- Is top level category (can expand/contract)
		if ( button.isSelected and button.element.collapsed == false ) then
			button.element.collapsed = true;
			for i, category in next, ACHIEVEMENTUI_CATEGORIES do
				if ( category.parent == id ) then
					category.hidden = true;
				end
			end
		else
			for i, category in next, ACHIEVEMENTUI_CATEGORIES do
				if ( category.parent == id ) then
					category.hidden = false;
				elseif ( category.parent == true ) then
					category.collapsed = true;
				elseif ( category.parent ) then
					category.hidden = true;
				end
			end
			button.element.collapsed = false;
		end
	end

	local buttons = AchievementFrameCategoriesContainer.buttons;
	for _, button in next, buttons do
		button.isSelected = nil;
	end

	button.isSelected = true;


	local selectedCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		selectedCategory = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		selectedCategory = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	if ( id == selectedCategory ) then
		-- If this category was selected already, bail after changing collapsed states
		return
	end

	--Intercept "summary" category
	if ( id == "summary" ) then
		if ( USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS' ) then
			AchievementFrame_ShowSubFrame(AchievementFrameSummary);
			ACHIEVEMENT_FUNCTIONS.selectedCategory = id;
			return;
		elseif (  USE_FUNCTIONS == 'STAT_FUNCTIONS' ) then
			AchievementFrame_ShowSubFrame(AchievementFrameStats);
			STAT_FUNCTIONS.selectedCategory = ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID;
			AchievementFrameStatsContainerScrollBar:SetValue(0);
		elseif ( USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS' ) then
			-- Put the summary stuff for comparison here, Derek!
			AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonContainer);
			COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory = ACHIEVEMENT_COMPARISON_SUMMARY_ID;
			AchievementFrameComparisonContainerScrollBar:SetValue(0);
			AchievementFrameComparison_UpdateStatusBars(ACHIEVEMENT_COMPARISON_SUMMARY_ID);
		elseif ( USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS' ) then
			AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonStatsContainer);
			COMPARISON_STAT_FUNCTIONS.selectedCategory = ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID;
			AchievementFrameComparisonStatsContainerScrollBar:SetValue(0);
		end

	else
		if ( USE_FUNCTIONS == 'STAT_FUNCTIONS' ) then
			AchievementFrame_ShowSubFrame(AchievementFrameStats);
			AchievementFrameStatsContainerScrollBar:SetValue(0);
		elseif ( USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS' ) then
			AchievementFrame_ShowSubFrame(AchievementFrameAchievements);
			AchievementFrameAchievementsContainerScrollBar:SetValue(0);
			if ( id == FEAT_OF_STRENGTH_ID ) then
				AchievementFrameFilterDropDown:Hide();
				AchievementFrameHeaderRightDDLInset:Hide();
			else
				AchievementFrameFilterDropDown:Show();
				AchievementFrameHeaderRightDDLInset:Show();
			end
		elseif ( USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS' ) then
			AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonContainer);
			AchievementFrameComparisonContainerScrollBar:SetValue(0);
			AchievementFrameComparison_UpdateStatusBars(id);
		else
			AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonStatsContainer);
			AchievementFrameComparisonStatsContainerScrollBar:SetValue(0);
		end
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
			ACHIEVEMENT_FUNCTIONS.selectedCategory = id;
		elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
			STAT_FUNCTIONS.selectedCategory = id;
		elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory = id;
		elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
			COMPARISON_STAT_FUNCTIONS.selectedCategory = id;
		end
	end

	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		AchievementFrameAchievements_ClearSelection();
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		AchievementFrameComparison_ClearSelection();
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		AchievementFrameComparison_ClearSelection();
	end

	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		AchievementFrameAchievements_Update();
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		AchievementFrameStats_Update();
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		AchievementFrameComparison_Update();
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		AchievementFrameComparison_UpdateStats();
	end

end

function AchievementFrameAchievements_OnShow()
	local selectedCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		selectedCategory = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		selectedCategory = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	if ( selectedCategory == FEAT_OF_STRENGTH_ID ) then
		AchievementFrameFilterDropDown:Hide();
		AchievementFrameHeaderRightDDLInset:Hide();
	else
		AchievementFrameFilterDropDown:Show();
		AchievementFrameHeaderRightDDLInset:Show();
	end
end

function AchievementFrameCategories_ClearSelection ()
	local buttons = AchievementFrameCategoriesContainer.buttons;
	for _, button in next, buttons do
		button.isSelected = nil;
		button:UnlockHighlight();
	end

	for i, category in next, ACHIEVEMENTUI_CATEGORIES do
		if ( category.parent == true ) then
			category.collapsed = true;
		elseif ( category.parent ) then
			category.hidden = true;
		end
	end
end

function AchievementFrameComparison_UpdateStatusBars (id)
	local numAchievements, numCompleted = GetCategoryNumAchievements(id);
	local name = GetCategoryInfo(id);

	if ( id == ACHIEVEMENT_COMPARISON_SUMMARY_ID ) then
		name = ACHIEVEMENT_SUMMARY_CATEGORY;
	end

	local statusBar = AchievementFrameComparisonSummaryPlayerStatusBar;
	statusBar:SetMinMaxValues(0, numAchievements);
	statusBar:SetValue(numCompleted);
	statusBar.title:SetText(string.format(ACHIEVEMENTS_COMPLETED_CATEGORY, name));
	statusBar.text:SetText(numCompleted.."/"..numAchievements);

	local friendCompleted = GetComparisonCategoryNumAchievements(id);

	statusBar = AchievementFrameComparisonSummaryFriendStatusBar;
	statusBar:SetMinMaxValues(0, numAchievements);
	statusBar:SetValue(friendCompleted);
	statusBar.text:SetText(friendCompleted.."/"..numAchievements);
end

-- [[ AchievementCategoryButton ]] --

function AchievementCategoryButton_OnLoad (button)
	debug('AchievementCategoryButton_OnLoad')
	button:EnableMouse(true);
	button:EnableMouseWheel(true);

	local buttonName = button:GetName();

	button.label = _G[buttonName .. "Label"];
	button.background = _G[buttonName.."Background"];
end

function AchievementCategoryButton_OnClick (button, button2, down)
	AchievementFrameCategories_SelectButton(button);
	AchievementFrameCategories_Update();
end

-- [[ AchievementFrameAchievements ]] --

function AchievementFrameAchievements_OnLoad (self)
	AchievementFrameAchievementsContainerScrollBar.OriginalShow = AchievementFrameAchievementsContainerScrollBar.Show
	AchievementFrameAchievementsContainerScrollBar.Show =
		function (self)
			AchievementFrameAchievements:SetWidth(504);
			for _, button in next, AchievementFrameAchievements.buttons do
				button:SetWidth(496);
			end
			self:OriginalShow(self)
			-- getmetatable(self).__index.Show(self);
		end

	AchievementFrameAchievementsContainerScrollBar.OriginalHide = AchievementFrameAchievementsContainerScrollBar.Hide
	AchievementFrameAchievementsContainerScrollBar.Hide =
		function (self)
			AchievementFrameAchievements:SetWidth(530);
			for _, button in next, AchievementFrameAchievements.buttons do
				button:SetWidth(522);
			end
			self:OriginalHide(self)
			-- getmetatable(self).__index.Hide(self);
		end

	-- self:RegisterEvent("ADDON_LOADED");
	-- warn('disabled registration event')
	AchievementFrameAchievementsContainerScrollBarBG:Show();
	AchievementFrameAchievementsContainer.update = AchievementFrameAchievements_Update;
	HybridScrollFrame_CreateButtons(AchievementFrameAchievementsContainer, "AchievementTemplate", 0, -2);
end

function AchievementFrameAchievements_OnEvent (self, event, ...)
	warn('inspect xml AchievementFrameAchievements_OnEvent '..event)
	if ( event == "ADDON_LOADED" ) then
		self:RegisterEvent("ACHIEVEMENT_EARNED");
		self:RegisterEvent("CRITERIA_UPDATE");
		self:RegisterEvent("TRACKED_ACHIEVEMENT_UPDATE");

		updateTrackedAchievements(GetTrackedAchievements());
	elseif ( event == "ACHIEVEMENT_EARNED" ) then
		local achievementID = arg;
		AchievementFrameCategories_Update();
		AchievementFrameCategories_UpdateTooltip();
		-- This has to happen before AchievementFrameAchievements_ForceUpdate() in order to achieve the behavior we want, since it clears the selection for progressive achievements.
		local selection = AchievementFrameAchievements.selection;
		AchievementFrameAchievements_ForceUpdate();
		if ( AchievementFrameAchievementsContainer:IsShown() and selection == achievementID ) then
			AchievementFrame_SelectAchievement(selection, true);
		end
		AchievementFrameHeaderPoints:SetText(GetTotalAchievementPoints());

	elseif ( event == "CRITERIA_UPDATE" ) then
		if ( AchievementFrameAchievements.selection ) then
			local id = AchievementFrameAchievementsObjectives.id;
			local button = AchievementFrameAchievementsObjectives:GetParent();
			AchievementFrameAchievementsObjectives.id = nil;
			AchievementButton_DisplayObjectives(button, id, button.completed);
			AchievementFrameAchievements_Update();
		else
			AchievementFrameAchievementsObjectives.id = nil; -- Force redraw
		end
	elseif ( event == "TRACKED_ACHIEVEMENT_UPDATE" ) then
		for k, v in next, trackedAchievements do
			trackedAchievements[k] = nil;
		end

		updateTrackedAchievements(GetTrackedAchievements());
	end

	-- if ( not AchievementMicroButton:IsShown() ) then
		-- AchievementMicroButton_Update();
	-- end
end

function AchievementFrameAchievementsBackdrop_OnLoad (self)
	self:SetBackdropBorderColor(ACHIEVEMENTUI_GOLDBORDER_R, ACHIEVEMENTUI_GOLDBORDER_G, ACHIEVEMENTUI_GOLDBORDER_B, ACHIEVEMENTUI_GOLDBORDER_A);
	self:SetFrameLevel(self:GetFrameLevel()+1);
end

function AchievementFrameAchievements_Update ()
	local category;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		category = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		category = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		category = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		category = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	debug('AchievementFrameAchievements_Update '..tostring(category))
	if ( category == "summary" ) then
		return;
	end
	local scrollFrame = AchievementFrameAchievementsContainer

	local offset = HybridScrollFrame_GetOffset(scrollFrame);
	local buttons = scrollFrame.buttons;
	if (not ACHIEVEMENTUI_SELECTEDFILTER) then
		warn('ACHIEVEMENTUI_SELECTEDFILTER is nil!')
		return
	end
	local numAchievements, numCompleted, completedOffset = ACHIEVEMENTUI_SELECTEDFILTER(category);
	debug('Filter returned: numAchievements=' .. tostring(numAchievements) .. ', numCompleted=' .. tostring(numCompleted))
	if (not buttons) then
		warn('scrollFrame.buttons is nil!')
		return
	end
	local numButtons = table.getn(buttons) -- #buttons;
	debug('numButtons=' .. tostring(numButtons))

	-- If the current category is feats of strength and there are no entries then show the explanation text
	if ( AchievementFrame_IsFeatOfStrength() and numAchievements == 0 ) then
		AchievementFrameAchievementsFeatOfStrengthText:Show();
	else
		AchievementFrameAchievementsFeatOfStrengthText:Hide();
	end

	local selection = AchievementFrameAchievements.selection;
	if ( selection ) then
		AchievementButton_ResetObjectives();
	end

	local extraHeight = scrollFrame.largeButtonHeight or ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT

	local achievementIndex;
	local displayedHeight = 0;
	for i = 1, numButtons do
		achievementIndex = i + offset + completedOffset;
		if ( achievementIndex > numAchievements + completedOffset ) then
			buttons[i]:Hide();
		else
			AchievementButton_DisplayAchievement(buttons[i], category, achievementIndex, selection);
			displayedHeight = displayedHeight + buttons[i]:GetHeight();
		end
	end

	local totalHeight = numAchievements * ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT;
	totalHeight = totalHeight + (extraHeight - ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT);

	HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);

	if ( selection ) then
		AchievementFrameAchievements.selection = selection;
	else
		HybridScrollFrame_CollapseButton(scrollFrame);
	end
end

function AchievementFrameAchievements_ForceUpdate ()
	debug('AchievementFrameAchievements_ForceUpdate called')
	if ( AchievementFrameAchievements.selection ) then
		local nextID = GetNextAchievement(AchievementFrameAchievements.selection);
		local id, _, _, completed = GetAchievementInfo(AchievementFrameAchievements.selection);
		if ( nextID and completed ) then
			AchievementFrameAchievements.selection = nil;
		end
	end
	AchievementFrameAchievementsObjectives:Hide();
	AchievementFrameAchievementsObjectives.id = nil;

	local buttons = AchievementFrameAchievementsContainer.buttons;
	
	-- Get the current category
	local category = nil
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		category = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		category = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	end
	debug('AchievementFrameAchievements_ForceUpdate: category=' .. tostring(category))
	for i, button in next, buttons do
		button.id = nil;
	end

	-- Pass category to Update function
	if (category) then
		AchievementFrameAchievements_Update(category);
	else
		AchievementFrameAchievements_Update();
	end
end

function AchievementFrameAchievements_ClearSelection ()
	AchievementButton_ResetObjectives();
	for _, button in next, AchievementFrameAchievements.buttons do
		button:Collapse();
		if ( not button.mouseOver ) then
			button.highlight:Hide();
		end
		button.selected = nil;
		if ( not button.tracked:GetChecked() ) then
			button.tracked:Hide();
		end
		button.description:Show();
		button.hiddenDescription:Hide();
	end

	AchievementFrameAchievements.selection = nil;
end

-- [[ Achievement Icon ]] --

function AchievementIcon_Desaturate (self)
	self.bling:SetVertexColor(.6, .6, .6, 1);
	self.frame:SetVertexColor(.75, .75, .75, 1);
	self.texture:SetVertexColor(.55, .55, .55, 1);
end

function AchievementIcon_Saturate (self)
	self.bling:SetVertexColor(1, 1, 1, 1);
	self.frame:SetVertexColor(1, 1, 1, 1);
	self.texture:SetVertexColor(1, 1, 1, 1);
end

function AchievementIcon_OnLoad (self)
	local name = self:GetName();
	self.bling = _G[name .. "Bling"];
	self.texture = _G[name .. "Texture"];
	self.frame = _G[name .. "Overlay"];

	self.Desaturate = AchievementIcon_Desaturate;
	self.Saturate = AchievementIcon_Saturate;
end

-- [[ Achievement Shield ]] --

function AchievementShield_Desaturate (self)
	self.icon:SetTexCoord(.5, 1, 0, 1);
end

function AchievementShield_Saturate (self)
	self.icon:SetTexCoord(0, .5, 0, 1);
end

function AchievementShield_OnLoad (self)
	local name = self:GetName();
	self.icon = _G[name .. "Icon"];
	self.points = _G[name .. "Points"];

	self.Desaturate = AchievementShield_Desaturate;
	self.Saturate = AchievementShield_Saturate;
end



-- [[ AchievementButton ]] --

ACHIEVEMENTBUTTON_DESCRIPTIONHEIGHT = 20;
ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT = 84;
ACHIEVEMENTBUTTON_CRITERIAROWHEIGHT = 15;
ACHIEVEMENTBUTTON_METAROWHEIGHT = 14;
ACHIEVEMENTBUTTON_MAXHEIGHT = 232;
ACHIEVEMENTBUTTON_TEXTUREHEIGHT = 128;

function AchievementButton_UpdatePlusMinusTexture (button)
	local id = button.id;
	if ( not id ) then
		return; -- This happens when we create buttons
	end

	local display = false;
	if ( GetAchievementNumCriteria(id) ~= 0 ) then
		display = true;
	elseif ( GetPreviousAchievement(id) and button.completed ) then
		display = true;
	end

	if ( display ) then
		button.plusMinus:Show();
		if ( button.collapsed and button.saturated ) then
			button.plusMinus:SetTexCoord(0, .5, 0, .5);
		elseif ( button.collapsed ) then
			button.plusMinus:SetTexCoord(.5, 1, 0, .5);
		elseif ( button.saturated ) then
			button.plusMinus:SetTexCoord(0, .5, .5, 1);
		else
			button.plusMinus:SetTexCoord(.5, 1, .5, 1);
		end
	else
		button.plusMinus:Hide();
	end
end

function AchievementButton_Collapse (self)
	if ( self.collapsed ) then
		return;
	end

	self.collapsed = true;
	AchievementButton_UpdatePlusMinusTexture(self);
	self:SetHeight(ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT);
	_G[self:GetName() .. "Background"]:SetTexCoord(0, 1, 1-(ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT / 256), 1);
	_G[self:GetName() .. "Glow"]:SetTexCoord(0, 1, 0, ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT / 128);

	if ( not self.tracked:GetChecked() ) then
		self.tracked:Hide();
	end
end

function AchievementButton_Expand (self, height)
	if ( not self.collapsed ) then
		return;
	end

	self.collapsed = nil;
	AchievementButton_UpdatePlusMinusTexture(self);
	self:SetHeight(height);
	_G[self:GetName() .. "Background"]:SetTexCoord(0, 1, max(0, 1-(height / 256)), 1);
	_G[self:GetName() .. "Glow"]:SetTexCoord(0, 1, 0, (height+5) / 128);
end

function AchievementButton_Saturate (self)
	local name = self:GetName();
	self.saturated = true;
	_G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0, 0.3125);
	_G[name .. "Background"]:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Parchment-Horizontal");
	_G[name .. "Glow"]:SetVertexColor(1.0, 1.0, 1.0);

	_G[name .. "TitleBackground"]:SetVertexColor(1.0, 1.0, 1.0, 0.8);
	_G[name .. "BottomLeftTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.2);
	_G[name .. "BottomRightTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.2);
	_G[name .. "TopLeftTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.1);
	_G[name .. "TopRightTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.1);
	_G[name .. "BottomTsunami1"]:SetVertexColor(1.0, 1.0, 1.0, 0.35);
	_G[name .. "TopTsunami1"]:SetVertexColor(1.0, 1.0, 1.0, 0.3);

	self.icon:Saturate();
	self.shield:Saturate();
	self.shield.points:SetVertexColor(1, 1, 1);
	self.reward:SetVertexColor(1, .82, 0);
	self.label:SetVertexColor(1, 1, 1);
	self.description:SetTextColor(0, 0, 0, 1);
	self.description:SetShadowOffset(0, 0);
	AchievementButton_UpdatePlusMinusTexture(self);
	self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
end

function AchievementButton_Desaturate (self)
	local name = self:GetName();
	self.saturated = nil;
	_G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0.34375, 0.65625);
	_G[name .. "Background"]:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Parchment-Horizontal-Desaturated");
	_G[name .. "Glow"]:SetVertexColor(.22, .17, .13);

	_G[name .. "TitleBackground"]:SetVertexColor(1.0, 1.0, 1.0, 0.8);
	_G[name .. "BottomLeftTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.2);
	_G[name .. "BottomRightTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.2);
	_G[name .. "TopLeftTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.1);
	_G[name .. "TopRightTsunami"]:SetVertexColor(1.0, 1.0, 1.0, 0.1);
	_G[name .. "BottomTsunami1"]:SetVertexColor(1.0, 1.0, 1.0, 0.35);
	_G[name .. "TopTsunami1"]:SetVertexColor(1.0, 1.0, 1.0, 0.3);

	self.icon:Desaturate();
	self.shield:Desaturate();
	self.shield.points:SetVertexColor(.65, .65, .65);
	self.reward:SetVertexColor(.8, .8, .8);
	self.label:SetVertexColor(.65, .65, .65);
	self.description:SetTextColor(1, 1, 1, 1);
	self.description:SetShadowOffset(1, -1);
	AchievementButton_UpdatePlusMinusTexture(self);
	self:SetBackdropBorderColor(.5, .5, .5);
end

function AchievementButton_OnLoad (self)
	local name = self:GetName();
	self.mouseOver = false
	self.label = _G[name .. "Label"];
	self.description = _G[name .. "Description"];
	self.hiddenDescription = _G[name .. "HiddenDescription"];
	self.reward = _G[name .. "Reward"];
	self.rewardBackground = _G[name.."RewardBackground"];
	self.icon = _G[name .. "Icon"];
	self.shield = _G[name .. "Shield"];
	self.objectives = _G[name .. "Objectives"];
	self.highlight = _G[name .. "Highlight"];
	self.dateCompleted = _G[name .. "DateCompleted"]
	self.tracked = _G[name .. "Tracked"];
	self.check = _G[name .. "Check"];
	self.plusMinus = _G[name .. "PlusMinus"];
	self.OnEnter = function(self)
		self.mouseOver = true
	end
	self.OnLeave = function(self)
		self.mouseOver = false
	end

	self.dateCompleted:ClearAllPoints();
	self.dateCompleted:SetPoint("TOP", self.shield, "BOTTOM", -3, 6);
	if ( not ACHIEVEMENTUI_FONTHEIGHT ) then
		local fontName, fontHeight, fontFlags = self.description:GetFont();
		if ( not fontHeight or fontHeight == 0 ) then
			-- Fallback for TBC compatibility
			fontHeight = 10;
		end
		ACHIEVEMENTUI_FONTHEIGHT = fontHeight;
	end
	self.description:SetHeight(ACHIEVEMENTUI_FONTHEIGHT * ACHIEVEMENTUI_MAX_LINES_COLLAPSED);
	self.description:SetWidth(ACHIEVEMENTUI_MAXCONTENTWIDTH);
	self.hiddenDescription:SetWidth(ACHIEVEMENTUI_MAXCONTENTWIDTH);

	self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
	self.Collapse = AchievementButton_Collapse;
	self.Expand = AchievementButton_Expand;
	self.Saturate = AchievementButton_Saturate;
	self.Desaturate = AchievementButton_Desaturate;

	self:Collapse();
	self:Desaturate();

	AchievementFrameAchievements.buttons = AchievementFrameAchievements.buttons or {};
	tinsert(AchievementFrameAchievements.buttons, self);
end

function AchievementButton_OnClick (self, ignoreModifiers)
	-- if(IsModifiedClick() and not ignoreModifiers) then
	-- 	if ( IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() ) then
	-- 		local achievementLink = GetAchievementLink(self.id);
	-- 		if ( achievementLink ) then
	-- 			ChatEdit_InsertLink(achievementLink);
	-- 		end
	-- 	elseif ( IsModifiedClick("QUESTWATCHTOGGLE") ) then
	-- 		AchievementButton_ToggleTracking(self.id);
	-- 	end

	-- 	return;
	-- end
	debug ('AchievementButton_OnClick ' .. self:GetName())

	if ( self.selected ) then
		if ( not self.mouseOver ) then

			self.highlight:Hide();
		end
		AchievementFrameAchievements_ClearSelection()
		HybridScrollFrame_CollapseButton(AchievementFrameAchievementsContainer);
		AchievementFrameAchievements_Update();
		return;
	end
	AchievementFrameAchievements_ClearSelection()
	AchievementFrameAchievements_SelectButton(self);
	local selectedCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		selectedCategory = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		selectedCategory = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	AchievementButton_DisplayAchievement(self, selectedCategory, self.index, self.id);
	HybridScrollFrame_ExpandButton(AchievementFrameAchievementsContainer, ((self.index - 1) * ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT), self:GetHeight());
	AchievementFrameAchievements_Update();
	if ( not ignoreModifiers ) then
		AchievementFrameAchievements_AdjustSelection();
	end
end

function AchievementButton_ToggleTracking (id)
	if ( trackedAchievements[id] ) then
		RemoveTrackedAchievement(id);
		AchievementFrameAchievements_ForceUpdate();
		WatchFrame_Update();
		return;
	end

	local count = GetNumTrackedAchievements();

	if ( count >= WATCHFRAME_MAXACHIEVEMENTS ) then
		UIErrorsFrame:AddMessage(format(ACHIEVEMENT_WATCH_TOO_MANY, WATCHFRAME_MAXACHIEVEMENTS), 1.0, 0.1, 0.1, 1.0);
		return;
	end

	local _, _, _, completed = GetAchievementInfo(id)
	if ( completed ) then
		UIErrorsFrame:AddMessage(ERR_ACHIEVEMENT_WATCH_COMPLETED, 1.0, 0.1, 0.1, 1.0);
		return;
	end

	AddTrackedAchievement(id);
	AchievementFrameAchievements_ForceUpdate();
	WatchFrame_Update();

	return true;
end

function AchievementButton_DisplayAchievement (button, category, achievement, selectionID)
	local id, name, points, completed, month, day, year, description, flags, icon, rewardText = GetAchievementInfo(category, achievement);
	debug('AchievementButton_DisplayAchievement '.. category .. ' ' .. id .. ' ' .. (name or 'nil'))
	if ( not id ) then
		button:Hide();
		return;
	else
		button:Show();
	end

	button.index = achievement;
	button.element = true;

	if ( button.id ~= id ) then
		button.id = id;
		button.label:SetWidth(ACHIEVEMENTBUTTON_LABELWIDTH);
		button.label:SetText(name)

		if ( GetPreviousAchievement(id) ) then
			-- If this is a progressive achievement, show the total score.
			AchievementShield_SetPoints(AchievementButton_GetProgressivePoints(id), button.shield.points, AchievementPointsFont, AchievementPointsFontSmall);
		else
			AchievementShield_SetPoints(points, button.shield.points, AchievementPointsFont, AchievementPointsFontSmall);
		end

		if ( points > 0 ) then
			button.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields]]);
		else
			button.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields-NoPoints]]);
		end
		button.description:SetText(description);
		button.hiddenDescription:SetText(description);
		local hiddenHeight = button.hiddenDescription:GetHeight();
		if ( hiddenHeight == 0 or not hiddenHeight ) then
			-- TBC compatibility: GetHeight might return 0 if not rendered yet
			hiddenHeight = button.hiddenDescription:GetStringHeight() or (ACHIEVEMENTUI_FONTHEIGHT * 2);
		end
		button.numLines = ceil(hiddenHeight / ACHIEVEMENTUI_FONTHEIGHT);

		if (icon) then
			local iconFromTable = iconTable[icon]
			if (iconFromTable) then
				button.icon.texture:SetTexture(iconFromTable);
				button.icon.texture:SetTexture([[Interface\AddOns\Achiever\textures\]] .. iconFromTable);
			end
		end
		button.hiddenDescription:SetTextColor(0, 0, 0, 1);
		button.hiddenDescription:SetShadowOffset(0, 0);
		if ( completed and not button.completed ) then
			button.completed = true;
			button.dateCompleted:SetText(string.format('%d/%d/%d', day, month, year));
			button.dateCompleted:Show();
			button:Saturate();
		elseif ( completed ) then
			button.dateCompleted:SetText(string.format('%d/%d/%d', day, month, year));
		else
			button.completed = nil;
			button.dateCompleted:Hide();
			button.hiddenDescription:SetTextColor(1, 1, 1, 1);
			button.hiddenDescription:SetShadowOffset(1, -1);
			button:Desaturate();
		end

		if ( rewardText == "" ) then
			button.reward:Hide();
			button.rewardBackground:Hide();
		else
			button.reward:SetText(rewardText);
			button.reward:Show();
			button.rewardBackground:Show();
			if ( button.completed ) then
				button.rewardBackground:SetVertexColor(1, 1, 1);
			else
				button.rewardBackground:SetVertexColor(0.35, 0.35, 0.35);
			end
		end

		if ( IsTrackedAchievement(id) ) then
			button.check:Show();
			button.label:SetWidth(button.label:GetStringWidth() + 4); -- This +4 here is to fudge around any string width issues that arize from resizing a string set to its string width. See bug 144418 for an example.
			button.tracked:SetChecked(true);
			button.tracked:Show();
		else
			button.check:Hide();
			button.tracked:SetChecked(false);
			button.tracked:Hide();
		end

		AchievementButton_UpdatePlusMinusTexture(button);
	end



	if ( id == selectionID ) then
		local achievements = AchievementFrameAchievements;

		achievements.selection = button.id;
		achievements.selectionIndex = button.index;
		button.selected = true;
		button.highlight:Show();
		local height = AchievementButton_DisplayObjectives(button, button.id, button.completed);
		if ( height == ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT ) then
			button:Collapse();
		else
			button:Expand(height);
		end
		if ( not completed ) then
			button.tracked:Show();
		end
	elseif ( button.selected ) then
		button.selected = nil;
		-- if ( not button:IsMouseOver() ) then
		if ( not button.mouseOver ) then
			button.highlight:Hide();
		end
		button:Collapse();
		button.description:Show();
		button.hiddenDescription:Hide();
	end

	return id;
end

function AchievementFrameAchievements_SelectButton (button)
	local achievements = AchievementFrameAchievements;

	achievements.selection = button.id;
	achievements.selectionIndex = button.index;
	button.selected = true;
end

function AchievementButton_ResetObjectives ()
	AchievementFrameAchievementsObjectives:Hide();
end

function AchievementButton_DisplayObjectives (button, id, completed)
	local objectives = AchievementFrameAchievementsObjectives;

	objectives:ClearAllPoints();
	objectives:SetParent(button);
	objectives:Show();
	objectives.completed = completed;
	local height = 0;
	if ( objectives.id == id ) then
		local ACHIEVEMENTMODE_CRITERIA = 1;
		if ( objectives.mode == ACHIEVEMENTMODE_CRITERIA ) then
			if ( objectives:GetHeight() > 0 ) then
				objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
				objectives:SetPoint("LEFT", "$parentIcon", "RIGHT", -5, 0);
				objectives:SetPoint("RIGHT", "$parentShield", "LEFT", -10, 0);
			end
			height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
		else
			objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
			height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
		end
	elseif ( completed and GetPreviousAchievement(id) ) then
		objectives:SetHeight(0);
		AchievementButton_ResetCriteria();
		AchievementButton_ResetProgressBars();
		AchievementButton_ResetMiniAchievements();
		AchievementButton_ResetMetas();
		AchievementObjectives_DisplayProgressiveAchievement(objectives, id);
		objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
		height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
	else
		objectives:SetHeight(0);
		AchievementButton_ResetCriteria();
		AchievementButton_ResetProgressBars();
		AchievementButton_ResetMiniAchievements();
		AchievementButton_ResetMetas();
		AchievementObjectives_DisplayCriteria(objectives, id);
		if ( objectives:GetHeight() > 0 ) then
			objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
			objectives:SetPoint("LEFT", "$parentIcon", "RIGHT", -5, -25);
			objectives:SetPoint("RIGHT", "$parentShield", "LEFT", -10, 0);
		end
		height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
	end

	if ( height ~= ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT or button.numLines > ACHIEVEMENTUI_MAX_LINES_COLLAPSED ) then
		button.hiddenDescription:Show();
		button.description:Hide();
		local descriptionHeight = button.hiddenDescription:GetHeight();
		height = height + descriptionHeight - ACHIEVEMENTBUTTON_DESCRIPTIONHEIGHT;
		if ( button.reward:IsShown() ) then
			height = height + 4;
		end
	end

	objectives.id = id;
	return height;
end

function AchievementShield_SetPoints(points, pointString, normalFont, smallFont)
	if ( points == 0 ) then
		pointString:SetText("");
		return;
	end
	if ( points <= 100 ) then
		pointString:SetFontObject(normalFont);
	else
		pointString:SetFontObject(smallFont);
	end
	pointString:SetText(points);
end

function AchievementButton_ResetTable (t)
	for k, v in next, t do
		v:Hide();
	end
end

local criteriaTable = {}

function AchievementButton_ResetCriteria ()
	AchievementButton_ResetTable(criteriaTable);
end

function AchievementButton_GetCriteria (index)
	local criteriaTable = criteriaTable;

	if ( criteriaTable[index] ) then
		return criteriaTable[index];
	end

	local frame = CreateFrame("FRAME", "AchievementFrameCriteria" .. index, AchievementFrameAchievements, "AchievementCriteriaTemplate");
	AchievementFrame_LocalizeCriteria(frame);
	criteriaTable[index] = frame;

	return frame;
end

-- The smallest table in WoW.
local miniTable = {}

function AchievementButton_ResetMiniAchievements ()
	AchievementButton_ResetTable(miniTable);
end

function AchievementButton_GetMiniAchievement (index)
	local miniTable = miniTable;
	if ( miniTable[index] ) then
		return miniTable[index];
	end

	local frame = CreateFrame("FRAME", "AchievementFrameMiniAchievement" .. index, AchievementFrameAchievements, "MiniAchievementTemplate");
	AchievementButton_LocalizeMiniAchievement(frame);
	miniTable[index] = frame;

	return frame;
end

local progressBarTable = {};

function AchievementButton_ResetProgressBars ()
	AchievementButton_ResetTable(progressBarTable);
end

function AchievementButton_GetProgressBar (index)
	local progressBarTable = progressBarTable;
	if ( progressBarTable[index] ) then
		return progressBarTable[index];
	end

	local frame = CreateFrame("STATUSBAR", "AchievementFrameProgressBar" .. index, AchievementFrameAchievements, "AchievementProgressBarTemplate");
	AchievementButton_LocalizeProgressBar(frame);
	progressBarTable[index] = frame;

	return frame;
end

local metaCriteriaTable = {};

function AchievementButton_ResetMetas ()
	AchievementButton_ResetTable(metaCriteriaTable);
end

function AchievementButton_GetMeta (index)
	local metaCriteriaTable = metaCriteriaTable;
	if ( metaCriteriaTable[index] ) then
		return metaCriteriaTable[index];
	end

	local frame = CreateFrame("BUTTON", "AchievementFrameMeta" .. index, AchievementFrameAchievements, "MetaCriteriaTemplate");
	AchievementButton_LocalizeMetaAchievement(frame);
	metaCriteriaTable[index] = frame;

	return frame;
end

function AchievementButton_GetProgressivePoints(achievementID)
	local points;
	local _, _, progressivePoints, completed = GetAchievementInfo(achievementID);

	while GetPreviousAchievement(achievementID) do
		achievementID = GetPreviousAchievement(achievementID);
		_, _, points, completed = GetAchievementInfo(achievementID);
		progressivePoints = progressivePoints+points;
	end

	if ( progressivePoints ) then
		return progressivePoints;
	else
		return 0;
	end
end

local achievementList = {};

function AchievementObjectives_DisplayProgressiveAchievement (objectivesFrame, id)
	local ACHIEVEMENTMODE_PROGRESSIVE = 2;
	local achievementID = id;

	local achievementList = achievementList;
	for i in next, achievementList do
		achievementList[i] = nil;
	end

	tinsert(achievementList, 1, achievementID);
	while GetPreviousAchievement(achievementID) do
		tinsert(achievementList, 1, GetPreviousAchievement(achievementID));
		achievementID = GetPreviousAchievement(achievementID);
	end

	local i = 0;
	for index, achievementID in ipairs(achievementList) do
		local _, achievementName, points, completed, month, day, year, description, flags, iconpath = GetAchievementInfo(achievementID);

		local miniAchievement = AchievementButton_GetMiniAchievement(index);

		miniAchievement:Show();
		miniAchievement:SetParent(objectivesFrame);
		if (iconpath) then
			local iconFromTable = iconTable[iconpath]
			if (iconFromTable) then
				_G[miniAchievement:GetName() .. "Icon"]:SetTexture(iconFromTable);
				_G[miniAchievement:GetName() .. "Icon"]:SetTexture([[Interface\AddOns\Achiever\textures\]] .. iconFromTable);
			end
		end
		if ( index == 1 ) then
			miniAchievement:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", -4, -4);
		elseif ( index == 7 ) then
			miniAchievement:SetPoint("TOPLEFT", miniTable[1], "BOTTOMLEFT", 0, -8);
		else
			miniAchievement:SetPoint("TOPLEFT", miniTable[index-1], "TOPRIGHT", 4, 0);
		end

		miniAchievement.points:SetText(points);

		miniAchievement.numCriteria = 0;
		if ( not ( bit.band(flags, ACHIEVEMENT_FLAGS_HAS_PROGRESS_BAR) == ACHIEVEMENT_FLAGS_HAS_PROGRESS_BAR ) ) then
			for i = 1, GetAchievementNumCriteria(achievementID) do
				local criteriaString, criteriaType, completed = GetAchievementCriteriaInfo(achievementID, i);
				if ( completed == false ) then
					criteriaString = "|CFF808080 - " .. criteriaString;
				else
					criteriaString = "|CFF00FF00 - " .. criteriaString;
				end
				miniAchievement["criteria" .. i] = criteriaString;
				miniAchievement.numCriteria = i;
			end
		end
		miniAchievement.name = achievementName;
		miniAchievement.desc = description;
		if ( month ) then
			miniAchievement.date = string.format('%d/%d/%d', day, month, year);
		end
		i = index;
	end

	objectivesFrame:SetHeight(math.ceil(i/6) * ACHIEVEMENTUI_PROGRESSIVEHEIGHT);
	objectivesFrame:SetWidth(min(i, 6) * ACHIEVEMENTUI_PROGRESSIVEWIDTH);
	objectivesFrame.mode = ACHIEVEMENTMODE_PROGRESSIVE;
end

function AchievementFrame_GetCategoryNumAchievements_All (categoryID)
	debug('AchievementFrame_GetCategoryNumAchievements_All called with categoryID=' .. tostring(categoryID))
	local numAchievements, numCompleted = GetCategoryNumAchievements(categoryID);
	debug('GetCategoryNumAchievements returned: ' .. tostring(numAchievements) .. ', ' .. tostring(numCompleted))
	return numAchievements, numCompleted, 0;
end

function AchievementFrame_GetCategoryNumAchievements_Complete (categoryID)
	debug('AchievementFrame_GetCategoryNumAchievements_Complete called with categoryID=' .. tostring(categoryID))
	local numAchievements, numCompleted = GetCategoryNumAchievements(categoryID);
	debug('GetCategoryNumAchievements returned: ' .. tostring(numAchievements) .. ', ' .. tostring(numCompleted))
	return numCompleted, numCompleted, 0;
end

function AchievementFrame_GetCategoryNumAchievements_Incomplete (categoryID)
	debug('AchievementFrame_GetCategoryNumAchievements_Incomplete called with categoryID=' .. tostring(categoryID))
	local numAchievements, numCompleted = GetCategoryNumAchievements(categoryID);
	debug('GetCategoryNumAchievements returned: ' .. tostring(numAchievements) .. ', ' .. tostring(numCompleted))
	return numAchievements - numCompleted, 0, numCompleted
end

ACHIEVEMENTUI_SELECTEDFILTER = AchievementFrame_GetCategoryNumAchievements_All;
ACHIEVEMENTUI_SELECTEDFILTER_INDEX = 1; -- Track which filter is selected by index

AchievementFrameFilters = { {text=ACHIEVEMENTFRAME_FILTER_ALL, func= AchievementFrame_GetCategoryNumAchievements_All},
 {text=ACHIEVEMENTFRAME_FILTER_COMPLETED, func=AchievementFrame_GetCategoryNumAchievements_Complete},
{text=ACHIEVEMENTFRAME_FILTER_INCOMPLETE, func=AchievementFrame_GetCategoryNumAchievements_Incomplete} };

function AchievementFrameFilterDropDown_OnLoad (self)
	self.relativeTo = "AchievementFrameFilterDropDown"
	self.xOffset = -14;
	self.yOffset = 10;
	myUIDropDownMenu_Initialize(self, AchievementFrameFilterDropDown_Initialize);
end

function AchievementFrameFilterDropDown_Initialize (self)
	debug('AchievementFrameFilterDropDown_Initialize called, selected index=' .. tostring(ACHIEVEMENTUI_SELECTEDFILTER_INDEX))
	local info = myUIDropDownMenu_CreateInfo();
	if (not AchievementFrameFilters) then
		warn('AchievementFrameFilters is nil!')
		return
	end
	for i, filter in ipairs(AchievementFrameFilters) do
		if (filter and filter.text) then
			info.text = filter.text;
			info.value = i;
			info.func = AchievementFrameFilterDropDownButton_OnClick;
			if ( i == ACHIEVEMENTUI_SELECTEDFILTER_INDEX ) then
				info.checked = 1;
				myUIDropDownMenu_SetText(self, filter.text);
			else
				info.checked = nil;
			end
			myUIDropDownMenu_AddButton(info);
			debug('Added filter: ' .. filter.text .. ' (value=' .. i .. ', checked=' .. tostring(i == ACHIEVEMENTUI_SELECTEDFILTER_INDEX) .. ')')
		else
			warn('Invalid filter at index ' .. i)
		end
	end
end

function AchievementFrameFilterDropDownButton_OnClick (self, arg1, arg2, checked)
	debug('AchievementFrameFilterDropDownButton_OnClick: value=' .. tostring(self.value))
	if ( self.value ) then
		AchievementFrame_SetFilter(self.value);
	else
		warn('AchievementFrameFilterDropDownButton_OnClick: self.value is nil')
	end
end

function AchievementFrame_SetFilter(value)
	debug('AchievementFrame_SetFilter called with value: ' .. tostring(value) .. ', current index=' .. tostring(ACHIEVEMENTUI_SELECTEDFILTER_INDEX))
	if ( not value or not AchievementFrameFilters[value] ) then
		warn('AchievementFrame_SetFilter: invalid value ' .. tostring(value))
		return
	end
	if ( value ~= ACHIEVEMENTUI_SELECTEDFILTER_INDEX ) then
		ACHIEVEMENTUI_SELECTEDFILTER_INDEX = value;
		local func = AchievementFrameFilters[value].func;
		ACHIEVEMENTUI_SELECTEDFILTER = func;
		myUIDropDownMenu_SetText(AchievementFrameFilterDropDown, AchievementFrameFilters[value].text)
		if (AchievementFrameAchievementsContainerScrollBar) then
			AchievementFrameAchievementsContainerScrollBar:SetValue(0);
		end
		AchievementFrameAchievements_ForceUpdate();
		debug('Filter changed to: ' .. AchievementFrameFilters[value].text .. ' (index=' .. value .. ')')
	else
		debug('Filter already set to: ' .. AchievementFrameFilters[value].text .. ' (index=' .. value .. ')')
	end
end

function AchievementObjectives_DisplayCriteria (objectivesFrame, id)
	if ( not id ) then
		return;
	end

	local ACHIEVEMENTMODE_CRITERIA = 1;
	local numCriteria = GetAchievementNumCriteria(id);

	if ( numCriteria == 0 ) then
		objectivesFrame.mode = ACHIEVEMENTMODE_CRITERIA;
		objectivesFrame:SetHeight(0);
		return;
	end

	local frameLevel = objectivesFrame:GetFrameLevel() + 1;

	-- Why textStrings? You try naming anything just "string" and see how happy you are.
	local textStrings, progressBars, metas = 0, 0, 0;

    -- Compress all progress bars
    local compressBars = false;
    local totalQuantity = 0;
	local id, achievementName, points, accompleted, month, day, year, description, acflags, iconpath = GetAchievementInfo(id);
	if ( bit.band(acflags, ACHIEVEMENT_FLAG_SUMM) == ACHIEVEMENT_FLAG_SUMM ) then
		compressBars = true;
		for i = 1, numCriteria do
			local criteriaString, criteriaType, completed, quantity, reqQuantity, charName, flags, assetID, quantityString = GetAchievementCriteriaInfo(id, i);
			totalQuantity = totalQuantity + quantity;
		end
		numCriteria = 1;
	end

	for i = 1, numCriteria do
		local criteriaString, criteriaType, completed, quantity, reqQuantity, charName, flags, assetID, quantityString = GetAchievementCriteriaInfo(id, i);
		if ( bit.band(flags, ACHIEVEMENT_CRITERIA_PROGRESS_BAR) == ACHIEVEMENT_CRITERIA_PROGRESS_BAR and bit.band(flags, ACHIEVEMENT_CRITERIA_HIDDEN) == ACHIEVEMENT_CRITERIA_HIDDEN ) then
			compressBars = true;
			numCriteria = 1;
		end
	end


	local numRows = 0;
	local maxCriteriaWidth = 0;
	local yPos;
	for i = 1, numCriteria do
		local criteriaString, criteriaType, completed, quantity, reqQuantity, charName, flags, assetID, quantityString = GetAchievementCriteriaInfo(id, i);
		debug('AchievementObjectives_DisplayCriteria ' .. i)

		if ( criteriaType == CRITERIA_TYPE_ACHIEVEMENT and assetID ) then
			metas = metas + 1;
			local metaCriteria = AchievementButton_GetMeta(metas);

			if ( metas == 1 ) then
				metaCriteria:SetPoint("TOP", objectivesFrame, "TOP", 0, -4);
				numRows = numRows + 2;
			elseif ( math.fmod(metas, 2) == 0 ) then
				yPos = -((metas/2 - 1) * 28) - 8;
				metaCriteriaTable[metas-1]:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 20, yPos);
				metaCriteria:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 210, yPos);
			else
				metaCriteria:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 20, -(math.ceil(metas/2 - 1) * 28) - 8);
				numRows = numRows + 2;
			end

			local acid, achievementName, points, accompleted, month, day, year, description, acflags, iconpath = GetAchievementInfo(assetID);

			if ( month ) then
				metaCriteria.date = string.format('%d/%d/%d', day, month, year);
			else
				metaCriteria.date = nil;
			end

			metaCriteria.id = id;
			metaCriteria.label:SetText(achievementName);
			if (iconpath) then
				local iconFromTable = iconTable[iconpath]
				if (iconFromTable) then
					metaCriteria.icon:SetTexture(iconFromTable);
					metaCriteria.icon:SetTexture([[Interface\AddOns\Achiever\textures\]] .. iconFromTable);
				end
			end

			if ( objectivesFrame.completed and completed ) then
				metaCriteria.check:Show();
				metaCriteria.border:SetVertexColor(1, 1, 1, 1);
				metaCriteria.icon:SetVertexColor(1, 1, 1, 1);
				metaCriteria.label:SetShadowOffset(0, 0)
				metaCriteria.label:SetTextColor(0, 0, 0, 1);
			elseif ( completed ) then
				metaCriteria.check:Show();
				metaCriteria.border:SetVertexColor(1, 1, 1, 1);
				metaCriteria.icon:SetVertexColor(1, 1, 1, 1);
				metaCriteria.label:SetShadowOffset(1, -1)
				metaCriteria.label:SetTextColor(0, 1, 0, 1);
			else
				metaCriteria.check:Hide();
				metaCriteria.border:SetVertexColor(.75, .75, .75, 1);
				metaCriteria.icon:SetVertexColor(.55, .55, .55, 1);
				metaCriteria.label:SetShadowOffset(1, -1)
				metaCriteria.label:SetTextColor(.6, .6, .6, 1);
			end

			metaCriteria:SetParent(objectivesFrame);
			metaCriteria:Show();
		elseif ( bit.band(flags, ACHIEVEMENT_CRITERIA_PROGRESS_BAR) == ACHIEVEMENT_CRITERIA_PROGRESS_BAR ) then
			-- Display this criteria as a progress bar!
			progressBars = progressBars + 1;
			local progressBar = AchievementButton_GetProgressBar(progressBars);

			if ( progressBars == 1 ) then
				progressBar:SetPoint("TOP", objectivesFrame, "TOP", 4, -4);
			else
				progressBar:SetPoint("TOP", progressBarTable[progressBars-1], "BOTTOM", 0, 0);
			end

			--if ( bit.band(flags, ACHIEVEMENT_CRITERIA_HIDDEN) == ACHIEVEMENT_CRITERIA_HIDDEN and not compressBars) then
			--	compressBars = true;
			--	for n = 1, numCriteria do
			--		local tcriteriaString, tcriteriaType, tcompleted, tquantity, treqQuantity, tcharName, tflags, tassetID, tquantityString = GetAchievementCriteriaInfo(id, n);
			--		totalQuantity = totalQuantity + tquantity;
			--	end
			--	numCriteria = 1;
			--end

			progressBar:SetMinMaxValues(0, reqQuantity);
			if (compressBars) then
				progressBar.text:SetText(string.format("%s", totalQuantity .. ' / ' .. reqQuantity));
				progressBar:SetValue(totalQuantity);
			else
				progressBar.text:SetText(string.format("%s", quantityString));
				progressBar:SetValue(quantity);
			end

			progressBar:SetParent(objectivesFrame);
			progressBar:Show();

			numRows = numRows + 1;
		elseif (achieverDBpc.debug == "enabled" or not ( bit.band(flags, ACHIEVEMENT_CRITERIA_HIDDEN) == ACHIEVEMENT_CRITERIA_HIDDEN) ) then
			textStrings = textStrings + 1;
			local criteria = AchievementButton_GetCriteria(textStrings);
			criteria:ClearAllPoints();
			if ( textStrings == 1 ) then
				if ( numCriteria == 1 ) then
					criteria:SetPoint("TOP", objectivesFrame, "TOP", -14, 0);
				else
					criteria:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 0, 0);
				end

			else
				criteria:SetPoint("TOPLEFT", criteriaTable[textStrings-1], "BOTTOMLEFT", 0, 0);
			end

			if ( objectivesFrame.completed and completed ) then
				criteria.name:SetTextColor(0, 0, 0, 1);
				criteria.name:SetShadowOffset(0, 0);
			elseif ( completed ) then
				criteria.name:SetTextColor(0, 1, 0, 1);
				criteria.name:SetShadowOffset(1, -1);
			else
				criteria.name:SetTextColor(.6, .6, .6, 1);
				criteria.name:SetShadowOffset(1, -1);
			end

			if ( completed ) then
				criteria.check:SetPoint("LEFT", 18, -3);
				criteria.name:SetPoint("LEFT", criteria.check, "RIGHT", 0, 2);
				criteria.check:Show();
				criteria.name:SetText(criteriaString);
			else
				criteria.check:SetPoint("LEFT", 0, -3);
				criteria.name:SetPoint("LEFT", criteria.check, "RIGHT", 5, 2);
				criteria.check:Hide();
				criteria.name:SetText("- "..criteriaString);
			end

			criteria:SetParent(objectivesFrame);
			criteria:Show();
			local stringWidth = criteria.name:GetStringWidth()
			criteria:SetWidth(stringWidth + criteria.check:GetWidth());
			maxCriteriaWidth = max(maxCriteriaWidth, stringWidth + criteria.check:GetWidth());

			numRows = numRows + 1;
		end
	end

	if ( textStrings > 0 and progressBars > 0 ) then
		-- If we have text criteria and progressBar criteria, display the progressBar criteria first and position the textStrings under them.
		criteriaTable[1]:ClearAllPoints();
		if ( textStrings == 1 ) then
			criteriaTable[1]:SetPoint("TOP", progressBarTable[progressBars], "BOTTOM", -14, -4);
		else
			criteriaTable[1]:SetPoint("TOP", progressBarTable[progressBars], "BOTTOM", 0, -4);
			criteriaTable[1]:SetPoint("LEFT", objectivesFrame, "LEFT", 0, 0);
		end
	elseif ( textStrings > 1 ) then
		-- Figure out if we can make multiple columns worth of criteria instead of one long one
		local numColumns = floor(ACHIEVEMENTUI_MAXCONTENTWIDTH/maxCriteriaWidth);
		if ( numColumns > 1 ) then
			local step;
			local rows = 1;
			local position = 0;
			local criteriaTableCount = table.getn(criteriaTable)
			for i=1, criteriaTableCount do
				position = position + 1;
				if ( position > numColumns ) then
					position = position - numColumns;
					rows = rows + 1;
				end

				if ( rows == 1 ) then
					criteriaTable[i]:ClearAllPoints();
					criteriaTable[i]:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", (position - 1)*(ACHIEVEMENTUI_MAXCONTENTWIDTH/numColumns), 0);
				else
					criteriaTable[i]:ClearAllPoints();
					criteriaTable[i]:SetPoint("TOPLEFT", criteriaTable[position + ((rows - 2) * numColumns)], "BOTTOMLEFT", 0, 0);
				end
			end
			numRows = ceil(numRows/numColumns);
		end
	end

	if ( metas > 0 ) then
		objectivesFrame:SetHeight(numRows * ACHIEVEMENTBUTTON_METAROWHEIGHT + 10);
	else
		objectivesFrame:SetHeight(numRows * ACHIEVEMENTBUTTON_CRITERIAROWHEIGHT);
	end
	objectivesFrame.mode = ACHIEVEMENTMODE_CRITERIA;
end

-- [[ StatsFrames ]]--

function AchievementFrameStats_OnEvent (self, event, ...)
	if ( event == "CRITERIA_UPDATE" and self:IsShown() ) then
		AchievementFrameStats_Update();
	end
end

function AchievementFrameStats_OnLoad (self)
	AchievementFrameStatsContainerScrollBar.OriginalShow = AchievementFrameStatsContainerScrollBar.Show
	AchievementFrameStatsContainerScrollBar.Show =
		function (self)
			AchievementFrameStats:SetWidth(504);
			for _, button in next, AchievementFrameStats.buttons do
				button:SetWidth(496);
			end
			self:OriginalShow(self)
			-- getmetatable(self).__index.Show(self);
		end

	AchievementFrameStatsContainerScrollBar.OriginalHide = AchievementFrameStatsContainerScrollBar.Hide
	AchievementFrameStatsContainerScrollBar.Hide =
		function (self)
			AchievementFrameStats:SetWidth(530);
			for _, button in next, AchievementFrameStats.buttons do
				button:SetWidth(522);
			end
			self:OriginalHide(self)
			-- getmetatable(self).__index.Hide(self);
		end

	self:RegisterEvent("CRITERIA_UPDATE");
	AchievementFrameStatsContainerScrollBarBG:Show();
	AchievementFrameStatsContainer.update = AchievementFrameStats_Update;
	HybridScrollFrame_CreateButtons(AchievementFrameStatsContainer, "StatTemplate");
end

local displayStatCategories = {};

function AchievementFrameStats_Update ()
	local category;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		category = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		category = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		category = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		category = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	local scrollFrame = AchievementFrameStatsContainer;
	local offset = HybridScrollFrame_GetOffset(scrollFrame);
	local buttons = scrollFrame.buttons;
	local numButtons = table.getn(buttons); -- #buttons;
	local statHeight = 24;

	local numStats, numCompleted = GetCategoryNumAchievements(category, true);
	debug ('AchievementFrameStats_Update ' .. category .. ' '..numStats)
	local categories = ACHIEVEMENTUI_CATEGORIES;

	local lastCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		lastCategory = ACHIEVEMENT_FUNCTIONS.lastCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		lastCategory = STAT_FUNCTIONS.lastCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		lastCategory = COMPARISON_ACHIEVEMENT_FUNCTIONS.lastCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		lastCategory = COMPARISON_STAT_FUNCTIONS.lastCategory
	end

	-- clear out table
	if ( lastCategory ~= category ) then
		local statCat;
		for i in next, displayStatCategories do
			displayStatCategories[i] = nil;
		end
		displayStatCategories = {}
		-- build a list of shown category and stat id's

		tinsert(displayStatCategories, {id = category, header = true});
		for i=1, numStats do
			tinsert(displayStatCategories, {id = GetAchievementInfo(category, i, true)});
		end
		-- add all the subcategories and their stat id's
		for i, cat in next, categories do
			-- debug('~!!!!!!!!!!!!!!!!!!!!!!!! ' .. category .. ' ' .. (cat.parent or 'nil'))
			if ( cat.parent == category ) then
				tinsert(displayStatCategories, {id = cat.id, header = true});
				numStats = GetCategoryNumAchievements(cat.id, true);
				debug('AchievementFrameStats_Update HEADER ' .. numStats)
				for k=1, numStats do
					tinsert(displayStatCategories, {id = GetAchievementInfo(cat.id, k, true)});
				end
			end
		end
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
			ACHIEVEMENT_FUNCTIONS.lastCategory = category;
		elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
			STAT_FUNCTIONS.lastCategory = category;
		elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			COMPARISON_ACHIEVEMENT_FUNCTIONS.lastCategory = category;
		elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
			COMPARISON_STAT_FUNCTIONS.lastCategory = category;
		end
	end

	-- iterate through the displayStatCategories and display them
	local selection = AchievementFrameStats.selection;
	local statCount = table.getn(displayStatCategories); -- #displayStatCategories;
	local statIndex, id, button;
	local stat;

	local totalHeight = statCount * statHeight;
	local displayedHeight = numButtons * statHeight;
	for i = 1, numButtons do
		button = buttons[i];
		statIndex = offset + i;
		if ( statIndex <= statCount ) then
			stat = displayStatCategories[statIndex];
			if ( stat.header ) then
				AchievementFrameStats_SetHeader(button, stat.id);
			else
				AchievementFrameStats_SetStat(button, stat.id, nil, statIndex);
			end
			button:Show();
		else
			button:Hide();
		end
	end
	HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);
end

function AchievementFrameStats_SetStat(button, category, index, colorIndex, isSummary)
	--Remove these variables when we know for sure we don't need them
	local id, name, points, completed, month, day, year, description, flags, icon;
	if ( not isSummary ) then
		if ( not index ) then
			debug ('AchievementFrameStats_SetStat no summary no index ' .. category)
			id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category);
		else
			debug ('AchievementFrameStats_SetStat no summary INDEX '..category .. ' ' .. index)
			id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category, index);
		end

	else
		debug ('AchievementFrameStats_SetStat SUMMARY ' .. category)
		-- This is on the summary page
		id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfoFromCriteria(category);
	end

	button.id = id;

	if ( not colorIndex ) then
		if ( not index ) then
			message("Error, need a color index or index");
		end
		colorIndex = index;
	end
	button:SetText(name);

	button.background:Show();
	-- Color every other line yellow
	if ( mod(colorIndex, 2) == 1 ) then
		button.background:SetTexCoord(0, 1, 0.1875, 0.3671875);
		button.background:SetBlendMode("BLEND");
		button.background:SetAlpha(1.0);
		button:SetHeight(24);
	else
		button.background:SetTexCoord(0, 1, 0.375, 0.5390625);
		button.background:SetBlendMode("ADD");
		button.background:SetAlpha(0.5);
		button:SetHeight(24);
	end

	-- Figure out the criteria
	local numCriteria = GetAchievementNumCriteria(id);
	if ( numCriteria == 0 ) then
		-- This is no good!
	end
	-- Just show the first criteria for now
	local criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity;
	if ( not isSummary ) then
		quantity = GetStatistic(id);
		if ( quantity > 0 ) then
			criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID = GetAchievementCriteriaInfo(id, 1);
			if (quantity and reqQuantity and quantity <= (reqQuantity * numCriteria) ) then
				quantity = floor(quantity / reqQuantity)
			end
		end
	else
		criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity = GetAchievementCriteriaInfo(category);
	end
	if ( not quantity or quantity == 0) then
		quantity = "--";
	end
	if ( quantity and flags and ( bit.band(flags, ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER) == ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER ) ) then
        quantity = getTextGSC(quantity, true, false)
    end

	button.value:SetText(quantity);

	-- Hide the header images
	button.title:Hide();
	button.left:Hide();
	button.middle:Hide();
	button.right:Hide();
	button.isHeader = false;
end

function AchievementFrameStats_SetHeader(button, id)
	-- show header
	button.left:Show();
	button.middle:Show();
	button.right:Show();
	local text;
	if ( id == ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID ) then
		text = ACHIEVEMENT_SUMMARY_CATEGORY;
	else
		text = GetCategoryInfo(id);
	end
	button.title:SetText(text);
	button.title:Show();
	button.value:SetText("");
	button:SetText("");
	button:SetHeight(24);
	button.background:Hide();
	button.isHeader = true;
	button.id = id;
end

function AchievementStatButton_OnLoad(self, parentFrame)
	local name = self:GetName();
	self.background = _G[name.."BG"];
	self.left = _G[name.."HeaderLeft"];
	self.middle = _G[name.."HeaderMiddle"];
	self.right = _G[name.."HeaderRight"];
	self.text = _G[name.."Text"];
	self.title = _G[name.."Title"];
	self.value = _G[name.."Value"];
	self.value:SetVertexColor(1, 0.97, 0.6);
	parentFrame.buttons = parentFrame.buttons or {};
	tinsert(parentFrame.buttons, self);
end

function AchievementStatButton_OnClick(self, button, down)
	if ( self.isHeader ) then
		local selectedCategory;
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
			ACHIEVEMENT_FUNCTIONS.selectedCategory = self.id;
		elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
			STAT_FUNCTIONS.selectedCategory = self.id;
		elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory = self.id;
		elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
			COMPARISON_STAT_FUNCTIONS.selectedCategory = self.id;
		end
		AchievementFrameCategories_Update();
		AchievementFrameStats_Update();
	elseif ( self.summary ) then
		AchievementFrame_SelectSummaryStatistic(self.id);
	end
end

-- [[ Summary Frame ]] --
function AchievementFrameSummary_OnShow()
	debug('AchievementFrameSummary_OnShow //////////')
	if ( USE_FUNCTIONS ~= 'COMPARISON_ACHIEVEMENT_FUNCTIONS' and USE_FUNCTIONS ~= 'COMPARISON_STAT_FUNCTIONS' ) then
		debug('AchievementFrameSummary_OnShow ////////// AchievementFrameSummary:SetWidth(530);')
		AchievementFrameSummary:SetWidth(530);
		AchievementFrameSummary_Update();
	else
		AchievementFrameComparisonDark:Hide();
		AchievementFrameComparisonWatermark:Hide();
		AchievementFrameComparison:SetWidth(650);
		AchievementFrameSummary:SetWidth(650);
		AchievementFrameSummary_Update(true);
	end
end

function AchievementFrameSummary_Update(isCompare)
	AchievementFrameSummaryCategoriesStatusBar_Update();
	AchievementFrameSummary_UpdateAchievements(GetLatestCompletedAchievements());
end

function AchievementFrameSummary_UpdateAchievements(...)
	local numAchievements = arg.n; -- select("#", ...);
	debug('AchievementFrameSummary_UpdateAchievements ' .. numAchievements)
	local id, name, points, completed, month, day, year, description, flags, icon;
	local buttons = AchievementFrameSummaryAchievements.buttons;
	local button, anchorTo, achievementID;
	local defaultAchievementCount = 1;

	for i = 1, ACHIEVEMENTUI_MAX_SUMMARY_ACHIEVEMENTS do
		if (buttons) then
			button = buttons[i];
		end
		if (not button) then
			button = CreateFrame('Button', 'AchievementFrameSummaryAchievement' .. i, AchievementFrameSummaryAchievements, 'SummaryAchievementTemplate');

			if (i == 1) then
				button:SetPoint('TOPLEFT', AchievementFrameSummaryAchievementsHeader, 'BOTTOMLEFT', 18, 2);
				button:SetPoint('TOPRIGHT', AchievementFrameSummaryAchievementsHeader, 'BOTTOMRIGHT', -18, 2);
			else
				anchorTo = _G['AchievementFrameSummaryAchievement' .. i - 1];
				button:SetPoint('TOPLEFT', anchorTo, 'BOTTOMLEFT', 0, 3 );
				button:SetPoint('TOPRIGHT', anchorTo, 'BOTTOMRIGHT', 0, 3);
			end

			if (not buttons) then
				buttons = AchievementFrameSummaryAchievements.buttons;
			end
			AchievementFrameSummary_LocalizeButton(button);
		end;

		if (i <= numAchievements) then
			achievementID = arg[i];
			id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(achievementID);

			button.label:SetText(name);
			button.description:SetText(description);
			AchievementShield_SetPoints(points, button.shield.points, GameFontNormal, GameFontNormalSmall);
			if ( points > 0 ) then
				button.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields]]);
			else
				button.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields-NoPoints]]);
			end

			if (icon) then
				local iconFromTable = iconTable[icon]
				if (iconFromTable) then
					button.icon.texture:SetTexture(iconFromTable);
					button.icon.texture:SetTexture([[Interface\AddOns\Achiever\textures\]] .. iconFromTable);
				end
			end
			button.id = id;

			if (completed) then
				button.dateCompleted:SetText(string.format('%d/%d/%d', day, month, year));
			else
				button.dateCompleted:SetText("");
			end

			button:Show();
			button:Saturate();
			button.tooltipTitle = nil;
		else
			debug('AchievementFrameSummary_UpdateAchievements i > numAchievements')
			for i=defaultAchievementCount, ACHIEVEMENTUI_MAX_SUMMARY_ACHIEVEMENTS do
				achievementID = ACHIEVEMENTUI_DEFAULTSUMMARYACHIEVEMENTS[defaultAchievementCount];
				if (not achievementID) then
					break;
				end
				id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(achievementID);
				if (completed) then
					defaultAchievementCount = defaultAchievementCount + 1;
				else
					-- id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(achievementID);
					button.label:SetText(name);
					button.description:SetText(description);
					AchievementShield_SetPoints(points, button.shield.points, GameFontNormal, GameFontNormalSmall);
					if ( points > 0 ) then
						button.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields]]);
					else
						button.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields-NoPoints]]);
					end
					if (icon) then
						local iconFromTable = iconTable[icon]
						if (iconFromTable) then
							button.icon.texture:SetTexture(iconFromTable);
							button.icon.texture:SetTexture([[Interface\AddOns\Achiever\textures\]] .. iconFromTable);
						end
					end
					button.id = id;
					if (month) then
						button.dateCompleted:SetText(string.format('%d/%d/%d', day, month, year));
					else
						button.dateCompleted:SetText("");
					end
					button:Show();
					defaultAchievementCount = defaultAchievementCount + 1;
					button:Desaturate();
					button.tooltipTitle = SUMMARY_ACHIEVEMENT_INCOMPLETE;
					button.tooltip = SUMMARY_ACHIEVEMENT_INCOMPLETE_TEXT;
					-- _G[button.GetName()..Background]:Desaturate();
					-- button.description:SetTextColor(0.3, 0.3, 0.3);
					break;
				end
			end
		end
	end
	if ( numAchievements == 0 ) then
		AchievementFrameSummaryAchievementsEmptyText:Show();
	else
		AchievementFrameSummaryAchievementsEmptyText:Hide();
	end
end

function AchievementFrameSummaryCategoriesStatusBar_Update()
	local total, completed = GetNumCompletedAchievements();
	AchievementFrameSummaryCategoriesStatusBar:SetMinMaxValues(0, total);
	AchievementFrameSummaryCategoriesStatusBar:SetValue(completed);
	AchievementFrameSummaryCategoriesStatusBarText:SetText(completed.."/"..total);
end

function AchievementFrameSummaryAchievement_OnLoad(self)
	AchievementComparisonPlayerButton_OnLoad(self);
	self.highlight = _G[self:GetName().."Highlight"];
	AchievementFrameSummaryAchievements.buttons = AchievementFrameSummaryAchievements.buttons or {};
	tinsert(AchievementFrameSummaryAchievements.buttons, self);
	self:Saturate();
	self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, 0.5);
	self.titleBar:SetVertexColor(1,1,1,0.5);
	self.dateCompleted:Show();
end

function AchievementFrameSummaryAchievement_OnClick(self, button, down)
	local id = self.id
	local nextID, completed = GetNextAchievement(id);
	if ( nextID and completed ) then
		local newID;
		while ( nextID and completed ) do
			newID, completed = GetNextAchievement(nextID);
			if ( completed ) then
				nextID = newID;
			end
		end
		id = nextID;
	end

	AchievementFrame_SelectAchievement(id);
end

function AchievementFrameSummaryAchievement_OnEnter(self)
	self.highlight:Show();
	if ( self.tooltipTitle ) then
		GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
		GameTooltip:SetText(self.tooltipTitle,1,1,1);
		GameTooltip:AddLine(self.tooltip, nil, nil, nil, 1);
		GameTooltip:Show();
	end
end

function AchievementFrameSummaryCategoryButton_OnClick (self, button, down)
	local id = self:GetParent():GetID();
	for _, button in next, AchievementFrameCategoriesContainer.buttons do
		if ( button.categoryID == id ) then
			button:Click();
			return;
		end
	end
end

function AchievementFrameSummaryCategory_OnLoad (self)
	self:SetMinMaxValues(0, 100);
	self:SetValue(0);
	local name = self:GetName();
	self.text = _G[name .. "Text"];
	self.label = _G[name .. "Label"];

	local categoryName = GetCategoryInfo(self:GetID());
	self.label:SetText(categoryName);
end

function AchievementFrame_GetCategoryTotalNumAchievements (id, showAll)
	-- Not recursive because we only have one deep and this saves time.
	local totalAchievements, totalCompleted = 0, 0;
	local numAchievements, numCompleted = GetCategoryNumAchievements(id, showAll);
	totalAchievements = totalAchievements + numAchievements;
	totalCompleted = totalCompleted + numCompleted;

	for _, category in next, ACHIEVEMENTUI_CATEGORIES do
		if ( category.parent == id ) then
			numAchievements, numCompleted = GetCategoryNumAchievements(category.id, showAll);
			totalAchievements = totalAchievements + numAchievements;
			totalCompleted = totalCompleted + numCompleted;
		end
	end

	return totalAchievements, totalCompleted;
end

function AchievementFrameSummaryCategory_OnEvent (self, event, ...)
	AchievementFrameSummaryCategory_OnShow(self);
end

function AchievementFrameSummaryCategory_OnShow (self)
	local totalAchievements, totalCompleted = AchievementFrame_GetCategoryTotalNumAchievements(self:GetID(), true);

	local categoryName = GetCategoryInfo(self:GetID());
	self.label:SetText(categoryName);
	self.text:SetText(string.format("%d/%d", totalCompleted, totalAchievements));
	self:SetMinMaxValues(0, totalAchievements);
	self:SetValue(totalCompleted);
	self:RegisterEvent("ACHIEVEMENT_EARNED");
	Achiever.achievementFrameSummaryCategorySubscribers[self:GetName()] = self
end

function AchievementFrameSummaryCategory_OnHide (self)
	Achiever.achievementFrameSummaryCategorySubscribers[self:GetName()] = nil
	self:UnregisterEvent("ACHIEVEMENT_EARNED");
end

function AchievementFrame_SelectAchievement(id, forceSelect)
	if ( not AchievementFrame:IsShown() and not forceSelect ) then
		return;
	end

	local _, _, _, achCompleted = GetAchievementInfo(id);
	if ( achCompleted and (ACHIEVEMENTUI_SELECTEDFILTER == AchievementFrameFilters[ACHIEVEMENT_FILTER_INCOMPLETE].func) ) then
		AchievementFrame_SetFilter(ACHIEVEMENT_FILTER_ALL);
	elseif ( (not achCompleted) and (ACHIEVEMENTUI_SELECTEDFILTER == AchievementFrameFilters[ACHIEVEMENT_FILTER_COMPLETE].func) ) then
		AchievementFrame_SetFilter(ACHIEVEMENT_FILTER_ALL);
	end

	AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;
	AchievementFrameTab_OnClick(1);
	AchievementFrameSummary:Hide();
	AchievementFrameAchievements:Show();

	-- Figure out if this is part of a progressive achievement; if it is and it's incomplete, make sure the previous level was completed. If not, find the first incomplete achievement in the chain and display that instead.
	local _, _, _, completed = GetAchievementInfo(id);
	if ( not completed and GetPreviousAchievement(id) ) then
		local prevID = GetPreviousAchievement(id);
		_, _, _, completed = GetAchievementInfo(prevID);
		while ( prevID and not completed ) do
			id = prevID;
			prevID = GetPreviousAchievement(id);
			if ( prevID ) then
				_, _, _, completed = GetAchievementInfo(prevID);
			end
		end
	elseif ( completed ) then
		local nextID, completed = GetNextAchievement(id);
		if ( nextID and completed ) then
			local newID
			while ( nextID and completed ) do
				newID, completed = GetNextAchievement(nextID);
				if ( completed ) then
					nextID = newID;
				end
			end
			id = nextID;
		end
	end

	AchievementFrameCategories_ClearSelection();
	local category = GetAchievementCategory(id);

	local categoryIndex, parent, hidden = 0;
	for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
		if ( entry.id == category ) then
			parent = entry.parent;
		end
	end

	for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
		if ( entry.id == parent ) then
			entry.collapsed = false;
		elseif ( entry.parent == parent ) then
			entry.hidden = false;
		elseif ( entry.parent == true ) then
			entry.collapsed = true;
		elseif ( entry.parent ) then
			entry.hidden = true;
		end
	end

	local selectedCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		ACHIEVEMENT_FUNCTIONS.selectedCategory = category;
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		STAT_FUNCTIONS.selectedCategory = category;
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory = category;
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		COMPARISON_STAT_FUNCTIONS.selectedCategory = category;
	end
	AchievementFrameCategoriesContainerScrollBar:SetValue(0);
	AchievementFrameCategories_Update();

	local shown, i = false, 1;
	while ( not shown ) do
		for _, button in next, AchievementFrameCategoriesContainer.buttons do
			if ( button.categoryID == category and math.ceil(button:GetBottom()) >= math.ceil(AchievementFrameAchievementsContainer:GetBottom())) then
				shown = true;
			end
		end

		if ( not shown ) then
			local _, maxVal = AchievementFrameCategoriesContainerScrollBar:GetMinMaxValues();
			if ( AchievementFrameCategoriesContainerScrollBar:GetValue() == maxVal ) then
				--assert(false)
				return;
			else
				HybridScrollFrame_OnMouseWheel(AchievementFrameCategoriesContainer, -1);
			end
		end

		-- Remove me if everything's working fine
		i = i + 1;
		if ( i > 100 ) then
			--assert(false);
			return;
		end
	end

	AchievementFrameAchievements_ClearSelection();
	AchievementFrameAchievementsContainerScrollBar:SetValue(0);
	AchievementFrameAchievements_Update();

	local shown = false;
	while ( not shown ) do
		for _, button in next, AchievementFrameAchievementsContainer.buttons do
			if ( button.id == id and math.ceil(button:GetTop()) >= math.ceil(AchievementFrameAchievementsContainer:GetBottom())) then
				-- The "True" here ignores modifiers, so you don't accidentally track or link this achievement. :P
				AchievementButton_OnClick(button, true);

				-- We found the button!
				shown = button;
				break;
			end
		end

		local _, maxVal = AchievementFrameAchievementsContainerScrollBar:GetMinMaxValues();
		if ( shown ) then
			-- If we can, move the achievement we're scrolling to to the top of the screen.
			local newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - shown:GetTop();
			newHeight = min(newHeight, maxVal);
			AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
		else
			if ( AchievementFrameAchievementsContainerScrollBar:GetValue() == maxVal ) then
				--assert(false, "Failed to find achievement " .. id .. " while jumping!")
				return;
			else
				HybridScrollFrame_OnMouseWheel(AchievementFrameAchievementsContainer, -1);
			end
		end
	end
end

function AchievementFrameAchievements_FindSelection()
	local _, maxVal = AchievementFrameAchievementsContainerScrollBar:GetMinMaxValues();
	local scrollHeight = AchievementFrameAchievementsContainer:GetHeight();
	local newHeight = 0;
	AchievementFrameAchievementsContainerScrollBar:SetValue(0);
	while ( not shown ) do
		for _, button in next, AchievementFrameAchievementsContainer.buttons do
			if ( button.selected ) then
				newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - button:GetTop();
				newHeight = min(newHeight, maxVal);
				AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
				return;
			end
		end
		if ( AchievementFrameAchievementsContainerScrollBar:GetValue() == maxVal ) then
			return;
		else
			newHeight = newHeight + scrollHeight;
			newHeight = min(newHeight, maxVal);
			AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
		end
	end
end

function AchievementFrameAchievements_AdjustSelection()
	local selectedButton;
	-- check if selection is visible
	for _, button in next, AchievementFrameAchievementsContainer.buttons do
		if ( button.selected ) then
			selectedButton = button;
			break;
		end
	end

	if ( not selectedButton ) then
		AchievementFrameAchievements_FindSelection();
	else
		local newHeight;
		if ( selectedButton:GetTop() > AchievementFrameAchievementsContainer:GetTop() ) then
			newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - selectedButton:GetTop();
		elseif ( selectedButton:GetBottom() < AchievementFrameAchievementsContainer:GetBottom() ) then
			if ( selectedButton:GetHeight() > AchievementFrameAchievementsContainer:GetHeight() ) then
				newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - selectedButton:GetTop();
			else
				newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetBottom() - selectedButton:GetBottom();
			end
		end
		if ( newHeight ) then
			local _, maxVal = AchievementFrameAchievementsContainerScrollBar:GetMinMaxValues();
			newHeight = min(newHeight, maxVal);
			AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
		end
	end
end

function AchievementFrame_SelectSummaryStatistic (criteriaId)
	debug('AchievementFrame_SelectSummaryStatistic WE R IN BUSINESS')
	AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;
	AchievementFrameTab_OnClick(2);
	AchievementFrameStats:Show();
	AchievementFrameSummary:Hide();

	AchievementFrameCategories_ClearSelection();

	local id = GetAchievementInfoFromCriteria(criteriaId);
	local category = GetAchievementCategory(id);

	local categoryIndex, parent, hidden = 0;

	local categoryIndex, parent, hidden = 0;
	for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
		if ( entry.id == category ) then
			parent = entry.parent;
		end
	end

	for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
		if ( entry.id == parent ) then
			entry.collapsed = false;
		elseif ( entry.parent == parent ) then
			entry.hidden = false;
		elseif ( entry.parent == true ) then
			entry.collapsed = true;
		elseif ( entry.parent ) then
			entry.hidden = true;
		end
	end

	local selectedCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		ACHIEVEMENT_FUNCTIONS.selectedCategory = category;
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		STAT_FUNCTIONS.selectedCategory = category;
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory = category;
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		COMPARISON_STAT_FUNCTIONS.selectedCategory = category;
	end
	AchievementFrameCategories_Update();
	AchievementFrameCategoriesContainerScrollBar:SetValue(0);

	local shown, i = false, 1;
	while ( not shown ) do
		for _, button in next, AchievementFrameCategoriesContainer.buttons do
			if ( button.categoryID == category and math.ceil(button:GetBottom()) >= math.ceil(AchievementFrameAchievementsContainer:GetBottom())) then
				shown = true;
			end
		end

		if ( not shown ) then
			local _, maxVal = AchievementFrameCategoriesContainerScrollBar:GetMinMaxValues();
			if ( AchievementFrameCategoriesContainerScrollBar:GetValue() == maxVal ) then
				assert(false)
			else
				HybridScrollFrame_OnMouseWheel(AchievementFrameCategoriesContainer, -1);
			end
		end

		-- Remove me if everything's working fine
		i = i + 1;
		if ( i > 100 ) then
			assert(false);
		end
	end

	AchievementFrameStats_Update();
	AchievementFrameStatsContainerScrollBar:SetValue(0);

	local shown, i = false, 1;
	while ( not shown ) do
		for _, button in next, AchievementFrameStatsContainer.buttons do
			if ( button.id == id and math.ceil(button:GetBottom()) >= math.ceil(AchievementFrameStatsContainer:GetBottom())) then
				AchievementStatButton_OnClick(button);

				-- We found the button! MAKE IT SHOWN ZOMG!
				shown = button;
			end
		end

		if ( shown and AchievementFrameStatsContainerScrollBar:IsShown() ) then
			-- If we can, move the achievement we're scrolling to to the top of the screen.
			AchievementFrameStatsContainerScrollBar:SetValue(AchievementFrameStatsContainerScrollBar:GetValue() + AchievementFrameStatsContainer:GetTop() - shown:GetTop());
		elseif ( not shown ) then
			local _, maxVal = AchievementFrameStatsContainerScrollBar:GetMinMaxValues();
			if ( AchievementFrameStatsContainerScrollBar:GetValue() == maxVal ) then
				assert(false)
			else
				HybridScrollFrame_OnMouseWheel(AchievementFrameStatsContainer, -1);
			end
		end

		-- Remove me if everything's working fine.
		i = i + 1;
		if ( i > 100 ) then
			assert(false);
		end
	end
end

function AchievementFrameComparison_OnLoad (self)
	AchievementFrameComparisonContainer_OnLoad(self);
	AchievementFrameComparisonStatsContainer_OnLoad(self);
	self:RegisterEvent("ACHIEVEMENT_EARNED");
	self:RegisterEvent("INSPECT_ACHIEVEMENT_READY");
end

function AchievementFrameComparisonContainer_OnLoad (parent)
	AchievementFrameComparisonContainerScrollBar.OriginalShow = AchievementFrameComparisonContainerScrollBar.Show
	AchievementFrameComparisonContainerScrollBar.Show =
		function (self)
			AchievementFrameComparison:SetWidth(626);
			AchievementFrameComparisonSummaryPlayer:SetWidth(498);
			for _, button in next, AchievementFrameComparisonContainer.buttons do
				button:SetWidth(616);
				button.player:SetWidth(498);
			end
			self:OriginalShow(self)
			-- getmetatable(self).__index.Show(self);
		end

	AchievementFrameComparisonContainerScrollBar.OriginalShow = AchievementFrameComparisonContainerScrollBar.Hide
	AchievementFrameComparisonContainerScrollBar.Hide =
		function (self)
			AchievementFrameComparison:SetWidth(650);
			AchievementFrameComparisonSummaryPlayer:SetWidth(522);
			for _, button in next, AchievementFrameComparisonContainer.buttons do
				button:SetWidth(640);
				button.player:SetWidth(522);
			end
			self:OriginalHide(self)
			-- getmetatable(self).__index.Hide(self);
		end

	AchievementFrameComparisonContainerScrollBarBG:Show();
	AchievementFrameComparisonContainer.update = AchievementFrameComparison_Update;
	HybridScrollFrame_CreateButtons(AchievementFrameComparisonContainer, "ComparisonTemplate", 0, -2);
end

function AchievementFrameComparisonStatsContainer_OnLoad (parent)
	AchievementFrameComparisonStatsContainerScrollBar.OriginalShow = AchievementFrameComparisonContainerScrollBar.Show
	AchievementFrameComparisonStatsContainerScrollBar.Show =
		function (self)
			AchievementFrameComparison:SetWidth(626);
			for _, button in next, AchievementFrameComparisonStatsContainer.buttons do
				button:SetWidth(616);
			end
			self:OriginalShow(self)
			-- getmetatable(self).__index.Show(self);
		end

	AchievementFrameComparisonStatsContainerScrollBar.OriginalShow = AchievementFrameComparisonContainerScrollBar.Hide
	AchievementFrameComparisonStatsContainerScrollBar.Hide =
		function (self)
			AchievementFrameComparison:SetWidth(650);
			for _, button in next, AchievementFrameComparisonStatsContainer.buttons do
				button:SetWidth(640);
			end
			self:OriginalHide(self)
			-- getmetatable(self).__index.Hide(self);
		end

	AchievementFrameComparisonStatsContainerScrollBarBG:Show();
	AchievementFrameComparisonStatsContainer.update = AchievementFrameComparison_UpdateStats;
	HybridScrollFrame_CreateButtons(AchievementFrameComparisonStatsContainer, "ComparisonStatTemplate", 0, -2);
end

function AchievementFrameComparison_OnShow ()
	AchievementFrameStats:Hide();
	AchievementFrameAchievements:Hide();
	AchievementFrame:SetWidth(890);
	AchievementFrame:SetAttribute("UIPanelLayout-xOffset", 38);
	UpdateUIPanelPositions(AchievementFrame);
	AchievementFrame.isComparison = true;
end

function AchievementFrameComparison_OnHide ()
	AchievementFrame.selectedTab = nil;
	AchievementFrame:SetWidth(768);
	AchievementFrame:SetAttribute("UIPanelLayout-xOffset", 80);
	UpdateUIPanelPositions(AchievementFrame);
	AchievementFrame.isComparison = false;
	ClearAchievementComparisonUnit();
end

function AchievementFrameComparison_OnEvent (self, event, ...)
	warn('investigate xml AchievementFrameComparison_OnEvent ' .. event)
	if ( event == "INSPECT_ACHIEVEMENT_READY" ) then
		AchievementFrameComparisonHeaderPoints:SetText(GetComparisonAchievementPoints());
		local selectedCategory;
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
			selectedCategory = ACHIEVEMENT_FUNCTIONS.selectedCategory
		elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
			selectedCategory = STAT_FUNCTIONS.selectedCategory
		elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			selectedCategory = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
		elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
			selectedCategory = COMPARISON_STAT_FUNCTIONS.selectedCategory
		end
		AchievementFrameComparison_UpdateStatusBars(selectedCategory)
	elseif ( event == "UNIT_PORTRAIT_UPDATE" ) then
		local updateUnit = arg;
		if ( updateUnit and updateUnit == AchievementFrameComparisonHeaderPortrait.unit and UnitName(updateUnit) == AchievementFrameComparisonHeaderName:GetText() ) then
			SetPortraitTexture(AchievementFrameComparisonHeaderPortrait, updateUnit);
		end
	end

	AchievementFrameComparison_ForceUpdate();
end

function AchievementFrameComparison_SetUnit (unit)
	ClearAchievementComparisonUnit();
	SetAchievementComparisonUnit(unit);

	AchievementFrameComparisonHeaderPoints:SetText(GetComparisonAchievementPoints());
	AchievementFrameComparisonHeaderName:SetText(UnitName(unit));
	SetPortraitTexture(AchievementFrameComparisonHeaderPortrait, unit);
	AchievementFrameComparisonHeaderPortrait.unit = unit;
	AchievementFrameComparisonHeaderPortrait.race = UnitRace(unit);
	AchievementFrameComparisonHeaderPortrait.sex = UnitSex(unit);
end

function AchievementFrameComparison_ClearSelection ()
	-- Doesn't do anything WHEE~!
end

function AchievementFrameComparison_ForceUpdate ()
	if ( USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS' ) then
		local buttons = AchievementFrameComparisonContainer.buttons;
		for i, button in next, buttons do
			button.id = nil;
		end

		AchievementFrameComparison_Update();
	elseif ( USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS' ) then
		AchievementFrameComparison_UpdateStats();
	end
end

function AchievementFrameComparison_Update ()
	local category;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		category = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		category = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		category = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		category = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	if ( not category or category == "summary" ) then
		return;
	end
	local scrollFrame = AchievementFrameComparisonContainer

	local offset = HybridScrollFrame_GetOffset(scrollFrame);
	local buttons = scrollFrame.buttons;
	local numAchievements, numCompleted = GetCategoryNumAchievements(category);
	local numButtons = table.getn(buttons); -- #buttons;

	local achievementIndex;
	local buttonHeight = buttons[1]:GetHeight();
	for i = 1, numButtons do
		achievementIndex = i + offset;
		AchievementFrameComparison_DisplayAchievement(buttons[i], category, achievementIndex);
	end

	HybridScrollFrame_Update(scrollFrame, buttonHeight*numAchievements, buttonHeight*numButtons);
end

ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT1 = GameFontNormal;
ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT2 = GameFontNormalSmall;
ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT1 = GameFontNormalSmall;
ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT2 = GameFontNormalSmall;

function AchievementFrameComparison_DisplayAchievement (button, category, index)
	local id, name, points, completed, month, day, year, description, flags, icon, rewardText = GetAchievementInfo(category, index);
	if ( not id ) then
		button:Hide();
		return;
	else
		button:Show();
	end

	if ( GetPreviousAchievement(id) ) then
		-- If this is a progressive achievement, show the total score.
		points = AchievementButton_GetProgressivePoints(id);
	end

	if ( button.id ~= id ) then
		button.id = id;

		local player = button.player;
		local friend = button.friend;

		local friendCompleted, friendMonth, friendDay, friendYear = GetAchievementComparisonInfo(id);
		player.label:SetText(name);

		player.description:SetText(description);

		if (icon) then
			local iconFromTable = iconTable[icon]
			if (iconFromTable) then
				player.icon.texture:SetTexture(iconFromTable);
				player.icon.texture:SetTexture([[Interface\AddOns\Achiever\textures\]] .. iconFromTable);
				friend.icon.texture:SetTexture(iconFromTable);
				friend.icon.texture:SetTexture([[Interface\AddOns\Achiever\textures\]] .. iconFromTable);
			end
		end


		if ( points > 0 ) then
			player.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields]]);
			friend.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields]]);
		else
			player.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields-NoPoints]]);
			friend.shield.icon:SetTexture([[Interface\AddOns\Achiever\textures\UI-Achievement-Shields-NoPoints]]);
		end
		AchievementShield_SetPoints(points, player.shield.points, ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT1, ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT2);
		AchievementShield_SetPoints(points, friend.shield.points, ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT1, ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT2);

		if ( completed and not player.completed ) then
			player.completed = true;
			player.dateCompleted:SetText(string.format('%d/%d/%d', day, month, year));
			player.dateCompleted:Show();
			player:Saturate();
		elseif ( completed ) then
			player.dateCompleted:SetText(string.format('%d/%d/%d', day, month, year));
		else
			player.completed = nil;
			player.dateCompleted:Hide();
			player:Desaturate();
		end

		if ( friendCompleted and not friend.completed ) then
			friend.completed = true;
			friend.status:SetText(string.format('%d/%d/%d', friendDay, friendMonth, friendYear));
			friend:Saturate();
		elseif ( friendCompleted ) then
			friend.status:SetText(string.format('%d/%d/%d', friendDay, friendMonth, friendYear));
		else
			friend.completed = nil;
			friend.status:SetText(INCOMPLETE);
			friend:Desaturate();
		end
	end
end


function AchievementFrameComparison_UpdateStats ()
	local category;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		category = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		category = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		category = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		category = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	local scrollFrame = AchievementFrameComparisonStatsContainer;
	local offset = HybridScrollFrame_GetOffset(scrollFrame);
	local buttons = scrollFrame.buttons;
	local numButtons = table.getn(buttonss); -- #buttons;
	local headerHeight = 24;
	local statHeight = 24;
	local totalHeight = 0;
	local numStats, numCompleted = GetCategoryNumAchievements(category);

	local categories = ACHIEVEMENTUI_CATEGORIES;
	-- clear out table
	local lastCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		lastCategory = ACHIEVEMENT_FUNCTIONS.lastCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		lastCategory = STAT_FUNCTIONS.lastCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		lastCategory = COMPARISON_ACHIEVEMENT_FUNCTIONS.lastCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		lastCategory = COMPARISON_STAT_FUNCTIONS.lastCategory
	end
	if ( lastCategory ~= category ) then
		local statCat;
		for i in next, displayStatCategories do
			displayStatCategories[i] = nil;
		end
		-- build a list of shown category and stat id's

		tinsert(displayStatCategories, {id = category, header = true});
		totalHeight = totalHeight+headerHeight;


		for i=1, numStats do
			tinsert(displayStatCategories, {id = GetAchievementInfo(category, i)});
			totalHeight = totalHeight+statHeight;
		end
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
			ACHIEVEMENT_FUNCTIONS.lastCategory = category;
			ACHIEVEMENT_FUNCTIONS.lastHeight = totalHeight;
		elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
			STAT_FUNCTIONS.lastCategory = category;
			STAT_FUNCTIONS.lastHeight = totalHeight;
		elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			COMPARISON_ACHIEVEMENT_FUNCTIONS.lastCategory = category;
			COMPARISON_ACHIEVEMENT_FUNCTIONS.lastHeight = totalHeight;
		elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
			COMPARISON_STAT_FUNCTIONS.lastCategory = category;
			COMPARISON_STAT_FUNCTIONS.lastHeight = totalHeight;
		end
	else
		if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
			totalHeight = ACHIEVEMENT_FUNCTIONS.lastHeight
		elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
			totalHeight = STAT_FUNCTIONS.lastHeight
		elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
			totalHeight = COMPARISON_ACHIEVEMENT_FUNCTIONS.lastHeight
		elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
			totalHeight = COMPARISON_STAT_FUNCTIONS.lastHeight
		end
	end

	-- add all the subcategories and their stat id's
	for i, cat in next, categories do
		if ( cat.parent == category ) then
			tinsert(displayStatCategories, {id = cat.id, header = true});
			totalHeight = totalHeight+headerHeight;
			numStats = GetCategoryNumAchievements(cat.id);
			for k=1, numStats do
				tinsert(displayStatCategories, {id = GetAchievementInfo(cat.id, k)});
				totalHeight = totalHeight+statHeight;
			end
		end
	end

	-- iterate through the displayStatCategories and display them
	local statCount = table.getn(displayStatCategories); -- #displayStatCategories;
	local statIndex, id, button;
	local stat;
	local displayedHeight = 0;
	for i = 1, numButtons do
		button = buttons[i];
		statIndex = offset + i;
		if ( statIndex <= statCount ) then
			stat = displayStatCategories[statIndex];
			if ( stat.header ) then
				AchievementFrameComparisonStats_SetHeader(button, stat.id);
			else
				AchievementFrameComparisonStats_SetStat(button, stat.id, nil, statIndex);
			end
			button:Show();
		else
			button:Hide();
		end
		displayedHeight = displayedHeight+button:GetHeight();
	end
	HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);
end

function AchievementFrameComparisonStat_OnLoad (self)
	local name = self:GetName();
	self.background = _G[name.."BG"];
	self.left = _G[name.."HeaderLeft"];
	self.middle = _G[name.."HeaderMiddle"];
	self.right = _G[name.."HeaderRight"];
	self.left2 = _G[name.."HeaderLeft2"];
	self.middle2 = _G[name.."HeaderMiddle2"];
	self.right2 = _G[name.."HeaderRight2"];
	self.text = _G[name.."Text"];
	self.title = _G[name.."Title"];
	self.value = _G[name.."Value"];
	self.value:SetVertexColor(1, 0.97, 0.6);
	self.friendValue = _G[name.."ComparisonValue"];
	self.friendValue:SetVertexColor(1, 0.97, 0.6);
	self.mouseover = _G[name.. "Mouseover"];
end

function AchievementFrameComparisonStats_SetStat (button, category, index, colorIndex, isSummary)
--Remove these variables when we know for sure we don't need them
	local id, name, points, completed, month, day, year, description, flags, icon;
	if ( not isSummary ) then
		if ( not index ) then
			id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category);
		else
			id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category, index);
		end

	else
		-- This is on the summary page
		id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfoFromCriteria(category);
	end

	button.id = id;

	if ( not colorIndex ) then
		if ( not index ) then
			message("Error, need a color index or index");
		end
		colorIndex = index;
	end

	button.background:Show();
	-- Color every other line yellow
	if ( mod(colorIndex, 2) == 1 ) then
		button.background:SetTexCoord(0, 1, 0.1875, 0.3671875);
		button.background:SetBlendMode("BLEND");
		button.background:SetAlpha(1.0);
		button:SetHeight(24);
	else
		button.background:SetTexCoord(0, 1, 0.375, 0.5390625);
		button.background:SetBlendMode("ADD");
		button.background:SetAlpha(0.5);
		button:SetHeight(24);
	end

	-- Figure out the criteria
	local numCriteria = GetAchievementNumCriteria(id);
	if ( numCriteria == 0 ) then
		-- This is no good!
	end
	-- Just show the first criteria for now
	local criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity, friendQuantity;
	if ( not isSummary ) then
		friendQuantity = GetComparisonStatistic(id);
		quantity = GetStatistic(id);
	else
		criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity = GetAchievementCriteriaInfo(category);
	end
	if ( not quantity ) then
		quantity = "--";
	end
	if ( not friendQuantity ) then
		friendQuantity = "--";
	end

	button.value:SetText(quantity);

	-- We're gonna use button.text here to measure string width for friendQuantity. This saves us many strings!
	button.text:SetText(friendQuantity);
	local width = button.text:GetStringWidth();
	if ( width > button.friendValue:GetWidth() ) then
		button.friendValue:SetFontObject("AchievementFont_Small");
		button.mouseover:Show();
		button.mouseover.tooltip = friendQuantity;
	else
		button.friendValue:SetFontObject("GameFontHighlightRight");
		button.mouseover:Hide();
		button.mouseover.tooltip = nil;
	end

	button.text:SetText(name);
	button.friendValue:SetText(friendQuantity);


	-- Hide the header images
	button.title:Hide();
	button.left:Hide();
	button.middle:Hide();
	button.right:Hide();
	button.left2:Hide();
	button.middle2:Hide();
	button.right2:Hide();
	button.isHeader = false;
end

function AchievementFrameComparisonStats_SetHeader(button, id)
	-- show header
	button.left:Show();
	button.middle:Show();
	button.right:Show();
	button.left2:Show();
	button.middle2:Show();
	button.right2:Show();
	button.title:SetText(GetCategoryInfo(id));
	button.title:Show();
	button.friendValue:SetText("");
	button.value:SetText("");
	button.text:SetText("");
	button:SetHeight(24);
	button.background:Hide();
	button.isHeader = true;
	button.id = id;
end

function AchievementComparisonPlayerButton_Saturate (self)
	local name = self:GetName();
	_G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0, 0.3125);
	_G[name .. "Background"]:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Parchment-Horizontal");
	_G[name .. "Glow"]:SetVertexColor(1.0, 1.0, 1.0);
	self.icon:Saturate();
	self.shield:Saturate();
	self.shield.points:SetVertexColor(1, 1, 1);
	self.label:SetVertexColor(1, 1, 1);
	self.description:SetTextColor(0, 0, 0, 1);
	self.description:SetShadowOffset(0, 0);
	self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
end

function AchievementComparisonPlayerButton_Desaturate (self)
	local name = self:GetName();
	_G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0.34375, 0.65625);
	_G[name .. "Background"]:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Parchment-Horizontal-Desaturated");
	_G[name .. "Glow"]:SetVertexColor(.22, .17, .13);
	self.icon:Desaturate();
	self.shield:Desaturate();
	self.shield.points:SetVertexColor(.65, .65, .65);
	self.label:SetVertexColor(.65, .65, .65);
	self.description:SetTextColor(1, 1, 1, 1);
	self.description:SetShadowOffset(1, -1);
	self:SetBackdropBorderColor(.5, .5, .5);
end

function AchievementComparisonPlayerButton_OnLoad (self)
	local name = self:GetName();

	self.label = _G[name .. "Label"];
	self.description = _G[name .. "Description"];
	self.icon = _G[name .. "Icon"];
	self.shield = _G[name .. "Shield"];
	self.dateCompleted = _G[name .. "DateCompleted"];
	self.titleBar = _G[name .. "TitleBackground"];

	self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
	self.Saturate = AchievementComparisonPlayerButton_Saturate;
	self.Desaturate = AchievementComparisonPlayerButton_Desaturate;

	self:Desaturate();

	-- AchievementFrameComparison.buttons = AchievementFrameComparison.buttons or {};
	-- tinsert(AchievementFrameComparison.buttons, self);
end

function AchievementComparisonFriendButton_Saturate (self)
	local name = self:GetName();
	_G[name .. "TitleBackground"]:SetTexCoord(0.3, 0.575, 0, 0.3125);
	_G[name .. "Background"]:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Parchment-Horizontal");
	_G[name .. "Glow"]:SetVertexColor(1.0, 1.0, 1.0);
	self.icon:Saturate();
	self.shield:Saturate();
	self.shield.points:SetVertexColor(1, 1, 1);
	self.status:SetVertexColor(1, .82, 0);
	self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
end

function AchievementComparisonFriendButton_Desaturate (self)
	local name = self:GetName();
	_G[name .. "TitleBackground"]:SetTexCoord(0.3, 0.575, 0.34375, 0.65625);
	_G[name .. "Background"]:SetTexture("Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Parchment-Horizontal-Desaturated");
	_G[name .. "Glow"]:SetVertexColor(.22, .17, .13);
	self.icon:Desaturate();
	self.shield:Desaturate();
	self.shield.points:SetVertexColor(.65, .65, .65);
	self.status:SetVertexColor(.65, .65, .65);
	self:SetBackdropBorderColor(.5, .5, .5);
end

function AchievementComparisonFriendButton_OnLoad (self)
	local name = self:GetName();

	self.status = _G[name .. "Status"];
	self.icon = _G[name .. "Icon"];
	self.shield = _G[name .. "Shield"];

	self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
	self.Saturate = AchievementComparisonFriendButton_Saturate;
	self.Desaturate = AchievementComparisonFriendButton_Desaturate;

	self:Desaturate();
end

function AchievementFrame_IsComparison()
	return AchievementFrame.isComparison;
end

function AchievementFrame_IsFeatOfStrength()
	local displayCategoriesCount = getn(displayCategories)
	local selectedCategory;
	if (USE_FUNCTIONS == 'ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'STAT_FUNCTIONS') then
		selectedCategory = STAT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_ACHIEVEMENT_FUNCTIONS') then
		selectedCategory = COMPARISON_ACHIEVEMENT_FUNCTIONS.selectedCategory
	elseif (USE_FUNCTIONS == 'COMPARISON_STAT_FUNCTIONS') then
		selectedCategory = COMPARISON_STAT_FUNCTIONS.selectedCategory
	end
	if ( AchievementFrame.selectedTab == 1 and selectedCategory == displayCategories[displayCategoriesCount].id ) then
		return true;
	end
	return false;
end



ACHIEVEMENT_TEXTURES_TO_LOAD = {
	{
		name="AchievementFrameAchievementsBackground",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-AchievementBackground",
	},
	{
		name="AchievementFrameSummaryBackground",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-AchievementBackground",
	},
	{
		name="AchievementFrameComparisonBackground",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-AchievementBackground",
	},
	{
		name="AchievementFrameCategoriesBG",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-AchievementBackground",
	},
	{
		name="AchievementFrameWaterMark",
	},
	{
		name="AchievementFrameHeaderLeft",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Header",
	},
	{
		name="AchievementFrameHeaderRight",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Header",
	},
	{
		name="AchievementFrameHeaderPointBorder",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-Header",
	},
	{
		name="AchievementFrameComparisonWatermark",
		file="Interface\\AddOns\\Achiever\\textures\\UI-Achievement-StatsComparisonBackground",
	},
}

function AchievementFrame_ClearTextures()
	for k, v in pairs(ACHIEVEMENT_TEXTURES_TO_LOAD) do
		_G[v.name]:SetTexture(nil);
	end
end

function AchievementFrame_LoadTextures()
	for k, v in pairs(ACHIEVEMENT_TEXTURES_TO_LOAD) do
		if ( v.file ) then
			_G[v.name]:SetTexture(v.file);
		end
	end
end