-------------------------------------------------------------------------------
-- Constants
-------------------------------------------------------------------------------

NUM_SPELL_SLOTS = 10;
VERSION = "3.0.3.13"

-------------------------------------------------------------------------------
-- Variables
-------------------------------------------------------------------------------

SHOW_WELCOME = true;
FLOASPECTBAR_BARSETTINGS_DEFAULT = { position = "auto", buttonsOrder = {}, color = { 0, 0.49, 0, 0.7 }, hiddenSpells = {} };
FLOASPECTBAR_OPTIONS_DEFAULT = { scale = 1, borders = true, barSettings = FLOASPECTBAR_BARSETTINGS_DEFAULT };
FLOASPECTBAR_OPTIONS = FLOASPECTBAR_OPTIONS_DEFAULT;

-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------

-- Executed on load, calls general set-up functions
function FloAspectBar_OnLoad(self)

	-- Class-based setup, abort if not supported
	local temp, classFileName = UnitClass("player");
	classFileName = strupper(classFileName);

	classSpells = FLO_ASPECT_SPELLS[classFileName];
	if classSpells == nil then
		return;
	end

	-- Store the spell list for later
	self.availableSpells = classSpells;
	if self.availableSpells == nil then
		return;
	end

	self.spells = {};
	self.SetupSpell = FloAspectBar_SetupSpell;
	self.UpdateState = FloAspectBar_UpdateState;
	self.menuHooks = { SetPosition = FloAspectBar_SetPosition, SetBorders = FloAspectBar_SetBorders };
	self:EnableMouse(1);

	if SHOW_WELCOME then
		DEFAULT_CHAT_FRAME:AddMessage( "FloAspectBar "..VERSION.." loaded." );
		SHOW_WELCOME = nil;

		SLASH_FLOASPECTBAR1 = "/floaspectbar";
		SLASH_FLOASPECTBAR2 = "/fab";
		SlashCmdList["FLOASPECTBAR"] = FloAspectBar_ReadCmd;

		self:RegisterEvent("VARIABLES_LOADED");
	end

	self:RegisterEvent("PLAYER_ENTERING_WORLD");
	self:RegisterEvent("LEARNED_SPELL_IN_TAB");
	self:RegisterEvent("SPELL_UPDATE_COOLDOWN");
	self:RegisterEvent("SPELL_UPDATE_USABLE");
	self:RegisterEvent("UNIT_AURA");
	self:RegisterEvent("UPDATE_BINDINGS");
end

function FloAspectBar_OnEvent(self, event, ...)

	if event == "PLAYER_ENTERING_WORLD" or event == "LEARNED_SPELL_IN_TAB" then
		FloLib_Setup(self);
	elseif event == "VARIABLES_LOADED" then

		-- Copy new variables
		FloLib_CopyPreserve(FLOASPECTBAR_OPTIONS_DEFAULT, FLOASPECTBAR_OPTIONS);
		FloLib_CopyPreserve(FLOASPECTBAR_BARSETTINGS_DEFAULT, FLOASPECTBAR_OPTIONS.barSettings);

		-- Import old variables
		if FLOASPECTBAR_LAYOUT then
			FLOASPECTBAR_OPTIONS.barSettings.position = FLOASPECTBAR_LAYOUT;
		elseif FLOASPECTBAR_OPTIONS.layout then
			FLOASPECTBAR_OPTIONS.barSettings.position = FLOASPECTBAR_OPTIONS.layout;
			FLOASPECTBAR_OPTIONS.layout = nil;
		end
		if FLOASPECTBAR_SCALE then
			FLOASPECTBAR_OPTIONS.scale = FLOASPECTBAR_SCALE;
		end
		if FLOASPECTBAR_BUTTONS_ORDER then
			FLOASPECTBAR_OPTIONS.barSettings.buttonsOrder = FLOASPECTBAR_BUTTONS_ORDER;
		elseif FLOASPECTBAR_OPTIONS.buttonsOrder then
			FLOASPECTBAR_OPTIONS.barSettings.buttonsOrder = FLOASPECTBAR_OPTIONS.buttonsOrder;
			FLOASPECTBAR_OPTIONS.buttonsOrder = nil;
		end
		self.globalSettings = FLOASPECTBAR_OPTIONS;
		self.settings = FLOASPECTBAR_OPTIONS.barSettings;
		FloAspectBar_SetPosition(nil, self, FLOASPECTBAR_OPTIONS.barSettings.position);
		FloAspectBar_SetScale(FLOASPECTBAR_OPTIONS.scale);
		FloAspectBar_SetBorders(nil, FLOASPECTBAR_OPTIONS.borders);

		-- Hook the UIParent_ManageFramePositions function
		hooksecurefunc("UIParent_ManageFramePositions", FloAspectBar_UpdatePosition);
	elseif ( event == "UPDATE_BINDINGS" ) then
		FloLib_UpdateBindings(self, "SHAPESHIFT");
	elseif ( event == "UNIT_AURA" ) then
		local unit = ...;
		if ( unit == PlayerFrame.unit ) then
			FloLib_UpdateState(self);
		end
	else
		FloLib_UpdateState(self);
	end
end

function FloAspectBar_ReadCmd(line)

	local cmd, var = strsplit(' ', line or "");

	if cmd == "scale" and tonumber(var) then
		FloAspectBar_SetScale(var);
	elseif cmd == "lock" or cmd == "unlock" or cmd == "auto" then
		FloAspectBar_SetPosition(FloAspectBar, cmd);
	elseif cmd == "borders" then
		FloAspectBar_SetBorders(true);
	elseif cmd == "noborders" then
		FloAspectBar_SetBorders(false);
	elseif cmd == "panic" or cmd == "reset" then
		FloLib_ResetAddon("FloAspectBar");
	else
		DEFAULT_CHAT_FRAME:AddMessage( "FloAspectBar usage :" );
		DEFAULT_CHAT_FRAME:AddMessage( "/fab lock|unlock : lock/unlock position" );
		DEFAULT_CHAT_FRAME:AddMessage( "/fab borders|noborders : show/hide borders" );
		DEFAULT_CHAT_FRAME:AddMessage( "/fab auto : Automatic positioning" );
		DEFAULT_CHAT_FRAME:AddMessage( "/fab scale <num> : Set scale" );
		DEFAULT_CHAT_FRAME:AddMessage( "/fab panic||reset : Reset FloAspectBar" );
		return;
	end
end

function FloAspectBar_SetupSpell(self, spell, spellID, pos)

	local durationMod = 0;
	local lifeMod = 0;
	local algo, lifeTable;

	-- Avoid tainting
	if not InCombatLockdown() then
		local button, icon, texture;

		button = getglobal(self:GetName().."Button"..pos);
		icon = getglobal(self:GetName().."Button"..pos.."Icon");

		button:SetAttribute("type1", "spell");
		button:SetAttribute("spell", spell.name);

		texture = GetSpellTexture(spellID, BOOKTYPE_SPELL);
		icon:SetTexture(texture);
	end

	self.spells[pos] = { name = spell.name, id = spellID };

end

function FloAspectBar_UpdateState(self, pos)

	local button = getglobal(self:GetName().."Button"..pos);
	local spell = self.spells[pos];

	if UnitAura(PlayerFrame.unit, spell.name, nil, "PLAYER") then
		button:SetChecked(1);
	else
		button:SetChecked(0);
	end
end

function FloAspectBar_UpdatePosition()

	-- Avoid tainting when in combat
	if FLOASPECTBAR_OPTIONS.barSettings.position ~= "auto" or InCombatLockdown() then
		return;
	end

	local yOffset = -3;
	local anchorFrame;

	if not MainMenuBar:IsShown() then
		anchorFrame = "UIParent";
		yOffset = 110-UIParent:GetHeight();
	else
		anchorFrame = "MainMenuBar";
		if ReputationWatchBar:IsShown() and MainMenuExpBar:IsShown() then
			yOffset = yOffset + 9;
		end

		if MainMenuBarMaxLevelBar:IsShown() then
			yOffset = yOffset - 5;
		end

		if SHOW_MULTI_ACTIONBAR_2 then
			yOffset = yOffset + 45;
		end
	end

	FloAspectBar:ClearAllPoints();
	FloAspectBar:SetPoint("BOTTOMLEFT", anchorFrame, "TOPLEFT", 512/FLOASPECTBAR_OPTIONS.scale, yOffset/FLOASPECTBAR_OPTIONS.scale);
end

function FloAspectBar_SetBorders(self, visible)

	FLOASPECTBAR_OPTIONS.borders = visible;
	if visible or FLOASPECTBAR_OPTIONS.barSettings.position == "unlock" then
		FloLib_ShowBorders(FloAspectBar);
	else
		FloLib_HideBorders(FloAspectBar);
	end

end

function FloAspectBar_SetPosition(self, bar, mode)

	local unlocked = (mode == "unlock");

	-- Close all dropdowns
	CloseDropDownMenus();

	bar.settings.position = mode;
	DEFAULT_CHAT_FRAME:AddMessage(bar:GetName().." position "..mode);

	if unlocked then
		FloLib_ShowBorders(bar);
		bar:RegisterForDrag("LeftButton");
	else
		if FLOASPECTBAR_OPTIONS.borders then
			FloLib_ShowBorders(bar);
		else
			FloLib_HideBorders(bar);
		end
	end

	if mode == "auto" then
		-- Force the auto positionning
		FloAspectBar_UpdatePosition(bar);
	end
end

function FloAspectBar_SetScale(scale)

	scale = tonumber(scale);
	if ( not scale or scale <= 0 ) then
		DEFAULT_CHAT_FRAME:AddMessage( "FloAspectBar : scale must be >0 ("..scale..")" );
		return;
	end

	FLOASPECTBAR_OPTIONS.scale = scale;

	local v = FloAspectBar;
	local p, a, rp, ox, oy = v:GetPoint();
	local os = v:GetScale();
	v:SetScale(scale);
	if a == nil or a == UIParent or a == MainMenuBar then
		v:SetPoint(p, a, rp, ox*os/scale, oy*os/scale);
	end

end

-- Returns the name, the texture and active state of an aspect
function FloAspectBar_GetAspectInfo(id)
	for spell,i in pairs(FloAspectBar_FormID) do
		if i == id then
			local texture = GetSpellTexture(FloAspectBar_GetAspectID(spell), BOOKTYPE_SPELL);
			return spell, texture, FloAspectBar_IsAspectActive(texture);
		end
	end
	return nil;
end

-- Returns whether the player has the aspect on or not, based on his buffs
function FloAspectBar_IsAspectActive(texture)
	local id = 0;
	for id = 0, 15 do
		if GetPlayerBuffTexture(id) == texture then
			return true;
		end
	end
	return false;
end
