--[[---------------------------------------------------------------------------

Copyright (c) 2008 by K. Scott Piel 
All Rights Reserved

E-mail: < kscottpiel@gmail.com >
Web:    < http://www.scottpiel.com >

This file is part of nUI.

    nUI is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    nUI is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with nUI.  If not, see <http://www.gnu.org/licenses/>.
	
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

--]]---------------------------------------------------------------------------

nUI_Version = "2.05.00 (Beta)";

if not nUI then nUI = {}; end
if not nUI_Skins then nUI_Skins = {}; end
if not nUI_UnitPanels then nUI_UnitPanels = {}; end
if not nUI_UnitFrames then nUI_UnitFrames = {}; end
if not nUI.FrameList then nUI.FrameList = {}; end
if not nUI.SkinnedFrames then nUI.SkinnedFrames = {}; end
if not nUI_L then nUI_L = {}; end
if not nUI_DefaultConfig then  nUI_DefaultConfig = {}; end
if not nUI_Options then nUI_Options = {}; end;
if not nUI_DebugLog then nUI_DebugLog = {}; end;

local ScalableFrameList = {};

-------------------------------------------------------------------------------
-- everything in nUI is anchored to, and a child of, the dashboard anchor
-- frame or one of the bar anchor frames. The purpose in doing this is to tie 
-- everything into a universal scale so that nUI can adjust itself to fit 
-- whatever display it is thrown at.

nUI_BottomBars.Anchor = CreateFrame( "Frame", "$parent_Anchor", nUI_BottomBars );
nUI_BottomBarsLocator:SetPoint( "BOTTOM", UIParent, "BOTTOM", 0, 0 );
nUI_BottomBars:SetPoint( "TOP", nUI_BottomBarsLocator, "TOP", 0, 0 );
nUI_BottomBars.Anchor:SetPoint( "TOP", nUI_BottomBars, "TOP", 0, 0 );

nUI_Dashboard.Anchor = CreateFrame( "Frame", "$parent_Anchor", nUI_Dashboard );
nUI_Dashboard:SetPoint( "BOTTOM", nUI_BottomBarsLocator, "TOP", 0, 0 );
nUI_Dashboard.Anchor:SetPoint( "CENTER", nUI_Dashboard, "CENTER", 0, 0 );

nUI_TopBars.Anchor = CreateFrame( "Frame", "$parent_Anchor", nUI_TopBars );
nUI_TopBarsLocator:SetPoint( "BOTTOM", UIParent, "TOP", 0, 0 );
nUI_TopBars:SetPoint( "BOTTOM", nUI_TopBarsLocator, "BOTTOM", 0, -130 );
nUI_TopBars.Anchor:SetPoint( "BOTTOM", nUI_TopBars, "BOTTOM", 0, 0 );

-------------------------------------------------------------------------------
-- the main nUI event driver

local function nUI_OnEvent()
	
	nUI:setScale();
		
	-- select the skin to be used
	
	if event == "VARIABLES_LOADED" then
		
		nUI.playerName = UnitName( "player" );
		nUI.realmName  = GetRealmName():trim();
	
		-- zero out the debug log for a new session
		
		if not nUI_DebugLog[nUI.realmName] then
			nUI_DebugLog[nUI.realmName] = {};
		end
		
		nUI_DebugLog[nUI.realmName][nUI.playerName] = {};
		
		-- attempt to load a skin by name... note that if the user
		-- wants to use a customized skin, they can use the skin
		-- name "custom" which will not match a known skin name
		-- and thus will set nUI_CurrentSkin nil, but the next
		-- test will see nUI_CurrentSkin already non-nil because of
		-- the data load and, thus, will use the player's custom skin

		if nUI_Options.skin
		and nUI_Options.skin ~= "default"
		and nUI_Options.skin ~= "custom"
		then
		
			if not nUI_CurrentSkin
			or nUI_CurrentSkin.name ~= nUI_Options.skin
			then
				nUI_CurrentSkin = nUI_Skins[nUI_Options.skin];
			end
		end
		
		-- if we do not have a skin loaded then either we have an
		-- invalid skin name, a skin name for an optional skin that's
		-- currently disabled or the user has not selected any skin
		-- and is using the built in default values
		
		if not nUI_CurrentSkin then
			
			if nUI_Options.skin 
			and nUI_Options.skin ~= "default" 
			and nUI_Options.skin ~= "custom"
			then
				DEFAULT_CHAT_FRAME:AddMessage( nUI_L["nUI could not load the currently selected skin [ %s ]... perhaps you have it disabled? Switching to the default nUI skin."]:format( nUI_Options.skin ), 1, 0.83, 0 );
			end
			
			nUI_Options.skin = "default";
			nUI_CurrentSkin  = nUI_DefaultConfig;
			
		end
		
		nUI_CurrentSkin.name = nUI_Options.skin;
		
		-- set the player's top console according to their current preference

		nUI:setConsoleVisibility( nUI_Options.console or "on" );
		
	-- the first time the player logs in we need to do some setup work
	
	elseif event == "PLAYER_LOGIN"
	then

		DEFAULT_CHAT_FRAME:AddMessage( (nUI_L["Welcome back to %s, %s..."].."\n"..nUI_L["nUI version %s is loaded!"].."\n"..nUI_L["Type '/nui' for a list of available nUI commands."].."\n"):format( nUI.realmName, nUI.playerName, nUI_Version ), 0, 1.0, 0.50 );
		
		-- hide away the Bliz UI elements we're replacing
		
		PossessBarFrame:SetClampedToScreen( false );
		PossessBarFrame:SetFrameStrata( "BACKGROUND" );
		PossessBarFrame:SetFrameLevel( 0 );	
		PossessBarFrame:ClearAllPoints();
		PossessBarFrame:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
		PossessBarFrame.SetPoint = function() end;
		
		ShapeshiftBarFrame:SetClampedToScreen( false );
		ShapeshiftBarFrame:SetFrameStrata( "BACKGROUND" );
		ShapeshiftBarFrame:SetFrameLevel( 0 );	
		ShapeshiftBarFrame:ClearAllPoints();
		ShapeshiftBarFrame:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
		ShapeshiftBarFrame.SetPoint = function() end;
		
		PetActionBarFrame:SetClampedToScreen( false );
		PetActionBarFrame:SetFrameStrata( "BACKGROUND" );
		PetActionBarFrame:SetFrameLevel( 0 );	
		PetActionBarFrame:ClearAllPoints();
		PetActionBarFrame:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
		PetActionBarFrame.SetPoint = function() end;
		
		MultiBarBottomLeft:SetClampedToScreen( false );
		MultiBarBottomLeft:SetFrameStrata( "BACKGROUND" );
		MultiBarBottomLeft:SetFrameLevel( 0 );	
		MultiBarBottomLeft:ClearAllPoints();
		MultiBarBottomLeft:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
		MultiBarBottomLeft.SetPoint       = function() end;
		
		MultiBarBottomRight:SetClampedToScreen( false );
		MultiBarBottomRight:SetFrameStrata( "BACKGROUND" );
		MultiBarBottomRight:SetFrameLevel( 0 );	
		MultiBarBottomRight:ClearAllPoints();
		MultiBarBottomRight:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
		MultiBarBottomRight.SetPoint       = function() end;
		
		MultiBarLeft:SetClampedToScreen( false );
		MultiBarLeft:SetFrameStrata( "BACKGROUND" );
		MultiBarLeft:SetFrameLevel( 0 );	
		MultiBarLeft:ClearAllPoints();
		MultiBarLeft:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
		MultiBarLeft.SetPoint       = function() end;
		
		MultiBarRight:SetClampedToScreen( false );
		MultiBarRight:SetFrameStrata( "BACKGROUND" );
		MultiBarRight:SetFrameLevel( 0 );	
		MultiBarRight:ClearAllPoints();
		MultiBarRight:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
		MultiBarRight.SetPoint     = function() end;
			
		MainMenuBar:SetClampedToScreen( false );
		MainMenuBar:SetParent( nUI_Dashboard );
		MainMenuBar:SetScale( 1.0 / nUI.scale );
		MainMenuBar:SetFrameStrata( "LOW" );
		MainMenuBar:SetFrameLevel( 1 );	
		MainMenuBar:ClearAllPoints();
		MainMenuBar:SetPoint( "TOPRIGHT", UIParent, "BOTTOMLEFT", -1000, -1000 );
	
		MainMenuExpBar:Hide();
		MainMenuBarMaxLevelBar:Hide();
		MainMenuBarPerformanceBarFrame:Hide();
		MainMenuBarPerformanceBarFrameButton:Hide();
		ExhaustionTick:Hide();
		
		nUI:disableUnitFrame( PlayerFrame );
		nUI:disableUnitFrame( PetFrame );
		nUI:disableUnitFrame( TargetFrame );		
		nUI:disableUnitFrame( TargetofTargetFrame );
		
		for i=1,4 do
			nUI:disableUnitFrame( _G["PartyMemberFrame"..i] );
			nUI:disableUnitFrame( _G["PartyMemberFrame"..i.."PetFrame"] );
		end
		
		TemporaryEnchantFrame:SetClampedToScreen( false );
		TemporaryEnchantFrame:ClearAllPoints();
		TemporaryEnchantFrame:SetPoint( "BOTTOMLEFT", UIParent, "TOPRIGHT", 1000, 1000 );	
		TemporaryEnchantFrame:Hide();
	
		BuffFrame:SetClampedToScreen( false );
		BuffFrame:ClearAllPoints();
		BuffFrame:SetPoint( "BOTTOMLEFT", UIParent, "TOPRIGHT", 1000, 1000 );	
		BuffFrame:Hide();
		
		CastingBarFrame:Hide();
		CastingBarFrame.Show = function() end;
		
		-- apply the current skin
		
		for i=1, #nUI.SkinnedFrames do
			nUI.SkinnedFrames[i].applySkin( nUI_CurrentSkin );
		end
		
	end
end

nUI_MasterFrame:SetScript( "OnEvent", nUI_OnEvent );
nUI_MasterFrame:RegisterEvent( "VARIABLES_LOADED" );
nUI_MasterFrame:RegisterEvent( "PLAYER_LOGIN" );
nUI_MasterFrame:RegisterEvent( "DISPLAY_SIZE_CHANGED" );

-------------------------------------------------------------------------------

local bar_fade_timer = 0;
local fade_in_rate   = 0.5;
local fade_out_rate  = 1;

local function nUI_OnUpdate( who, elapsed )

	-- manage top bar fade in and out visibility... note... none of this matter
	-- unless and until the bar visibility is defined
	
	if nUI_TopBars.visibility then
			
		bar_fade_timer = bar_fade_timer + elapsed;
		
		if bar_fade_timer > 0.08 then -- 12.5fps update... plenty fast enough I should think
		
			local now       = GetTime();
			local mouseover = nUI_TopBars.visibility == "mouseover";
			local hover     = mouseover and MouseIsOver( nUI_TopBars );
			
			bar_fade_timer = 0;
	
			-- if the mouse is over the top bars and we're in mouseover mode
			-- then start a fade in if the bars aren't already visibile
			
			if mouseover and hover
			and not nUI_TopBars.startFadeIn
			and not nUI_TopBars.stopFadeIn
			and nUI_TopBars:GetAlpha() == 0
			then
				
				nUI_TopBars.startFadeIn = now+0.25;
				
			end
			
			-- if the mouse is not hovering over the top bars and we're
			-- in mouseover mode, then if the bars are still visible
			-- we need to start a fade out
			
			if mouseover and not hover
			and not nUI_TopBars.startFadeOut
			and not nUI_TopBars.endFadeOut
			and nUI_TopBars:GetAlpha() == 1
			then
				
				nUI_TopBars.startFadeOut = now + 1;
				
			end
			
			-- if we think we need to start a fade in, check to ensure
			-- the user's mouse is still over the bars... they may have
			-- been just passing by, so don't start a false fade in
			
			if nUI_TopBars.startFadeIn then
				
				if mouseover
				and not MouseIsOver( nUI_TopBars ) then
					nUI_TopBars.startFadeIn = nil;
				else
					nUI_TopBars.stopFadeIn   = nUI_TopBars.startFadeIn + fade_in_rate;
					nUI_TopBars.startFadeOut = nil;
					nUI_TopBars.stopFadeOut  = nil;
					nUI_TopBars.startFadeIn  = nil;
				end
				
			-- likewise, if the mouse has left the top bars make sure it wasn't
			-- momentary... if we're in mouseover mode and the mouse is over
			-- the bars when we're actually ready to start the fade out, then
			-- abort it
			
			elseif nUI_TopBars.startFadeOut then
				
				if now >= nUI_TopBars.startFadeOut then
					
					if mouseover and MouseIsOver( nUI_TopBars )
					then
						nUI_TopBars.startFadeOut = nil;
					else
						nUI_TopBars.stopFadeOut  = nUI_TopBars.startFadeOut + fade_out_rate;
						nUI_TopBars.startFadeOut = nil;
					end			
				end
			end

			-- fade the bar in
			
			if nUI_TopBars.stopFadeIn then
				
				if now >= nUI_TopBars.stopFadeIn then
					nUI_TopBars:SetAlpha( 1 );
					nUI_TopBars.stopFadeIn = nil;
				else
					local dx = nUI_TopBars.stopFadeIn - now;
					nUI_TopBars:SetAlpha( (1 - dx) / fade_in_rate );			
				end
			end
			
			-- fade the bar out
			
			if nUI_TopBars.stopFadeOut then
				
				if now >= nUI_TopBars.stopFadeOut then
					nUI_TopBars:SetAlpha( 0 );
					nUI_TopBars.stopFadeOut = nil;
					
					if nUI_Options.console == "off" then
						nUI_MicroMenu:Hide();
					end
					
				else
					local dx = nUI_TopBars.stopFadeOut - now;
					nUI_TopBars:SetAlpha( dx / fade_out_rate );
				end			
			end
		end
	end
end

nUI_MasterFrame:SetScript( "OnUpdate", nUI_OnUpdate );

-------------------------------------------------------------------------------
-- methods for adding frames to and removing frames from the list of known
-- scalable frames. A scaleable frame has two methods in its interface...
--
-- frame.applyScale()  -- called to alert the frame that there has been some
--                        change in the scaling of the frame in order to allow
--                        the frame to adjust layouts, sizes, fonts or whatever
--                        else may be necessary
--
-- frame.applyAnchor() -- the anchoring of some frames relative to other frames
--                        may vary based on the scale of the nUI Dashboard. This
--                        method is called to let the frame know that the scale
--                        has changed in order to allow the frame to adjust its
--                        anchor point if required
--

function nUI:registerScalableFrame( frame )
	
	local register = true;
	local name     = frame:GetName() or nUI_L["<unnamed frame>"];
	
	-- ensure the registered frame will not blow up the interface
	
	if not frame.applyScale then
		
		register = false;
		DEFAULT_CHAT_FRAME:AddMessage( nUI_L["nUI: Cannot register %s for scaling... frame does not have an applyScale() method"]:format( name ), 1, 0.5, 0.5 );
		
	end
	
	if not frame.applyAnchor then
		
		register = false;
		DEFAULT_CHAT_FRAME:AddMessage( nUI_L["nUI: Cannot register %s for scaling... frame does not have an applyAnchor() method"]:format( name ), 1, 0.5, 0.5 );
		
	end
	
	-- if the frame conforms to the interface, register it
	
	if register then
		
		nUI:TableInsertByValue( ScalableFrameList, frame );
		
	end
end

function nUI:unregisterScalableFrame( frame )
	
	nUI:TableRemoveByValue( ScalableFrameList, frame );
	
end

-------------------------------------------------------------------------------
-- methods for adding frames to and removing frames from the list of known
-- skinned frames. A skinned frame has a single in its interface...
--
-- frame.applySkin( skin ) -- called to alert the frame that there has been some
--                            change in the skinning of nUI in order to allow
--                            the frame to adjust layouts, sizes, fonts or whatever
--                            else may be necessary. The passed value is the users
--                            currently chosen skin, the called object should be
--                            both aware of where its definition is supposed to
--                            be located within the skin and should be able to
--                            handle its configuration being missing entirely or
--                            having and element named "enabled" set to false...
--                            in either case, the object should consider itself
--                            to not exist in either case and should not display
--                            anything on screen or perform and operations in the
--                            background in that event. Either case is a declaration
--                            that the user does not want that object in their UI
--
-- NOTE: To apply itself, a custom addon should watch for the "VARIABLES_LOADED" event
--       and register itself with nUI at that time via nUI:registerSkinnedFrame() and
--       do no more. nUI will call the addon's frame.applySkin() method when it is
--       ready for the addon to do its layout. It may call the method again if the
--       user changes skins, so be ready to handle a new layout in realtime... see
--       AddOns\nUI_SysInfo.lua for a fairly simple example.
--
-- NOTE: A well behaved 3rd party addon should also register itself as a scalable
--       frame and use the combination of nUI.scale and the user selected scale value (below)
--       to alter its size and the orientation of its internal elements as well as anchoring
--
-- NOTE: nUI Core elements will inser themselves into any skin and cannot be disabled. If, for example,
--       your addon is defining a new skin and is does not contain values for casting bar colors, nUI
--       will insert its default values mercilessly. In short, any nUI core element not specifically 
--       defined in a skin is assumed to be whatever the nUI default value is. However, nUI defaults
--       can be overloaded by defining specific values for them in the skin definition.
--
-- NOTE: Third party addons should use (and expect) the following data logic to include 
--       themselves in a skin...
--
-- MyAddOnConfig =
-- {
--     anchor  = 	   -- where the user wants your addon to appear in their skin... suitable for frame:SetPoint()
--     {
--         anchor_pt   = value,			-- if nil, your addon should choose a sane anchor point
--         relative_to = frame_name,    -- if nil, your addon should choose its parent frame (by name as a string, not by refernce!)
--         relative_pt = value,         -- if nil, your addon should use the anchor_pt value
--         xOfs        = value,         -- if nil, your addon should use 0
--         yOfs        = value,         -- if nil, your addon should use 0
--     },
--     options =  						-- configuration options for the addon
--     {
--         enabled = value,				-- if false, the user has turned your addon off
--         scale   = value,				-- increases or descreases the size of your addon without altering dimesions
--         strata  = value,				-- if nil, you should use the parent frame's strata
--         level   = value,				-- if nil, you should use the parent frame's level + 1
--                                      -- whatever custom data/options your addon requires or offers
--
--          -- if not nil, your addon should have this border which is only visible when your addon is visible
--          -- otherwise, if border is nil, your addon should not display a border/background
--
--          -- see: frame:SetBackdrop(), frame:SetBackdropColor() and frame:SetBackdropBorderColor() for application
--
--			border =					
--			{							
--				backdrop =				-- suitable for passing into SetBackdrop()
--				{
--					bgFile   = value, 	-- path to the background texture file or nil for no background
--					edgeFile = value,	-- path to the border/edge texture file or nil for no edge
--					tile     = true, 	-- whether or not the background should be tiled
--					tileSize = n, 		-- how big to make each background tile
--					edgeSize = 5, 		-- how big to make the border
--					insets   = { left = 0, right = 0, top = 0, bottom = 0 },
--				},					
--				color =					-- if nil, select a set of sane default colors for your addon
--				{
--					border   = { r = 1, g = 1, b = 1, a = 0.5 }, -- suitable for passing to SetBackdropBorderColor()
--					backdrop = { r = 0, g = 0, b = 0, a = 0 },	 -- suitable for passing to SetBackdropColor()
--				},
--			},
--
--          -- background is identical to border in content and use, it differs in application... if not nil, this 
--          -- background should be displayed even when your addon is not (but IS enabled -- never diplay anything 
--          -- if your addon is disabled)... in practice, if background is non-nil, then create a second frame with
--          -- the same parent as your addon and one frame level below your addon. When you Show()/Hide() your addon, 
--          -- you do not Show()/Hide() this frame... this provides an "always on" backdrop for your addon (like a unit frame)
--
--			background =
--			{
--			},
--     },
-- };

function nUI:registerSkinnedFrame( frame )
	
	local register = true;
	local name     = frame:GetName() or nUI_L["<unnamed frame>"];
	
	-- ensure the registered frame will not blow up the interface
	
	if not frame.applySkin then
		
		register = false;
		DEFAULT_CHAT_FRAME:AddMessage( nUI_L["nUI: Cannot register %s for skinning... frame does not have an applySkin() method"]:format( name ), 1, 0.5, 0.5 );
		
	end
	
	-- if the frame conforms to the interface, register it
	
	if register then
		
		nUI:TableInsertByValue( nUI.SkinnedFrames, frame );
		
	end
end

function nUI:unregisterSkinnedFrame( frame )
	
	nUI:TableRemoveByValue( nUI.SkinnedFrames, frame );
	
end

-------------------------------------------------------------------------------
-- this method adjusts the size and location of a frame according to the
-- current scale of the nUI dashboard and is called when the player first
-- initializes nUI and again any time the display size changes

function nUI:setScale()

	local scale;

	-- what should the scale be now?

	if nUI_Options.scale and nUI_Options.scale > 0 then
		scale = nUI_Options.scale;
	else
		scale = (UIParent:GetRight() - UIParent:GetLeft()) / 2560;
	end

	-- if it is different than what we know the scale to be, then we need
	-- to update the size and position of all of our known scalable frames
	
	if nUI.scale ~= scale then
		
		nUI.scale = scale;
		
		nUI_MasterFrame:SetScale( nUI.scale );
		nUI_TopBars.Anchor:SetScale( 1.0 / nUI.scale );
		nUI_Dashboard.Anchor:SetScale( 1.0 / nUI.scale );
	
		-- update each known scalable frame
		
		for i,frame in ipairs( ScalableFrameList ) do
			
			frame.applyScale();
			frame.applyAnchor();
		
		end
	end
end

-------------------------------------------------------------------------------
-- disable unit frames to keep them from hammering the engine 

function nUI:disableUnitFrame( frame )
	
	UnregisterUnitWatch( frame );
	
	frame:UnregisterAllEvents();	

	frame:SetClampedToScreen( false );
	frame:ClearAllPoints();
	frame:SetPoint( "TOPRIGHT", UIParent, "TOPRIGHT", -1000, -1000 );
	frame:Hide();
	
	frame.Show           = function() end;
	frame.ClearAllPoints = function() end;
	frame.SetPoint       = function() end;
	frame.SetAllPoints   = function() end;

	local health = getglobal( frame:GetName().."HealthBar" );
	if health then health:UnregisterAllEvents(); end

	local mana = getglobal( frame:GetName().."ManaBar" );
	if mana then mana:UnregisterAllEvents(); end
	
end

-------------------------------------------------------------------------------
-- simple helper untility to remove an entry from a table by value 

function nUI:TableRemoveByValue( list, key )

	for i, value in ipairs( list ) do
		if value == key then						
			table.remove( list, i );
			break;
		end
	end				
end

-------------------------------------------------------------------------------
-- simple helper untility to insert a value into a table if it isn't already

function nUI:TableInsertByValue( list, key )

	local matched = false;

	if list then
			
		for i, value in ipairs( list ) do
			if value == key then						
				matched = true;
				break;
			end
		end				
		
		if not matched then 
			table.insert( list, key ); 
		end
	end
end

-------------------------------------------------------------------------------
-- method for setting and initializing the console visibility mode to on, off
-- or mouseover as well as setting the OnEnter and OnLeave functions

function nUI:setConsoleVisibility( option )

	if option ~= nUI_TopBars.visibility then
			
		if not nUI_TopBars.visibility and option ~= "on" then
			nUI_TopBars.startFadeOut = GetTime() + 15;
		elseif option == "on" then
			if nUI_TopBars.visibility == "off" then
				nUI_MicroMenu:Show();
			end
			nUI_TopBars.startFadeIn = GetTime() + 1;
		elseif nUI_Options.console == "on" then
			nUI_TopBars.startFadeOut = GetTime() + 5;
		end
		
		nUI_TopBars.visibility = option;				
		nUI_Options.console    = option;
	end	
end

-------------------------------------------------------------------------------

local debug_log = nil;

function nUI:debug( msg, level )
	
	local debug_level = nUI_Options.debug or 0;
	local print_debug = not level or debug_level < 0;
	
	if debug_level < 0 then debug_level = -debug_level; end
	
	if not level or level <= debug_level then

		if not debug_log then 
			debug_log = nUI_DebugLog[nUI.realmName][nUI.playerName]; 
		end
		
		if not msg then 
			msg = "<nil>"; 
		end
		
		if print_debug then 
			DEFAULT_CHAT_FRAME:AddMessage( "|cFFFF8080nUI Debug:|r "..(msg or "<nil>"), 1, 0.83, 0 ); 
		end
	
		table.insert( debug_log, msg );
		
	end
end
