-- ------------------------------------------------------------------------------ --
--                                TradeSkillMaster                                --
--                          https://tradeskillmaster.com                          --
--    All Rights Reserved - Detailed license information included with addon.     --
-- ------------------------------------------------------------------------------ --

--- ViewContainer UI Element Class.
-- A view container allows the content to be changed depending on the selected view (called the path). It is a subclass of the @{Container} class.
-- @classmod ViewContainer

local _, TSM = ...
local ViewContainer = TSM.Include("LibTSMClass").DefineClass("ViewContainer", TSM.UI.Container)
local Table = TSM.Include("Util.Table")
local UIElements = TSM.Include("UI.UIElements")
UIElements.Register(ViewContainer)
TSM.UI.ViewContainer = ViewContainer



-- ============================================================================
-- Public Class Methods
-- ============================================================================

function ViewContainer.__init(self)
	local frame = UIElements.CreateFrame(self, "Frame")
	self.__super:__init(frame)
	self._pathsList = {}
	self._contextTable = nil
	self._defaultContextTable = nil
end

function ViewContainer.Acquire(self)
	self._path = nil
	self._navCallback = nil
	self.__super:Acquire()
end

function ViewContainer.Release(self)
	wipe(self._pathsList)
	self.__super:Release()
	self._contextTable = nil
	self._defaultContextTable = nil
end

function ViewContainer.SetLayout(self, layout)
	error("ViewContainer doesn't support this method")
end

function ViewContainer.AddChild(self, child)
	error("ViewContainer doesn't support this method")
end

function ViewContainer.AddChildNoLayout(self, child)
	error("ViewContainer doesn't support this method")
end

--- Set the navigation callback.
-- @tparam ViewContainer self The view container object
-- @tparam function callback The function called when the selected path changes to get the new content
-- @treturn ViewContainer The view container object
function ViewContainer.SetNavCallback(self, callback)
	self._navCallback = callback
	return self
end

--- Add a path (view).
-- @tparam ViewContainer self The view container object
-- @tparam string path The path
-- @tparam[opt=false] boolean setSelected Set this as the selected path (view)
-- @treturn ViewContainer The view container object
function ViewContainer.AddPath(self, path, setSelected)
	tinsert(self._pathsList, path)
	if self._contextTable then
		assert(setSelected == nil, "Cannot set selected path when using a context table")
		local newPathIndex = Table.KeyByValue(self._pathsList, path)
		if self._contextTable.pathIndex == newPathIndex then
			self:SetPath(path)
		end
	elseif setSelected then
		self:SetPath(path)
	end
	return self
end

--- Renames a path (view).
-- @tparam ViewContainer self The view container object
-- @tparam string path The new path
-- @tparam number index The index of the path to change
-- @treturn ViewContainer The view container object
function ViewContainer.RenamePath(self, path, index)
	local changePath = self._pathsList[index] == self._path
	self._pathsList[index] = path

	if changePath then
		self:SetPath(path)
	end
	return self
end

--- Set the selected path (view).
-- @tparam ViewContainer self The view container object
-- @tparam string path The selected path
-- @tparam boolean redraw Whether or not to redraw the view container
-- @treturn ViewContainer The view container object
function ViewContainer.SetPath(self, path, redraw)
	if path ~= self._path then
		local child = self:_GetChild()
		if child then
			assert(#self._layoutChildren == 1)
			self:RemoveChild(child)
			child:Release()
		end
		self.__super:AddChild(self:_navCallback(path))
		self._path = path
		-- Save the path index of the new selected path to the context table
		if self._contextTable then
			self._contextTable.pathIndex = Table.KeyByValue(self._pathsList, path)
		end
	end
	if redraw then
		self:Draw()
	end
	return self
end

--- Reload the current view.
-- @tparam ViewContainer self The view container object
function ViewContainer.ReloadContent(self)
	local path = self._path
	self._path = nil
	self:SetPath(path, true)
end

--- Get the current path (view).
-- @tparam ViewContainer self The view container object
-- @treturn string The current path
function ViewContainer.GetPath(self)
	return self._path
end

--- Get a list of the paths for the view container.
-- @tparam ViewContainer self The view container object
-- @treturn table The path list
function ViewContainer.GetPathList(self)
	return self._pathsList
end

function ViewContainer.Draw(self)
	self.__super.__super:Draw()
	local child = self:_GetChild()
	local childFrame = child:_GetBaseFrame()

	-- set the child to be full-size
	childFrame:ClearAllPoints()
	local xOffset, yOffset = child:_GetMarginAnchorOffsets("BOTTOMLEFT")
	local paddingXOffset, paddingYOffset = self:_GetPaddingAnchorOffsets("BOTTOMLEFT")
	xOffset = xOffset + paddingXOffset - self:_GetContentPadding("LEFT")
	yOffset = yOffset + paddingYOffset - self:_GetContentPadding("BOTTOM")
	childFrame:SetPoint("BOTTOMLEFT", xOffset, yOffset)
	xOffset, yOffset = child:_GetMarginAnchorOffsets("TOPRIGHT")
	paddingXOffset, paddingYOffset = self:_GetPaddingAnchorOffsets("TOPRIGHT")
	xOffset = xOffset + paddingXOffset - self:_GetContentPadding("RIGHT")
	yOffset = yOffset + paddingYOffset - self:_GetContentPadding("TOP")
	childFrame:SetPoint("TOPRIGHT", xOffset, yOffset)
	child:Draw()

	-- draw the no-layout children
	for _, noLayoutChild in ipairs(self._noLayoutChildren) do
		noLayoutChild:Draw()
	end
end

--- Sets the context table.
-- This table can be used to save which tab is active, refrenced by the path index
-- @tparam ViewContainer self The view container object
-- @tparam table tbl The context table
-- @tparam table defaultTbl Default values
-- @treturn ViewContainer The view container object
function ViewContainer.SetContextTable(self, tbl, defaultTbl)
	assert(defaultTbl.pathIndex ~= nil)
	tbl.pathIndex = tbl.pathIndex or defaultTbl.pathIndex
	self._contextTable = tbl
	self._defaultContextTable = defaultTbl
	return self
end

--- Sets the context table from a settings object.
-- @tparam ViewContainer self The view container object
-- @tparam Settings settings The settings object
-- @tparam string key The setting key
-- @treturn ViewContainer The view container object
function ViewContainer.SetSettingsContext(self, settings, key)
	return self:SetContextTable(settings[key], settings:GetDefaultReadOnly(key))
end



-- ============================================================================
-- Private Class Methods
-- ============================================================================

function ViewContainer._GetMinimumDimension(self, dimension)
	if dimension == "WIDTH" then
		local width = self._width
		if width then
			return width, false
		else
			return self:_GetChild():_GetMinimumDimension(dimension)
		end
	elseif dimension == "HEIGHT" then
		local height = self._height
		if height then
			return height, false
		else
			return self:_GetChild():_GetMinimumDimension(dimension)
		end
	else
		error("Invalid dimension: "..tostring(dimension))
	end
end

function ViewContainer._GetContentPadding(self, side)
	if side == "TOP" then
		return 0
	elseif side == "BOTTOM" then
		return 0
	elseif side == "LEFT" then
		return 0
	elseif side == "RIGHT" then
		return 0
	else
		error("Invalid side: "..tostring(side))
	end
end

function ViewContainer._GetChild(self)
	return self._layoutChildren[1]
end
