------------------------------------------------
--               CT_BottomBar                 --
--                                            --
-- Breaks up the main menu bar into pieces,   --
-- allowing you to hide and move the pieces   --
-- independently of each other.               --
-- Please do not modify or otherwise          --
-- redistribute this without the consent of   --
-- the CTMod Team. Thank you.                 --
------------------------------------------------

--------------------------------------------
-- Initialization

local module = { };
local _G = getfenv(0);

local MODULE_NAME = "CT_BottomBar";
local MODULE_VERSION = strmatch(GetAddOnMetadata(MODULE_NAME, "version"), "^([%d.]+)");

module.name = MODULE_NAME;
module.version = MODULE_VERSION;

_G[MODULE_NAME] = module;
CT_Library:registerModule(module);

-- Local copies
local type = type;

--------------------------------------------
-- Helper Functions

-- Empty function
local function emptyFunc() end

-- Drag Frame
local addonFrameTable;
local function addonDragSkeleton()
	if ( not addonFrameTable ) then
		addonFrameTable = {
			["button#hidden#i:button#st:LOW"] = {
				"backdrop#tooltip#0:0:0:0.5",
				"font#v:GameFontNormalLarge#i:text",
				["onleave"] = module.hideTooltip,
				["onmousedown"] = function(self, button)
					if ( button == "LeftButton" ) then
						module:moveMovable(self.movable);
					end
				end,
				["onmouseup"] = function(self, button)
					if ( button == "LeftButton" ) then
						module:stopMovable(self.movable);
					elseif ( button == "RightButton" ) then
						self.object:rotate();
					end
				end,
				["onload"] = function(self)
					self:SetBackdropBorderColor(1, 1, 1, 0);
				end,
				["onenter"] = function(self)
					local object = self.object;
					local text = "|c00FFFFFF"..object.name.."|r\n" ..
						"Left click to drag";
					if ( object.rotateFunc ) then
						text = text .. "\nRight click to rotate";
					end
					module:displayTooltip(self, text);
				end
			}
		};
	end
	return "frame#s:30:1", addonFrameTable;
end

local function prepareFrame(frame, parent)
	frame:SetParent(parent);
	frame.superSetPoint = frame.SetPoint;
	frame.superClearAllPoints = frame.ClearAllPoints;
	frame.SetPoint = emptyFunc;
	frame.ClearAllPoints = emptyFunc;
end

--------------------------------------------
-- Addon Handler

local addon = { };
local addonMeta = { __index = addon };

-- List of addons
local addons = { };
module.addons = addons;

function addon:toggleVisibility(mode, show)
	if ( mode == 3 ) then
		local func = MinimapBorder[(show and "Show") or "Hide"];
		local textures = self["textures"];
		if ( type(textures) == "table" ) then
			for key, value in ipairs(textures) do
				func(value);
			end
		elseif ( frames ) then
			func(frames);
		end
	elseif ( mode == 2 ) then
		if ( show ) then
			self.frame.button:Show();
		else
			self.frame.button:Hide();
		end
	elseif ( mode == 1 ) then
		if ( show ) then
			self.frame:Show();
		else
			self.frame:Hide();
		end
	end
end

function addon:rotate()
	if ( not self.rotateFunc or ( UnitAffectingCombat("player") and self.frame:IsProtected() ) ) then return; end
	
	local newOrientation = "ACROSS";
	if ( self.orientation == "ACROSS" ) then
		self.orientation = "DOWN";
		newOrientation = "DOWN";
	else
		self.orientation = "ACROSS";
	end
	module:setOption("orientation"..self.name, newOrientation);
	self:rotateFunc(newOrientation);
	self:update();
end

function addon:position()
	local frame = self.frames;
	if ( not frame[0] ) then
		frame = frame[1];
	end
	
	frame:ClearAllPoints();
	frame:SetPoint("BOTTOMLEFT", self.frame);
end

function addon:update()
	local button = self.frame.button;
	if ( button ) then
		local orientation = self.orientation;
		local name = self.name;	
		local text = button.text;
		
		text:ClearAllPoints();
		if ( orientation == "ACROSS" ) then
			text:SetText(name);
			text:SetPoint("BOTTOMLEFT", button, "TOPLEFT", 10, -11);
		else
			text:SetText(self.shortName);
			text:SetPoint("BOTTOM", button, "TOP", 0, -11);
		end
	end
end

function addon:init()
	local frames = self.frames;	
	if ( frames ) then
		local name = self.name;
		local frame = self.frame;
		local button = frame.button;

		if ( not self.skipDefaultPosition ) then
			self:position();
		end
		
		local defaults = self.defaults;
		if ( defaults ) then
			frame:ClearAllPoints();
			frame:SetPoint(unpack(defaults));
		end
		
		button.object = self;
		button.movable = name;
		module:registerMovable(name, frame);

		-- Keep our frames from moving anywhere we don't want them!
		local guideFrame;
		if ( frames[0] ) then
			guideFrame = frames;
			prepareFrame(frames, frame);
		else
			for key, value in ipairs(frames) do
				prepareFrame(value, frame);
			end
			guideFrame = frames[1];
		end
		
		button:SetPoint("TOPLEFT", guideFrame, -11, 11);
		button:SetPoint("BOTTOMRIGHT", guideFrame, 11, -11);
		
		local orientation = module:getOption("orientation"..name) or "ACROSS";
		local func = self.rotateFunc;
		
		self.orientation = orientation;
		if ( func ) then
			func(self, orientation);
		end
	end
	
	self:update();
end

--------------------------------------------
-- Addon Registrar

function module:registerAddon(name, defaults, initFunc, rotateFunc, ...)
	local new = { };
	new.name = name;
	new.rotateFunc = rotateFunc;
	new.defaults = defaults;
	
	-- Store our frames & textures
	local index = 1;
	if ( rotateFunc ) then
		-- Use first one as the addon's "short name" when rotated
		index = 2;
		new.shortName = (...) or name;
	end
	
	if ( ( (select(index, ...)) or "" ) ~= "" ) then
		-- Add a drag frame only if we have frame
		local frame = module:getFrame(addonDragSkeleton, nil, "CT_BottomBarAddon-"..name);
		new.frame = frame;
	end
	
	if ( initFunc ) then
		new.skipDefaultPosition = initFunc(new);
	end
	
	local key, value = "frames";
	for i = index, select('#', ...), 1 do
		value = select(i, ...);
		if ( value == "" ) then
			-- Constitutes change to textures
			key = "textures";
		else
			if ( type(value) == "string" ) then
				value = new[value];
			end
			
			-- Add our value
			if ( not new[key] ) then
				new[key] = value;
			elseif ( new[key][0] ) then
				new[key] = { new[key], value };
			else
				tinsert(new[key], value);
			end
		end
	end
	
	setmetatable(new, addonMeta);
	tinsert(addons, new);
	return new;
end

local function isDefaultHidden(self)
	local defaults = self.defaults;
	if ( defaults and defaults.perClass ) then
		local _, class = UnitClass("player");
		if ( not defaults[class] ) then
			return true;
		end
	end
	return false;
end

module.update = function(self, type, value)
	if ( type == "init" ) then
		for key, value in ipairs(addons) do
			value:init();
			
			-- Check option for show/hide
			if ( self:getOption(value.name) or isDefaultHidden(value) ) then
				value:toggleVisibility(1, false);
			end
		end
		MainMenuBar:Hide();
		
		self:updateMainBar("barScale", self:getOption("barScale") or 1);
		self:updateMainBar("barOpacity", self:getOption("barOpacity") or 1);
		self:updateMainBar("barSpacing", self:getOption("barSpacing") or 6);
		
		self:updatePetBar("petBarScale", self:getOption("petBarScale") or 1);
		self:updatePetBar("petBarOpacity", self:getOption("petBarOpacity") or 1);
		self:updatePetBar("petBarSpacing", self:getOption("petBarSpacing") or 6);
	else
		if ( type == "barScale" or type == "barOpacity" or type == "barSpacing" ) then
			self:updateMainBar(type, value);
			return;
		elseif ( type == "petBarScale" or type == "petBarOpacity" or type == "petBarSpacing" ) then
			self:updatePetBar(type, value);
			return;
		end
		
		for key, val in ipairs(addons) do
			if ( val.name == type ) then
				val:toggleVisibility(1, not value);
			end
		end
	end
end

-- Options Frame
local function showModules(self)
	for key, value in ipairs(addons) do
		value:toggleVisibility(2, true);
	end
	if ( self and CT_BarMod and CT_BarMod.show ) then
		CT_BarMod.show();
	end
end

local function hideModules(self)
	for key, value in ipairs(addons) do
		value:toggleVisibility(2, false);
	end
	if ( self and CT_BarMod and CT_BarMod.hide ) then
		CT_BarMod.hide();
	end
end

module.show, module.hide = showModules, hideModules;

module.frame = function()
	local options = {
		"font#tl:5:-5#v:GameFontNormalLarge#Modules",
		["onshow"] = showModules,
		["onhide"] = hideModules,
		
		["button#t:b:0:-15#s:170:30#v:GameMenuButtonTemplate#Reset Options to Default"] = {
			["onclick"] = function(self)
				CT_BottomBarOptions = nil;
				ConsoleExec("RELOADUI");
			end
		},
		"font#t:b:0:-45#s:0:40#l#r#(Note: Resetting options to default will reload your UI)#0.5:0.5:0.5",
	};
	
	-- Add to our options
	local count = 0;
	for key, value in ipairs(addons) do
		if ( value.frames ) then
			count = count + 1;
			tinsert(options, "checkbutton#tl:20:-"..(5+20*count).."#o:"..value.name..
				((isDefaultHidden(value) and ":true") or "").."#Hide "..value.name);
		end
	end
	
	options["frame#tl:0:-"..(45+20*count).."#r"] = {
		"font#tl:5:0#v:GameFontNormalLarge#Action Bar Options",
		"slider#t:0:-35#o:barScale:1#i:scale#s:175:17#Bar Scale - <value>#0.25:2:0.05",
		"slider#t:0:-70#o:barOpacity:1#i:opacity#s:175:17#Bar Opacity - <value>#0:1:0.05",
		"slider#t:0:-105#o:barSpacing:6#i:spacing#s:175:17#Bar Spacing - <value>#0:25:1",
	}
	
	options["frame#tl:0:-"..(185+20*count).."#r"] = {
		"font#tl:5:0#v:GameFontNormalLarge#Pet Bar Options",
		"slider#t:0:-35#o:petBarScale:1#i:scale#s:175:17#Bar Scale - <value>#0.25:2:0.05",
		"slider#t:0:-70#o:petBarOpacity:1#i:opacity#s:175:17#Bar Opacity - <value>#0:1:0.05",
		"slider#t:0:-105#o:petBarSpacing:6#i:spacing#s:175:17#Bar Spacing - <value>#0:25:1",
	}
	
	return "frame#all", options;
end