local _, env = ...;

---------------------------------------------------------------
-- Menu header secure code template
---------------------------------------------------------------
local ENV_DEFAULT = {
	_onload = [[
		hID = 1
		headers = newtable()
	]];
	_onshow = [[
		self:RunAttribute('SetHeader', hID)
		local showHeader = self:GetAttribute('ShowHeader')
		if showHeader then self:Run(showHeader, hID) end
	]];
	_onhide = [[
		for i, header in ipairs(headers) do
			self:RunAttribute('ClearHeader', i)
		end
	]];
	--------------------------------
	-- @param hID : header to set, identified by ID
	SetHeader = [[
		local header = headers[...]
		if not header then return end
		header:CallMethod('SetButtonState', 'PUSHED')
		header:CallMethod('LockHighlight')
		header:SetAttribute('nodepriority', 1)
		header:SetAttribute('focused', true)
		self:CallMethod('OnHeaderSet', header:GetName(), header:GetID())
	]];
	-- @param hID : header to clear, identified by ID
	ClearHeader = [[
		local header = headers[...]
		if not header then return end
		header:CallMethod('SetButtonState', 'NORMAL')
		header:CallMethod('UnlockHighlight')
		header:SetAttribute('nodepriority', 0)
		header:SetAttribute('focused', false)
		self:CallMethod('OnHeaderCleared', header:GetName(), header:GetID())
	]];
	-- @param hID : header to set, identified by ID
	ChangeHeader = [[
		local header = headers[...]
		if header and header:IsShown() then
			hID = ...;
			self:RunAttribute('_onhide')
			self:RunAttribute('_onshow')
		end
	]];
}
---------------------------------------------------------------
local Menu = {}; env.MenuMixin = Menu;
---------------------------------------------------------------

function Menu:StartEnvironment()
	for attribute, body in pairs(ENV_DEFAULT) do
		self:SetAttribute(attribute, body)
	end
	self:Execute(self:GetAttribute('_onload'))
	self.StartEnvironment = nil
end

---------------------------------------------------------------
-- @param config : table {
-- 	@param name : parentKey 
--	@param id   : (optional) numeric order ID
-- 	@param text : (optional) displayed on item
-- 	@param click : (optional) secure on click script
-- 	@param blueprint : (optional) children blueprint
--
-- 	@param type : (optional) frame type
--	@param templates : (optional) frame templates
--	@param redraw : (optional) redraw the menu
-- 	@param init   : (optional) init function
-- }
-- @return header : frame object
function Menu:AddHeader(config)
	local object = LibStub('Carpenter')(self, {
		[config.name] = {
			_ID = config.id or self:GetNumHeaders() + 1;
			_Type  = config.type or 'CheckButton';
			_Text  = config.text;
			_Setup = config.templates or {
				'SecureHandlerBaseTemplate';
				'SecureHandlerClickTemplate';
				'CPUIListCategoryTemplate';
			};
			_SetAttribute = {'_onclick', config.click};
			[1] = config.blueprint;
		};
	})
	if (type(config.init) == 'function') then
		config.init(object, self)
	end
	if config.redraw then
		self:DrawIndex()
	end
	return object;
end

function Menu:UpdateHeaderIndex(forceCount)
	self.headers = forceCount and {} or self.headers or {}
	if ( #self.headers < 1 or forceCount ) then
		self:SetAttribute('headerwidth', self:GetAttribute('indexwidth') or 0)
		for _, child in ipairs({self:GetChildren()}) do
			local id = child:GetID()
			if child:IsObjectType('CheckButton') and id > 0 then
				self.headers[id] = child
				local width = child:GetWidth()
				if width > self:GetAttribute('headerwidth') then
					self:SetAttribute('headerwidth', width)
				end
			end
		end
	end
	return self.headers
end

function Menu:GetMinHeaderWidth()
	return self:GetAttribute('headerwidth') or 0
end

function Menu:GetNumHeaders(forceCount)
	return #self:UpdateHeaderIndex(forceCount)
end

function Menu:IterateHeaders(forceCount)
	return ipairs(self:UpdateHeaderIndex(forceCount))
end

function Menu:DrawIndex(headerFunc)
	local numHeaders = self:GetNumHeaders(true)
	local headerWidth = self:GetMinHeaderWidth()
	local startingPoint = -((headerWidth*numHeaders)/2 - headerWidth/2)

	self:Execute(format('numheaders = %s', numHeaders))

	for id, header in self:IterateHeaders() do
		header:ClearAllPoints()
		header:SetPoint('CENTER', startingPoint + (headerWidth * (id-1)), 0)

		self:SetFrameRef('newheader', header)
		self:Execute([[
			local newheader = self:GetFrameRef('newheader')
			headers[newheader:GetID()] = newheader
		]])

		if ( type(headerFunc) == 'function' ) then
			headerFunc(header, self)
		end
	end
end

---------------------------------------------------------------
-- Secure environment script handling

function Menu:SetSecureScript(attribute, body, asPrefix, asSuffix)
	if asPrefix then self:PrependSecureScript(attribute, body)
	elseif asSuffix then self:AppendSecureScript(attribute, body)
	else self:SetAttribute(attribute, body) end
end

function Menu:PrependSecureScript(attribute, body)
	local suffix = self:GetAttribute(attribute)
	self:SetAttribute(attribute, (suffix and body .. suffix) or body)
end

function Menu:AppendSecureScript(attribute, body)
	local prefix = self:GetAttribute(attribute)
	self:SetAttribute(attribute, (prefix and prefix .. body) or body)
end

---------------------------------------------------------------
-- Art

function Menu:LoadArt()
	local db = ConsolePort:GetData()
	local nR, nG, nB = CPAPI.NormalizeColor(CPAPI.GetClassColor())

	self.TopLine:SetVertexColor(nR, nG, nB, 1)
	self:SetClassGradient(self.BG)

	self.BG:Show()
	self.GlowLeft:Show()
	self.GlowRight:Show()

	self.FadeIn, self.FadeOut = db.Alpha.FadeIn, db.Alpha.FadeOut;

	self:HookScript('OnShow', self.OnShowPlay)
	self.LoadArt = nil;
end


function Menu:SetClassGradient(object, alpha)
	local r, g, b = CPAPI.GetClassColor()
	local gBase, gMulti, gAlpha = .3, 1.1, alpha or 0.5;

	CPAPI.SetGradient(object, 'HORIZONTAL',
		(r + gBase) * gMulti, (g + gBase) * gMulti, (b + gBase) * gMulti, gAlpha,
		1 - (r - gBase) * gMulti, 1 - (g - gBase) * gMulti, 1 - (b - gBase) * gMulti, gAlpha)
end

function Menu:OnHeaderSet(id)
	self.Flair:ClearAllPoints()
	local header = type(id) == 'string' and _G[id] or id
	if header then
		if header.OnFocusAnim then
			header.OnFocusAnim:Play()
		end
		if header.OnFocus then
			header:OnFocus()
		end
		self.FadeOut(self.Flair, 0.5, 1, .25)
		self.Flair:SetPoint('BOTTOMLEFT', header, 'BOTTOMLEFT')
		self.Flair:SetPoint('BOTTOMRIGHT', header, 'BOTTOMRIGHT')
		self.Flair:SetHeight(64)
		self.Flair:Show()
	end
end

function Menu:OnHeaderCleared(id)
	local header = type(id) == 'string' and _G[id] or id
	if header and header.OnClear then
		header:OnClear()
	end
end

function Menu:OnShowPlay()
	self.FadeIn(self.Emblem, 0.5, 0, 1)
end

function Menu:OnButtonPressed()
	PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
end