--[[
Name: AceDB-2.0
Revision: $Rev: 4763 $
Author(s): ckknight (ckknight@gmail.com)
Inspired By: AceDB 1.x by Turan (<email here>)
Website: http://www.wowace.com/
Documentation: http://wiki.wowace.com/index.php/AceDB-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceDB-2.0
Description: Mixin to allow for fast, clean, and featureful saved variable
             access.
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0
]]

local MAJOR_VERSION = "AceDB-2.0"
local MINOR_VERSION = "$Revision: 4763 $"

if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end

if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end

-- localize --
local ACTIVE = "Active"
local STATE = "State"
local TOGGLE_ACTIVE = "Suspend/resume this addon"
local MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Active|r", [false] = "|cffff0000Suspended|r" }
local SET_PROFILE = "Set profile for this addon"
local SET_PROFILE_USAGE = "{char || class || realm || <profile name>}"
local PROFILE = "Profile"
local PLAYER_OF_REALM = "%s of %s"
-- localize --

local AceOO = AceLibrary("AceOO-2.0")
local AceEvent
local Mixin = AceOO.Mixin
local AceDB = Mixin {
						"RegisterDB",
						"RegisterDefaults",
						"ResetDB",
						"SetProfile",
						"GetProfile",
						"ToggleActive",
						"IsActive",
						"AcquireDBNamespace",
						"ToggleStandby", -- remove at 2006-07-21
						"IsEnabled", -- remove at 2006-07-21
					}

local _G = getfenv(0)

local function inheritDefaults(t, defaults)
	if not defaults then
		return t
	end
	for k,v in pairs(defaults) do
		if k == "*" then
			local v = v
			if type(v) == "table" then
				setmetatable(t, {
					__index = function(self, key)
						if key == nil then
							return nil
						end
						self[key] = {}
						inheritDefaults(self[key], v)
						return self[key]
					end
				} )
			else
				setmetatable(t, {
					__index = function(self, key)
						if key == nil then
							return nil
						end
						self[key] = v
						return self[key]
					end
				} )
			end
			for key in pairs(t) do
				if (defaults[key] == nil or key == "*") and type(t[key]) == "table" then
					inheritDefaults(t[key], v)
				end
			end
		else
			if type(v) == "table" then
				if type(t[k]) ~= "table" then
					t[k] = {}
				end
				inheritDefaults(t[k], v)
			elseif t[k] == nil then
				t[k] = v
			end
		end
	end
	return t
end

local _,race = UnitRace("player")
local faction
if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" then
	faction = FACTION_HORDE
else
	faction = FACTION_ALLIANCE
end
local charID = string.format(PLAYER_OF_REALM, UnitName("player"), (string.gsub(GetRealmName(), "^%s*(.-)%s*$", "%1")))
local realm = string.gsub(GetRealmName(), "^%s*(.-)%s*$", "%1")
local realmID = realm .. " - " .. faction
local classID = UnitClass("player")

AceDB.CHAR_ID = charID
AceDB.REALM_ID = realmID
AceDB.CLASS_ID = classID

AceDB.FACTION = faction
AceDB.REALM = realm
AceDB.NAME = UnitName("player")

local caseInsensitive_mt = {
	__index = function(self, key)
		if type(key) ~= "string" then
			return nil
		end
		local lowerKey = string.lower(key)
		for k,v in pairs(self) do
			if string.lower(k) == lowerKey then
				return self[k]
			end
		end
	end,
	__newindex = function(self, key, value)
		if type(key) ~= "string" then
			return error("table index is nil", 2)
		end
		local lowerKey = string.lower(key)
		for k in pairs(self) do
			if string.lower(k) == lowerKey then
				rawset(self, k, nil)
				rawset(self, key, value)
				return
			end
		end
		rawset(self, key, value)
	end
}

local db_mt = { __index = function(db, key)
	if key == "char" then
		if db.charName then
			if type(_G[db.charName]) ~= "table" then
				_G[db.charName] = {}
			end
			if type(_G[db.charName].raw) ~= "table" then
				_G[db.charName].global = {}
			end
			rawset(db, 'char', _G[db.charName].global)
		else
			if type(db.raw.chars) ~= "table" then
				db.raw.chars = {}
			end
			local id = charID
			if type(db.raw.chars[id]) ~= "table" then
				db.raw.chars[id] = {}
			end
			rawset(db, 'char', db.raw.chars[id])
		end
		if db.defaults and db.defaults.char then
			inheritDefaults(db.char, db.defaults.char)
		end
		return db.char
	elseif key == "realm" then
		if type(db.raw.realms) ~= "table" then
			db.raw.realms = {}
		end
		local id = realmID
		if type(db.raw.realms[id]) ~= "table" then
			db.raw.realms[id] = {}
		end
		rawset(db, 'realm', db.raw.realms[id])
		if db.defaults and db.defaults.realm then
			inheritDefaults(db.realm, db.defaults.realm)
		end
		return db.realm
	elseif key == "account" then
		if type(db.raw.account) ~= "table" then
			db.raw.account = {}
		end
		rawset(db, 'account', db.raw.account)
		if db.defaults and db.defaults.account then
			inheritDefaults(db.account, db.defaults.account)
		end
		return db.account
	elseif key == "class" then
		if type(db.raw.classes) ~= "table" then
			db.raw.classes = {}
		end
		local id = classID
		if type(db.raw.classes[id]) ~= "table" then
			db.raw.classes[id] = {}
		end
		rawset(db, 'class', db.raw.classes[id])
		if db.defaults and db.defaults.class then
			inheritDefaults(db.class, db.defaults.class)
		end
		return db.class
	elseif key == "profile" then
		if type(db.raw.profiles) ~= "table" then
			db.raw.profiles = setmetatable({}, caseInsensitive_mt)
		else
			setmetatable(db.raw.profiles, caseInsensitive_mt)
		end
		local id = db.raw.currentProfile[charID]
		if id == "char" then
			id = "char/" .. charID
		elseif id == "class" then
			id = "class/" .. classID
		elseif id == "realm" then
			id = "realm/" .. realmID
		end
		if type(db.raw.profiles[id]) ~= "table" then
			db.raw.profiles[id] = {}
		end
		rawset(db, 'profile', db.raw.profiles[id])
		if db.defaults and db.defaults.profile then
			inheritDefaults(db.profile, db.defaults.profile)
		end
		return db.profile
	elseif key == "raw" or key == "defaults" or key == "name" or key == "charName" or key == "namespaces" then
		return nil
	end
	error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2)
end, __newindex = function(db, key, value)
	error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2)
end }

local namespace_mt = { __index = function(namespace, key)
	local db = namespace.db
	local name = namespace.name
	if key == "char" then
		if db.charName then
			if type(_G[db.charName]) ~= "table" then
				_G[db.charName] = {}
			end
			if type(_G[db.charName].namespaces) ~= "table" then
				_G[db.charName].namespaces = {}
			end
			if type(_G[db.charName].namespaces[name]) ~= "table" then
				_G[db.charName].namespaces[name] = {}
			end
			rawset(namespace, 'char', _G[db.charName].namespaces[name])
		else
			if type(db.raw.namespaces) ~= "table" then
				db.raw.namespaces = {}
			end
			if type(db.raw.namespaces[name]) ~= "table" then
				db.raw.namespaces[name] = {}
			end
			if type(db.raw.namespaces[name].chars) ~= "table" then
				db.raw.namespaces[name].chars = {}
			end
			local id = charID
			if type(db.raw.namespaces[name].chars[id]) ~= "table" then
				db.raw.namespaces[name].chars[id] = {}
			end
			rawset(namespace, 'char', db.raw.namespaces[name].chars[id])
		end
		if namespace.defaults and namespace.defaults.char then
			inheritDefaults(namespace.char, namespace.defaults.char)
		end
		return namespace.char
	elseif key == "realm" then
		if type(db.raw.namespaces) ~= "table" then
			db.raw.namespaces = {}
		end
		if type(db.raw.namespaces[name]) ~= "table" then
			db.raw.namespaces[name] = {}
		end
		if type(db.raw.namespaces[name].realms) ~= "table" then
			db.raw.namespaces[name].realms = {}
		end
		local id = realmID
		if type(db.raw.namespaces[name].realms[id]) ~= "table" then
			db.raw.namespaces[name].realms[id] = {}
		end
		rawset(namespace, 'realm', db.raw.namespaces[name].realms[id])
		if namespace.defaults and namespace.defaults.realm then
			inheritDefaults(namespace.realm, namespace.defaults.realm)
		end
		return namespace.realm
	elseif key == "account" then
		if type(db.raw.namespaces) ~= "table" then
			db.raw.namespaces = {}
		end
		if type(db.raw.namespaces[name]) ~= "table" then
			db.raw.namespaces[name] = {}
		end
		if type(db.raw.namespaces[name].account) ~= "table" then
			db.raw.namespaces[name].account = {}
		end
		rawset(namespace, 'account', db.raw.namespaces[name].account)
		if namespace.defaults and namespace.defaults.account then
			inheritDefaults(namespace.account, namespace.defaults.account)
		end
		return namespace.account
	elseif key == "class" then
		if type(db.raw.namespaces) ~= "table" then
			db.raw.namespaces = {}
		end
		if type(db.raw.namespaces[name]) ~= "table" then
			db.raw.namespaces[name] = {}
		end
		if type(db.raw.namespaces[name].classes) ~= "table" then
			db.raw.namespaces[name].classes = {}
		end
		local id = classID
		if type(db.raw.namespaces[name].classes[id]) ~= "table" then
			db.raw.namespaces[name].classes[id] = {}
		end
		rawset(namespace, 'class', db.raw.namespaces[name].classes[id])
		if namespace.defaults and namespace.defaults.class then
			inheritDefaults(namespace.class, namespace.defaults.class)
		end
		return namespace.class
	elseif key == "profile" then
		if type(db.raw.namespaces) ~= "table" then
			db.raw.namespaces = {}
		end
		if type(db.raw.namespaces[name]) ~= "table" then
			db.raw.namespaces[name] = {}
		end
		if type(db.raw.namespaces[name].profiles) ~= "table" then
			db.raw.namespaces[name].profiles = setmetatable({}, caseInsensitive_mt)
		else
			setmetatable(db.raw.namespaces[name].profiles, caseInsensitive_mt)
		end
		local id = db.raw.currentProfile[charID]
		if id == "char" then
			id = "char/" .. charID
		elseif id == "class" then
			id = "class/" .. classID
		elseif id == "realm" then
			id = "realm/" .. realmID
		end
		if type(db.raw.namespaces[name].profiles[id]) ~= "table" then
			db.raw.namespaces[name].profiles[id] = {}
		end
		rawset(namespace, 'profile', db.raw.namespaces[name].profiles[id])
		if namespace.defaults and namespace.defaults.profile then
			inheritDefaults(namespace.profile, namespace.defaults.profile)
		end
		return namespace.profile
	elseif key == "defaults" or key == "name" or key == "db" then
		return nil
	end
	error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2)
end, __newindex = function(db, key, value)
	error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2)
end }

function AceDB:InitializeDB(addonName)
	local db = self.db
	
	if not db then
		if addonName then
			AceDB.addonsLoaded[addonName] = true
		end
		return
	end
	
	if db.raw then
		-- someone manually initialized
		return
	end
	
	if type(_G[db.name]) ~= "table" then
		_G[db.name] = {}
	end
	rawset(db, 'raw', _G[db.name])
	if not db.raw.currentProfile then
		db.raw.currentProfile = {}
	end
	if not db.raw.currentProfile[charID] then
		db.raw.currentProfile[charID] = "default"
	end
	if db.raw.disabled then
		setmetatable(db.raw.disabled, caseInsensitive_mt)
	end
	setmetatable(db, db_mt)
end

function AceDB:RegisterDB(name, charName)
	AceDB:argCheck(name, 2, "string")
	AceDB:argCheck(charName, 3, "string", "nil")
	if self.db then
		AceDB:error("Cannot call \"RegisterDB\" if self.db is set.")
	end
	local stack = debugstack()
	local addonName = string.gsub(stack, ".-\n.-\\AddOns\\(.-)\\.*", "%1")
	self.db = {
		name = name,
		charName = charName
	}
	if AceDB.addonsLoaded[addonName] then
		AceDB.InitializeDB(self, addonName)
	else
		AceDB.addonsToBeInitialized[self] = addonName
	end
	AceDB.registry[self] = true
end

function AceDB:RegisterDefaults(kind, defaults, a3)
	local name
	if a3 then
		name, kind, defaults = kind, defaults, a3
		AceDB:argCheck(name, 2, "string")
		AceDB:argCheck(kind, 3, "string")
		AceDB:argCheck(defaults, 4, "table")
		if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" then
			AceDB:error("Bad argument #3 to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", or \"realm\" expected, got %q)", kind)
		end
	else
		AceDB:argCheck(kind, 2, "string")
		AceDB:argCheck(defaults, 3, "table")
		if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" then
			AceDB:error("Bad argument #2 to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", or \"realm\" expected, got %q)", kind)
		end
	end
	if type(self.db) ~= "table" or type(self.db.name) ~= "string" then
		AceDB:error("Cannot call \"RegisterDefaults\" unless \"RegisterDB\" has been previously called.")
	end
	local db
	if name then
		local namespace = self:AcquireDBNamespace(name)
		if namespace.defaults and namespace.defaults[kind] then
			AceDB:error("\"RegisterDefaults\" has already been called for %q::%q.", name, kind)
		end
		db = namespace
	else
		if self.db.defaults and self.db.defaults[kind] then
			AceDB:error("\"RegisterDefaults\" has already been called for %q.", kind)
		end
		db = self.db
	end
	if not db.defaults then
		rawset(db, 'defaults', {})
	end
	db.defaults[kind] = defaults
	if rawget(db, kind) then
		inheritDefaults(db[kind], defaults)
	end
end

function AceDB:ResetDB(kind)
	AceDB:checkArg(kind, 2, "nil", "string")
	if not self.db or not self.db.raw then
		AceDB:error("Cannot call \"ResetDB\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
	end
	local db = self.db
	if kind == nil then
		if db.charName then
			_G[db.charName] = nil
		end
		_G[db.name] = nil
		rawset(db, 'raw', nil)
		AceDB.InitializeDB(self)
		for name,v in pairs(db.namespaces) do
			rawset(v, 'account', nil)
			rawset(v, 'char', nil)
			rawset(v, 'class', nil)
			rawset(v, 'profile', nil)
			rawset(v, 'realm', nil)
		end
	elseif kind == "account" then
		db.raw.account = nil
		rawset(db, 'account', nil)
		for name,v in pairs(db.namespaces) do
			rawset(v, 'account', nil)
		end
	elseif kind == "char" then
		if db.charName then
			_G[db.charName] = nil
		else
			db.raw.chars[charID] = nil
			for name,v in pairs(db.raw.namespaces) do
				if v.chars then
					v.chars[charID] = nil
				end
			end
		end
		rawset(db, 'char', nil)
		for name,v in pairs(db.namespaces) do
			rawset(v, 'char', nil)
		end
	elseif kind == "realm" then
		db.raw.realms[realmID] = nil
		rawset(db, 'realm', nil)
		for name,v in pairs(db.raw.namespaces) do
			if v.realms then
				v.realms[realmID] = nil
			end
		end
		for name,v in pairs(db.namespaces) do
			rawset(v, 'realm', nil)
		end
	elseif kind == "class" then
		db.raw.realms[classID] = nil
		rawset(db, 'class', nil)
		for name,v in pairs(db.raw.namespaces) do
			if v.classes then
				v.classes[classID] = nil
			end
		end
		for name,v in pairs(db.namespaces) do
			rawset(v, 'class', nil)
		end
	elseif kind == "profile" then
		local id = db.raw.currentProfile[charID]
		if id == "char" then
			id = "char/" .. charID
		elseif id == "class" then
			id = "class/" .. classID
		elseif id == "realm" then
			id = "realm/" .. realmID
		end
		db.raw.profiles[id] = nil
		rawset(db, 'profile', nil)
		for name,v in pairs(db.raw.namespaces) do
			if v.profiles then
				v.profiles[id] = nil
			end
		end
		for name,v in pairs(db.namespaces) do
			rawset(v, 'profile', nil)
		end
	end
end

local function cleanDefaults(t, defaults)
	if defaults then
		for k,v in pairs(defaults) do
			if k == "*" then
				if type(v) == "table" then
					for k in pairs(t) do
						if (defaults[k] == nil or k == "*") and type(t[k]) == "table" then
							if cleanDefaults(t[k], v) then
								t[k] = nil
							end
						end
					end
				else
					for k in pairs(t) do
						if (defaults[k] == nil or k == "*") and t[k] == v then
							t[k] = nil
						end
					end
				end
			else
				if type(v) == "table" then
					if type(t[k]) == "table" then
						if cleanDefaults(t[k], v) then
							t[k] = nil
						end
					end
				elseif t[k] == v then
					t[k] = nil
				end
			end
		end
	end
	return not next(t)
end

function AceDB:GetProfile()
	if not self.db or not self.db.raw then
		return nil
	end
	local profile = self.db.raw.currentProfile[charID]
	if profile == "char" then
		return "char", "char/" .. charID
	elseif profile == "class" then
		return "class", "class/" .. classID
	elseif profile == "realm" then
		return "realm", "realm/" .. realmID
	end
	return profile, profile
end

local function copyTable(to, from)
	setmetatable(to, nil)
	for k,v in pairs(from) do
		if type(k) == "table" then
			k = copyTable({}, k)
		end
		if type(v) == "table" then
			v = copyTable({}, v)
		end
		to[k] = v
	end
	table.setn(to, table.getn(from))
	setmetatable(to, from)
	return to
end

local stage = 3
if tonumber(date("%Y%m%d")) < 20060713 then
	stage = 1
elseif tonumber(date("%Y%m%d")) < 20060720 then
	stage = 2
end

function AceDB:SetProfile(name, copyFrom)
	AceDB:argCheck(name, 2, "string")
	AceDB:argCheck(copyFrom, 3, "string", "nil")
	if not self.db or not self.db.raw then
		AceDB:error("Cannot call \"SetProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
	end
	local db = self.db
	local copy = false
	local lowerName = string.lower(name)
	local lowerCopyFrom = copyFrom and string.lower(copyFrom)
	if string.sub(lowerName, 1, 5) == "char/" or string.sub(lowerName, 1, 6) == "realm/" or string.sub(lowerName, 1, 6) == "class/" then
		if stage <= 2 then
			if string.sub(lowerName, 1, 5) == "char/" then
				name, copyFrom = "char", name
			else
				name, copyFrom = string.sub(lowerName, 1, 5), name
			end
			lowerName = string.lower(name)
			lowerCopyFrom = string.lower(copyFrom)
			if stage == 2 then
				local line = string.gsub(debugstack(), ".-\n(.-)\n.*", "%1")
				DEFAULT_CHAT_MESSAGE:AddMessage(line .. " - Bad argument #2 to `SetProfile'. Cannot start with char/, realm/, or class/. This will cause an error on July 20, 2006.")
			end
		else
			AceDB:error("Bad argument #2 to `SetProfile'. Cannot start with char/, realm/, or class/.")
		end
	end
	if copyFrom then
		if string.sub(lowerCopyFrom, 1, 5) == "char/" then
			AceDB:assert(lowerName == "char", "If argument #3 starts with `char/', argument #2 must be `char'")
		elseif string.sub(lowerCopyFrom, 1, 6) == "realm/" then
			AceDB:assert(lowerName == "realm", "If argument #3 starts with `realm/', argument #2 must be `realm'")
		elseif string.sub(lowerCopyFrom, 1, 6) == "class/" then
			AceDB:assert(lowerName == "class", "If argument #3 starts with `class/', argument #2 must be `class'")
		else
			AceDB:assert(lowerName ~= "char" and lowerName ~= "realm" and lowerName ~= "class", "If argument #3 does not start with a special prefix, that prefix cannot be copied to.")
		end
		if not db.raw.profiles or not db.raw.profiles[copyFrom] then
			AceDB:error("Cannot copy profile %q, it does not exist.", copyFrom)
		elseif (string.sub(lowerName, 1, 5) == "char/" and string.sub(lowerName, 6) == string.lower(charID)) or (string.sub(lowerName, 1, 6) == "realm/" and string.sub(lowerName, 7) == string.lower(realmID)) or (string.sub(lowerName, 1, 6) == "class/" and string.sub(lowerName, 7) == string.lower(classID)) then
			AceDB:error("Cannot copy profile %q, it is currently in use.", name)
		end
	end
	local oldName = db.raw.currentProfile[charID]
	if type(self.OnProfileDisable) == "function" then
		self:OnProfileDisable()
	end
	local oldProfileData = db.profile
	local realName = name
	if lowerName == "char" then
		realName = name .. "/" .. charID
	elseif lowerName == "realm/" then
		realName = name .. "/" .. realmID
	elseif lowerName == "class/" then
		realName = name .. "/" .. classID
	end
	local active = self:IsActive()
	db.raw.currentProfile[charID] = name
	rawset(db, 'profile', nil)
	if copyFrom then
		for k,v in pairs(db.profile) do
			db.profile[k] = nil
		end
		copyTable(db.profile, db.raw.profiles[copyFrom])
		inheritDefaults(db.profile, db.defaults and db.defaults.profile)
	end
	if type(self.OnProfileEnable) == "function" then
		self:OnProfileEnable(oldName, oldProfileData)
	end
	if cleanDefaults(oldProfileData, db.defaults and db.defaults.profile) then
		db.raw.profiles[oldName] = nil
		if not next(db.raw.profiles) then
			db.raw.profiles = nil
		end
	end
	local newactive = self:IsActive()
	if active ~= newactive then
		if AceOO.inherits(self, "AceAddon-2.0") then
			local AceAddon = AceLibrary("AceAddon-2.0")
			if not AceAddon.addonsStarted[self] then
				return
			end
		end
		if newactive then
			if type(self.OnEnable) == "function" then
				self:OnEnable()
			end
		else
			local current = self.class
			while true do
				if current == AceOO.Class then
					break
				end
				if current.mixins then
					for mixin in pairs(current.mixins) do
						if type(mixin.OnEmbedDisable) == "function" then
							mixin:OnEmbedDisable(self)
						end
					end
				end
				current = current.super
			end
			if type(self.OnDisabled) == "function" then
				self:OnDisable()
			end
		end
	end
end

local stage = 3
if tonumber(date("%Y%m%d")) < 20060714 then
	stage = 1
elseif tonumber(date("%Y%m%d")) < 20060721 then
	stage = 2
end

function AceDB:IsActive()
	return not self.db or not self.db.raw or not self.db.raw.disabled or not self.db.raw.disabled[self.db.raw.currentProfile[charID]]
end

function AceDB:ToggleActive(state)
	AceDB:argCheck(state, 2, "boolean", "nil")
	if not self.db or not self.db.raw then
		AceDB:error("Cannot call \"ToggleActive\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
	end
	local db = self.db
	if not db.raw.disabled then
		db.raw.disabled = setmetatable({}, caseInsensitive_mt)
	end
	local profile = db.raw.currentProfile[charID]
	local disable
	if state == nil then
		disable = not db.raw.disabled[profile]
	else
		disable = not state
		if disable == db.raw.disabled[profile] then
			return
		end
	end
	db.raw.disabled[profile] = disable or nil
	if AceOO.inherits(self, "AceAddon-2.0") then
		local AceAddon = AceLibrary("AceAddon-2.0")
		if not AceAddon.addonsStarted[self] then
			return
		end
	end
	if not disable then
		if type(self.OnEnable) == "function" then
			self:OnEnable()
		end
	else
		local current = self.class
		while true do
			if current == AceOO.Class then
				break
			end
			if current.mixins then
				for mixin in pairs(current.mixins) do
					if type(mixin.OnEmbedDisable) == "function" then
						mixin:OnEmbedDisable(self)
					end
				end
			end
			current = current.super
		end
		if type(self.OnDisable) == "function" then
			self:OnDisable()
		end
	end
	return not disable
end

if stage <= 2 then
	function AceDB:IsEnabled()
		if stage == 2 then
			local line = string.gsub(debugstack(), ".-\n(.-)\n.*", "%1")
			DEFAULT_CHAT_MESSAGE:AddMessage(line .. " - :IsEnabled() has been replaced by :IsActive(). This will cause an error on July 21, 2006.")
		end
		return self:IsActive()
	end
	function AceDB:ToggleStandby()
		if stage == 2 then
			local line = string.gsub(debugstack(), ".-\n(.-)\n.*", "%1")
			DEFAULT_CHAT_MESSAGE:AddMessage(line .. " - :ToggleStandby() has been replaced by :ToggleActive([state]). This will cause an error on July 21, 2006.")
		end
		return self:ToggleActive()
	end
end

function AceDB:embed(target)
	self.super.embed(self, target)
	if not AceEvent then
		AceDB:error(MAJOR_VERSION .. " requires AceEvent-2.0")
	end
end

function AceDB:ADDON_LOADED(name)
	AceDB.addonsLoaded[name] = true
	for addon, addonName in pairs(AceDB.addonsToBeInitialized) do
		if name == addonName then
			AceDB.InitializeDB(addon, name)
			AceDB.addonsToBeInitialized[addon] = nil
		end
	end
end

function AceDB:PLAYER_LOGOUT()
	for addon in pairs(AceDB.registry) do
		local db = addon.db
		if db then
			setmetatable(db, nil)
			if db.char and cleanDefaults(db.char, db.defaults and db.defaults.char) then
				if db.charName and _G[db.charName].global == db.char then
					_G[db.charName].global = nil
					if not next(_G[db.charName]) then
						_G[db.charName] = nil
					end
				else
					db.raw.chars[charID] = nil
					if not next(db.raw.chars) then
						db.raw.chars = nil
					end
				end
			end
			if db.realm and cleanDefaults(db.realm, db.defaults and db.defaults.realm) then
				db.raw.realms[realmID] = nil
				if not next(db.raw.realms) then
					db.raw.realms = nil
				end
			end
			if db.class and cleanDefaults(db.class, db.defaults and db.defaults.class) then
				db.raw.classes[classID] = nil
				if not next(db.raw.classes) then
					db.raw.classes = nil
				end
			end
			if db.account and cleanDefaults(db.account, db.defaults and db.defaults.account) then
				db.raw.account = nil
			end
			if db.profile and cleanDefaults(db.profile, db.defaults and db.defaults.profile) then
				db.raw.profiles[db.raw.currentProfile[charID] or "default"] = nil
				if not next(db.raw.profiles) then
					db.raw.profiles = nil
				end
			end
			if db.namespaces then
				for name,v in pairs(db.namespaces) do
					setmetatable(v, nil)
					if v.char and cleanDefaults(v.char, v.defaults and v.defaults.char) then
						if db.charName and _G[db.charName] and _G[db.charName].namespaces and _G[db.charName].namespaces[name] == v then
							_G[db.charName].namespaces[name] = nil
							if not next(_G[db.charName].namespaces) then
								_G[db.charName].namespaces = nil
								if not next(_G[db.charName]) then
									_G[db.charName] = nil
								end
							end
						else
							db.raw.namespaces[name].chars[charID] = nil
							if not next(db.raw.namespaces[name].chars) then
								db.raw.namespaces[name].chars = nil
							end
						end
					end
					if v.realm and cleanDefaults(v.realm, v.defaults and v.defaults.realm) then
						db.raw.namespaces[name].realms[realmID] = nil
						if not next(db.raw.namespaces[name].realms) then
							db.raw.namespaces[name].realms = nil
						end
					end
					if v.class and cleanDefaults(v.class, v.defaults and v.defaults.class) then
						db.raw.namespaces[name].classes[classID] = nil
						if not next(db.raw.namespaces[name].classes) then
							db.raw.namespaces[name].classes = nil
						end
					end
					if v.account and cleanDefaults(v.account, v.defaults and v.defaults.account) then
						db.raw.namespaces[name].account = nil
					end
					if v.profile and cleanDefaults(v.profile, v.defaults and v.defaults.profile) then
						db.raw.namespaces[name].profiles[db.raw.currentProfile[charID] or "default"] = nil
						if not next(db.raw.namespaces[name].profiles) then
							db.raw.namespaces[name].profiles = nil
						end
					end
					if not next(db.raw.namespaces[name]) then
						db.raw.namespaces[name] = nil
					end
				end
				if not next(db.raw.namespaces) then
					db.raw.namespaces = nil
				end
			end
			if db.raw.disabled then
				if not next(db.raw.disabled) then
					db.raw.disabled = nil
				end
			end
			if db.raw.currentProfile then
				for k,v in pairs(db.raw.currentProfile) do
					if string.lower(v) == "default" then
						db.raw.currentProfile[k] = nil
					end
				end
				if not next(db.raw.currentProfile) then
					db.raw.currentProfile = nil
				end
			end
			if not next(db.raw) then
				_G[db.name] = nil
			end
		end
	end
end

function AceDB:AcquireDBNamespace(name)
	AceDB:argCheck(name, 2, "string")
	local db = self.db
	if not db then
		AceDB:error("Cannot call `AcquireDBNamespace' before `RegisterDB' has been called.", 2)
	end
	if not db.namespaces then
		rawset(db, 'namespaces', {})
	end
	if not db.namespaces[name] then
		local namespace = {}
		db.namespaces[name] = namespace
		namespace.db = db
		namespace.name = name
		setmetatable(namespace, namespace_mt)
	end
	return db.namespaces[name]
end

local options
function AceDB:GetAceOptionsDataTable(target)
	if not options then
		options = {
			standby = {
				cmdName = STATE,
				guiName = ACTIVE,
				name = ACTIVE,
				desc = TOGGLE_ACTIVE,
				type = "toggle",
				get = "IsActive",
				set = "ToggleActive",
				map = MAP_ACTIVESUSPENDED,
			},
			profile = {
				name = PROFILE,
				desc = SET_PROFILE,
				get = "GetProfile",
				set = "SetProfile",
				usage = SET_PROFILE_USAGE,
				type = "text",
				validate = function(x) return not tonumber(x) end,
			}
		}
	end
	return options
end

local function activate(self, oldLib, oldDeactivate)
	AceDB = self
	AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0")
	
	self.super.activate(self, oldLib, oldDeactivate)
	
	for t in pairs(self.embedList) do
		if t.db then
			rawset(t.db, 'char', nil)
			rawset(t.db, 'realm', nil)
			rawset(t.db, 'class', nil)
			rawset(t.db, 'account', nil)
			rawset(t.db, 'profile', nil)
			setmetatable(t.db, db_mt)
		end
	end
	
	if oldLib then
		self.addonsToBeInitialized = oldLib.addonsToBeInitialized
		self.addonsLoaded = oldLib.addonsLoaded
		self.registry = oldLib.registry
	end
	if not self.addonsToBeInitialized then
		self.addonsToBeInitialized = {}
	end
	if not self.addonsLoaded then
		self.addonsLoaded = {}
	end
	if not self.registry then
		self.registry = {}
	end
	
	if oldLib then
		oldDeactivate(oldLib)
	end
end

local function external(self, major, instance)
	if major == "AceEvent-2.0" then
		AceEvent = instance
		
		AceEvent:embed(self)
		
		self:RegisterEvent("ADDON_LOADED")
		self:RegisterEvent("PLAYER_LOGOUT")
	end
end

AceLibrary:Register(AceDB, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
AceDB = AceLibrary(MAJOR_VERSION)
