--[[
	### Rev 04 ###
	- Dropdowns can now overwrite the label in their init and selectvalue funcs.
	- Empty menus now show "No items".
	### Rev 05 ###
	- A menu entry now supports a .tip key, and will show a tooltip if it's a string.
	- The SelectValueFunc() now has a third parameter, the menu item index that was clicked.
	- The checkmark texture is now the green one used for readychecks in the raid tab.
	- Will now obey the .checked key if set, not only when it's true.
	- The autoselect feature of the last selected value, will not just select everything when nil.
	- The InitSelectedItem() function will not ignore an initialisation with nil anymore.
	### Rev 06 ###
	- The "menu.list" table now has a meta table which will automatically create a table or take one from storage.
	- If tables are creates through the new metatable index method, it will recycle old tables from storage.
	### Rev 07 ###
	- The menu will now hide itself, if any of it's parents was hidden.
--]]

local REVISION = 7;
if (type(AzDropDown) == "table") and (AzDropDown.vers >= REVISION) then
	return;
end

AzDropDown = AzDropDown or {};
AzDropDown.vers = REVISION;

local menu;
local measure;
local menuMaxItems = 15;
local menuItemHeight = 14;
local backDrop = { bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 14, insets = { left = 2.5, right = 2.5, top = 2.5, bottom = 2.5 } };
local storage = {};

--------------------------------------------------------------------------------------------------------
--                                          Menu Functions                                            --
--------------------------------------------------------------------------------------------------------

-- MenuItem OnClick
local function MenuItem_OnClick(self,button)
	local table = menu.list[self.index];
	local parent = menu.parent;
	if (parent.isAutoSelect) then
		parent.label:SetText(table.text);
		parent.SelectedValue = table.value;
	end
	menu.SelectValueFunc(parent,table,self.index);
	menu:Hide();
end

-- MenuItem OnEnter
local function MenuItem_OnEnter(self)
	local entry = menu.list[self.index];
	if (type(entry.tip) == "string") then
		GameTooltip_SetDefaultAnchor(GameTooltip,self);
		GameTooltip:AddLine(entry.text,1,1,1);
		GameTooltip:AddLine(entry.tip,nil,nil,nil,1);
		GameTooltip:Show();
	end
end

-- HideGTT
local function HideGTT()
	GameTooltip:Hide();
end

-- Make Menu Item
local function CreateMenuItem()
	local item = CreateFrame("Button",nil,menu);
	item:SetHeight(menuItemHeight);
	item:SetHitRectInsets(-12,-10,0,0);
	item:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight");
	item:SetScript("OnClick",MenuItem_OnClick);
	item:SetScript("OnEnter",MenuItem_OnEnter);
	item:SetScript("OnLeave",HideGTT);

	item.text = item:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall");
	item.text:SetPoint("LEFT",2,0);

	item.check = item:CreateTexture(nil,"ARTWORK");
	item.check:SetTexture(READY_CHECK_READY_TEXTURE);
	item.check:SetWidth(14);
	item.check:SetHeight(14);
	item.check:SetPoint("RIGHT",item,"LEFT");
	item.check:Hide();

	if (#menu.items == 0) then
		item:SetPoint("TOPLEFT",20,-8);
		menu.scroll:SetPoint("TOPLEFT",item);
	else
		item:SetPoint("TOPLEFT",menu.items[#menu.items],"BOTTOMLEFT");
		item:SetPoint("TOPRIGHT",menu.items[#menu.items],"BOTTOMRIGHT");
		menu.scroll:SetPoint("BOTTOMRIGHT",item);
	end

	menu.items[#menu.items + 1] = item;
	return item;
end

-- UpdateList
local function Menu_UpdateList()
	FauxScrollFrame_Update(menu.scroll,#menu.list,menuMaxItems,menuItemHeight);
	local item, entry;
	local index = menu.scroll.offset;
	-- Loop
	for i = 1, menuMaxItems do
		index = (index + 1);
		item = menu.items[i] or CreateMenuItem();
		if (index <= #menu.list) then
			entry = menu.list[index];
			item.text:SetText(entry.text);
			item.index = index;
			item.text:SetTextColor(1,entry.header and 0.82 or 1,entry.header and 0 or 1);
			if (entry.header) then
				item:Disable();
			else
				item:Enable();
			end
			if (entry.checked) or (entry.checked == nil and menu.parent.isAutoSelect and entry.value ~= nil and entry.value == menu.parent.SelectedValue) then
				item.check:Show();
			else
				item.check:Hide();
			end
			item:Show();
		else
			item:Hide();
		end
	end
end

-- Create Menu
local function CreateMenu()
	menu = CreateFrame("Frame",nil,nil);
	menu:SetBackdrop(backDrop);
	menu:SetBackdropColor(0.1,0.1,0.1,1);
	menu:SetBackdropBorderColor(0.4,0.4,0.4,1);
	menu:SetToplevel(1);
	menu:SetClampedToScreen(1);
	menu:SetFrameStrata("FULLSCREEN_DIALOG");
	menu:SetScript("OnHide",function(self) if (self:IsShown()) then self:Hide(); end end);
	menu:Hide();
	
	measure = menu:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall");
	measure:Hide();

	menu.scroll = CreateFrame("ScrollFrame","AzDropDownScroll"..REVISION,menu,"FauxScrollFrameTemplate");
	menu.scroll:SetScript("OnVerticalScroll",function(self,offset) FauxScrollFrame_OnVerticalScroll(self,offset,menuItemHeight,Menu_UpdateList); end);

	menu.items = {};
	menu.list = setmetatable({},{ __index = function(t,k) t[k] = #storage > 0 and tremove(storage,#storage) or {}; return t[k]; end });
end

-- InitList
local function InitMenu(parent,initFunc,selectValueFunc,point,parentPoint)
	if (not initFunc) then
		return;
	end
	-- Set DropDown Parent
	menu.parent = parent;
	menu:SetParent(parent);
	-- Anchor to Parent
	menu:ClearAllPoints();
	menu:SetPoint(point or "TOPRIGHT",parent,parentPoint or "BOTTOMRIGHT");
	-- Clear Old List & Init the New
	for index, tbl in ipairs(menu.list) do
		wipe(tbl);
		storage[#storage + 1] = tbl;
	end
	wipe(menu.list);
	menu.SelectValueFunc = selectValueFunc;
	menu.InitFunc = initFunc;
	initFunc(parent,menu.list);
	-- Show "No items" for empty lists & Update List
	if (#menu.list == 0) then
		menu.list[1].text = "No items"; menu.list[1].header = 1;
	end
	Menu_UpdateList();
	-- Set Width
	local maxItemWidth = 0;
	for _, table in ipairs(menu.list) do
		measure:SetText(table.text);
		maxItemWidth = max(maxItemWidth,measure:GetWidth() + 10);
	end
	if (#menu.list > menuMaxItems) then
		maxItemWidth = (maxItemWidth + 12);
		menu.items[1]:SetPoint("TOPRIGHT",-28,-8);
	else
		menu.items[1]:SetPoint("TOPRIGHT",-16,-8);
	end
	menu:SetWidth(maxItemWidth + 38);
	menu:SetHeight(min(#menu.list,menuMaxItems) * menuItemHeight + 16);
end

--------------------------------------------------------------------------------------------------------
--                                        Drop Down Functions                                         --
--------------------------------------------------------------------------------------------------------

-- DropDown OnClick
local function DropDown_OnClick(self,button)
	local parent = self:GetParent();
	AzDropDown.ToggleMenu(parent,parent.InitFunc,parent.SelectValueFunc);
end

-- Init Selected DropDown Item
local function DropDown_InitSelectedItem(self,selectedValue)
	if (not menu) then
		CreateMenu();
	end
	self.label:SetText("|cff00ff00Select Value...");
	InitMenu(self,self.InitFunc,self.SelectValueFunc);
	self.SelectedValue = selectedValue;
	for _, table in ipairs(menu.list) do
		if (table.value == self.SelectedValue) then
			self.label:SetText(table.text);
			return;
		end
	end
end

--------------------------------------------------------------------------------------------------------
--                                        "Exported" Functions                                        --
--------------------------------------------------------------------------------------------------------

-- ToggleMenu
function AzDropDown.HideMenu()
	if (menu) then
		menu:Hide();
	end
end

-- ToggleMenu
function AzDropDown.ToggleMenu(parent,initFunc,selectValueFunc,point,parentPoint)
	if (not parent or not initFunc or not selectValueFunc) then
		return;
	end
	if (not menu) then
		CreateMenu();
	end
	PlaySound("igMainMenuOptionCheckBoxOn");
	if (menu:IsShown()) and (menu.parent == parent) then
		menu:Hide();
	else
		InitMenu(parent,initFunc,selectValueFunc,point,parentPoint);
		menu:Show();
	end
end

-- Create DropDown
function AzDropDown.CreateDropDown(parent,width,isAutoSelect,initFunc,selectValueFunc)
	if (not parent or not width) then
		return;
	end
	local f = CreateFrame("Frame",nil,parent);
	f:SetWidth(width);
	f:SetHeight(24);
	f:SetBackdrop(backDrop);
	f:SetBackdropColor(0.1,0.1,0.1,1);
	f:SetBackdropBorderColor(0.4,0.4,0.4,1);

	f.button = CreateFrame("Button",nil,f);
	f.button:SetPoint("TOPRIGHT");
	f.button:SetPoint("BOTTOMRIGHT");
	f.button:SetWidth(24);
	f.button:SetHitRectInsets(-1 * (width - f.button:GetWidth()),0,0,0);
	f.button:SetScript("OnClick",DropDown_OnClick);

	f.button:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up");
	f.button:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down");
	f.button:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled");
	f.button:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight");

	f.label = f:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall");
	f.label:SetPoint("RIGHT",f.button,"LEFT",-2,0);

	f.isAutoSelect = isAutoSelect;

	f.InitFunc = initFunc;
	f.SelectValueFunc = selectValueFunc;
	f.InitSelectedItem = DropDown_InitSelectedItem;
	return f;
end