view DependencyLoader/Tree.lua @ 10:e0a4a8b5b389

lots more modifications...
author mckenziemc
date Sun, 05 Dec 2010 03:10:07 -0800
parents 5362e308c3eb
children b230b94d4487
line wrap: on
line source
--	Tree
--	Represents a recursive "tree" of addon 
--	dependencies rooted at a specific addon.


local addonName, addonTable = ...


--	FIXME: prevent infinite loops in the recursive functions


local Tree, tree = addonTable:NewClass("Tree")


Tree.trees = {}


--	internal
--	Creates a new tree object
--	@param	root	Name, index, or Addon object of the root addon.
function Tree:New(root)
	if type(root) ~= "table" then
		root = addonTable.classes.Addon:Get(root)
	end
	
	local instance = {}
	setmetatable(instance, self.instanceMetatable)
	
	instance.root = root
	
	return instance
end


---	Retrieves the tree rooted at the specified addon
--	@param	root	Name, index, or Addon object of the root.
function Tree:Get(root)
	if type(root) ~= "table" then
		root = addonTable.classes.Addon:Get(root)
	end
	
	local tree = self.trees[root]
	
	if tree then
		return tree
	else
		tree = self:New(root)
		self.trees[root] = tree
		return tree
	end
end


function tree:GetLoadBitfield()
	local bitfield = self.root:GetLoadBitfield()
	
	local dependencies = {self.root:GetDependencies()}
	for i, depName in pairs(dependencies) do
		local depTree = Tree:Get(depName)
		
		if depTree == nil then
			return 0
		end
		
		bitfield = bit.band(bitfield, depTree:GetLoadBitfield())
	end
	
	return bitfield
end


---	Checks if this tree can be force-loaded.
--	Does not check user settings nor if force-loading is actually available.
--	@return	canForceLoad	True if this tree can be force loaded, false otherwise
function tree:CanForceLoad()
	if self.root:IsLoaded() then
		return true
	end
	
	if not self.root:CanForceLoad() then
		return false
	end
	
	--	now check dependencies recursively
	local dependencies = {self.root:GetDependencies()}
	for i, depName in pairs(dependencies) do
		local depTree = Tree:Get(depName)
		
		if not depTree:CanForceLoad() then
			return false
		end
	end
	
	return
end


--	NOTE: any tree that can be loaded on demand is also eligible for force-loading
--	Checks if the tree can be loaded on demand.
function tree:CanLoD()
	--	since this will be used recursively, return true if 
	--	this is already loaded.
	if self.root:IsLoaded() then
		return true
	end
	
	--	true if all dependencies are loaded or LoD
	
	if not self.root:CanLoD() then
		return false
	end
	
	--	now check dependencies recursively
	local dependencies = {root:GetDependencies()}
	for i, depName in pairs(dependencies) do
		local depTree = Tree:Get(depName)
		
		if not depTree:CanLoD() then
			return false
		end
	end
	
	return true
end


--	Checks if the tree rooted at the specified addon 
--	can be loaded if all dependencies are enabled 
--	the UI is reloaded.
--	Basically makes sure all dependencies are installed.
function tree:CanLoad()
	if self.root:IsLoaded() then
		return true
		--	FIXME: 	deps may have been disabled
	end
	
	--	TODO: make sure the root isn't incompatible
	
	--	now check dependencies recursively
	--	FIXME: prevent infinite recursion

	local dependencies = {self.root:GetDependencies()}
	for i, depName in pairs(dependencies) do
		local depTree = Tree:Get(depName)
		
		if not depTree:CanLoad() then
			return false		--	missing dependency
		end

		--	TODO: make sure it's compatible
	end
	
	return true
end

--[[
--	Loads the tree rooted at the specified addon.
--	FIXME: load the root too or not?
--	Supports both LoD addons and those that require force-loading.
function tree:Load(addon)
	--	don't check if the tree can actually be loaded.
	--	external code should do that itself to check if it 
	--	should even call this at all.

	if self:ForceLoadAvailable() then
		--	LoD trees can also be force-loaded
		self:ForceLoadTree(addon)
	else
		self:LoadLoDTree(addon)
	end
end
]]


--	load the root too, since it may actually be a leaf
function tree:ForceLoad()
	--	load dependencies
	local dependencies = {self.root:GetDependencies()}
	for i, depName in pairs(dependencies) do
		local depTree = Tree:Get(depName)
		depTree:ForceLoad()
	end

	--	load embeds, if they are available separately
	local embeds = {self.root:GetEmbeds()}
	for i, embedName in pairs(embeds) do
		local embedTree = Tree:Get(embedName)
		embedTree:ForceLoad()
	end
	
	root:ForceLoad()
end


--[[	don't think i need this
function core:LoadLoDTree(root)
	root = self:GetAddon(root)
	assert(root)
	
	--	load dependencies
	local dependencies = {root:GetDependencies(addon)}
	for i, depName in pairs(dependencies) do
		self:LoadLoDTree(depName)
	end

	--	load embeds, if they are available separately
	local embeds = {root:GetEmbeds(addon)}
	for i, embedName in pairs(embeds) do
		if Addon:Exists(embedName) then
			self:LoadLoDTree(embedName)
		end
	end
	
	root:LoD()
end
]]


--	I think the problem this solves is a major issue with 
--	migrating to separate libs. think about it more and document 
--	here and in project description
function tree:PrepareForLoD()
	--	assume root is LoD
	
	--	check dependencies
	local dependencies = {root:GetDependencies(addon)}
	for i, depName in pairs(dependencies) do
		local depTree = Tree:Get(depName)
		depTree:PrepareForLoD()
		
		--[[
		if dep:CanLoD() then
			--	don't load it now but make sure its dependencies are prepared
			self:PrepareLoDTree(depName)
		else
			--	FIXME: if it's already loaded
			--	force-load it now so we can load the parent on demand
			self:ForceLoadTree(depName)
		end
		]]
	end

	--	prepare embeds, if they are available separately
	local embeds = {root:GetEmbeds(addon)}	--	FIXME: addon?
	for i, embedName in pairs(embeds) do
		local embedTree = Tree:Get(embedName)
		embedTree:PrepareForLoD()
		
		--[[
		if embed then
			if embed:CanLoD() then
				--	don't load it now but make sure its dependencies are prepared
				self:PrepareLoDTree(embedName)
			else
				--	FIXME: if it's already loaded
				--	force-load it now so we can load the parent on demand
				self:ForceLoadTree(depName)
			end
		end
		]]
	end
end


function tree:PrepareForReload()
	self.root:Enable()
	
	--	check dependencies
	local dependencies = {self.root:GetDependencies()}
	for i, depName in pairs(dependencies) do
		Tree:Get(depName):PrepareForReload()
	end

	--	prepare embeds, if they are available separately
	local embeds = {self.root:GetEmbeds(addon)}
	for i, embedName in pairs(embeds) do
		Tree:Get(embedName):PrepareForReload()
	end
end