--[[

AutoBuff -- Automatically casts self-buffs, weapon buffs, tracking abilites, and aspects.
Originally authored by Frosty @ http://www.curse-gaming.com/mod.php?addid=1400

ADOPTED 2005-08 by Dsanai, as Frosty is no longer playing World of Warcraft.
Please direct any suggestions, comments, or blame, to Dsanai. Frosty still deserves the praise, though. :-)

http://membersui.worldofwar.net/ui.php?id=1475
http://www.curse-gaming.com/mod.php?addid=2442
http://www.wowinterface.com/downloads/fileinfo.php?s=&id=4259

FEATURE REQUESTS (Not added yet)
-- Option to not cast while Resting (removed it a while back, add back in with default Off)
-- Option to not cast while in Battlegrounds (check MetaMap for method to test this state)
-- Figure out what changed to make the Expiration flag unknowable (won't cast until spell is gone).

-[ MOST RECENT HISTORY ]-  (For older history, see ReadMe.txt)

v11200-3
-- Fixed error caused by not having Titan installed.

v11200-2
-- Fixed error caused by not having FuBar installed.

v11200-1
-- Updated TOC for Patch 1.12.
-- Added Warlock Life Tap scaling (code from ScaledLifeTap by Kimilly). Requires  BonusScanner mod.
-- Added option to recast Priests' Inner Fire spell at a set number of charges or less (5/20 is default).
-- Added option to change Inner Fire recast charges to anything from 1 to 19 (/ab innercharges <integer>).
-- Removed check for weapons before casting Shaman weapon buffs (fixes tooltip bug). If you're working on your Unarmed skill, disable the selected weapon buff in /autobuff and all will be well.
-- Hid options on Titan and FuBar tooltips if they do not apply to the currently-played character class.

v11100-3b/c
-- Fixed bug introduced by Detect Traps removal.

v11100-3
-- Added FuBar 2+ support.
-- Priest: Will no longer cast while Spirit of Redemption is active (EN,DE,FR clients)
-- Fixed DE Windfury translation (courtesy Helaku@WorldOfWar)
-- Fixed DE Sense Undead translation (courtesy DelphiDie@WorldOfWar)
-- Fixed DE Ice Barrier translation (courtesy DelphiDie@WorldOfWar)
-- Removed Detect Traps (Blizzard passive spell now)

]]

-- Constants
--AUTOBUFF_USAGE_LIST = "/autobuff on|off|toggle|track|weapon|mana\n/autobuff trigger|rebuff|combat|enable|disable|list\n/autobuff hide|resetbutton";
AUTOBUFF_USAGE_LIST = "/autobuff on | off | toggle\n";
AUTOBUFF_USAGE_LIST = AUTOBUFF_USAGE_LIST.."/autobuff track | weapon\n";
AUTOBUFF_USAGE_LIST = AUTOBUFF_USAGE_LIST.."/autobuff mana | trigger | rebuff | combat | enable | disable | list\n";
AUTOBUFF_USAGE_LIST = AUTOBUFF_USAGE_LIST.."/autobuff reset\n";
AUTOBUFF_USAGE_LIST = AUTOBUFF_USAGE_LIST.."/autobuff water | tap | scaled | inner\n";
AUTOBUFF_USAGE_LIST = AUTOBUFF_USAGE_LIST.."/autobuff innercharges <num>\n";
AUTOBUFF_USAGE_LIST = AUTOBUFF_USAGE_LIST.."/autobuff hide | resetbutton\n";
AUTOBUFF_USAGE_LIST = AUTOBUFF_USAGE_LIST.."To Run Autobuff: /autobuff run\n";

BINDING_HEADER_AUTOBUFF = "AutoBuff";

local AUTOBUFF_GUI_ABILITY_TOTALROWS = 43;
local AUTOBUFF_GUI_ABILITY_OVERHEAD = 14;
local AUTOBUFF_GUI_ABILITY_INTERVAL = 18;

cSpellList = {
	[AUTOBUFF_ABILITY_FORTITUDE] =         { ["type"] = "friendly", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_PRAYEROFFORTITUDE) },
	[AUTOBUFF_ABILITY_PWSHIELD] =          { ["type"] = "friendly", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_WEAKENEDSOUL) },
	[AUTOBUFF_ABILITY_INNER_FIRE] =        { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_SHADOW_PROTECTION] = { ["type"] = "friendly", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_PRAYEROFSHADOWPROTECTION) },
	[AUTOBUFF_ABILITY_FEARWARD] =          { ["type"] = "friendly", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_DIVINESPIRIT] =      { ["type"] = "friendly", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_PRAYEROFSPIRIT) },
	[AUTOBUFF_ABILITY_MOTW] =              { ["type"] = "friendly", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_GOTW) },
	[AUTOBUFF_ABILITY_THORNS] =            { ["type"] = "friendly", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_ELUNESGRACE] =       { ["type"] = "self", ["pwt"]=0 },
--	[AUTOBUFF_ABILITY_PRIEST_FEEDBACK] =   { ["type"] = "self", ["pwt"]=0 },  -- akpatch: в общем случае не нужно, действует очень недолго, а cooldown большой
	[AUTOBUFF_ABILITY_LIGHTNING_SHIELD] =  { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_INTELLECT] =         { ["type"] = "friendly", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_ARCANEBRILLIANCE) },
	[AUTOBUFF_ABILITY_MAGE_ARMOR] =        { ["type"] = "self", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_ICE_ARMOR) },
	[AUTOBUFF_ABILITY_ICE_ARMOR] =         { ["type"] = "self", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_MAGE_ARMOR) },
	[AUTOBUFF_ABILITY_FROST_ARMOR] =       { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_MANASHIELD] =        { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_ICEBARRIER] =        { ["type"] = "self", ["pwt"]=0 },
--	[AUTOBUFF_ABILITY_FIREWARD] =          { ["type"] = "self", ["pwt"]=0 }, -- akpatch: неэффективно по сравнению с instant заклинаниями исцеления
--	[AUTOBUFF_ABILITY_FROSTWARD] =         { ["type"] = "self", ["pwt"]=0 }, -- akpatch: неэффективно по сравнению с instant заклинаниями исцеления
	[AUTOBUFF_ABILITY_AMPLIFYMAGIC] =      { ["type"] = "friendly", ["pwt"]=0,   -- akpatch: почему-то запрета замены Dampen -> Amplify не было
	[0] = string.lower(AUTOBUFF_ABILITY_DAMPENMAGIC) },                          -- akpatch: ...
	[AUTOBUFF_ABILITY_DAMPENMAGIC] =       { ["type"] = "friendly", ["pwt"]=0,
	[0] = string.lower(AUTOBUFF_ABILITY_AMPLIFYMAGIC) },
	[AUTOBUFF_ABILITY_DEMON_SKIN] =        { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_DEMON_ARMOR] =       { ["type"] = "self", ["pwt"]=0 },
--[[ akpatch: убрать обнаружение невидимости - не нужно в общем случае
	[AUTOBUFF_ABILITY_DETECT_LINVIS] =     { ["type"] = "friendly", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_DETECT_INVIS] =      { ["type"] = "friendly", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_DETECT_GINVIS] =     { ["type"] = "friendly", ["pwt"]=0 },
]]
	[AUTOBUFF_ABILITY_UNENDING_BREATH] =   { ["type"] = "friendly", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_SOULLINK] =          { ["type"] = "self", ["pwt"]=0 },
--	[AUTOBUFF_ABILITY_SHADOWWARD] =        { ["type"] = "self", ["pwt"]=0 }, -- akpatch: неэффективно по сравнению с instant заклинаниями исцеления
	[AUTOBUFF_ABILITY_TRUESHOTAURA] =      { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_BATTLESHOUT] =       { ["type"] = "self", ["pwt"]=1 },
	[AUTOBUFF_ABILITY_NATURES_GRASP] =     { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_OMENOFCLARITY] =     { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_BARKSKIN] =          { ["type"] = "self", ["pwt"]=0 },
--	[AUTOBUFF_ABILITY_FEINT] =             { ["type"] = "self", ["pwt"]=0 }, -- akpatch: не нужно в соло игре
	[AUTOBUFF_ABILITY_BLADE_FLURRY] =      { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_SHADOWGUARD] =       { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_TOUCHOFWEAKNESS] =   { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_WATER_BREATHING] =   { ["type"] = "friendly", ["pwt"]=0 },
--	[AUTOBUFF_ABILITY_RIGHTFURY] =         { ["type"] = "self", ["pwt"]=0 }, -- akpatch: увеличение threat для паладинов-танков, не нужно для соло игры
	[AUTOBUFF_ABILITY_LIFE_TAP] =          { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_DARK_PACT] =         { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_BERSERKING] =        { ["type"] = "self", ["pwt"]=1 },
--	[AUTOBUFF_ABILITY_FADE] =              { ["type"] = "self", ["pwt"]=0 }, -- akpatch: не нужно в соло игре
--	[AUTOBUFF_ABILITY_COWER] =             { ["type"] = "self", ["pwt"]=0 }, -- akpatch: не нужно в соло игре, да ещё требует Cat Form
	[AUTOBUFF_ABILITY_PERCEPTION] =        { ["type"] = "self" },
	[AUTOBUFF_ABILITY_BLOODFURY] =         { ["type"] = "self", ["pwt"]=1 },
	[AUTOBUFF_ABILITY_REJUV] =             { ["type"] = "friendly", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_RENEW] =             { ["type"] = "friendly", ["pwt"]=0 },
--	[AUTOBUFF_ABILITY_ICEBLOCK] =          { ["type"] = "self", ["pwt"]=0 }, -- akpatch: применять при условии малой жизни и наличия аур HoT
	[AUTOBUFF_ABILITY_BLOODRAGE] =         { ["type"] = "self", ["pwt"]=1 },
	[AUTOBUFF_ABILITY_EVASION] =           { ["type"] = "self", ["pwt"]=3 },
--	[AUTOBUFF_ABILITY_SPRINT] =            { ["type"] = "self", ["pwt"]=3 }, -- akpatch: в общем случае не нужно
	[AUTOBUFF_ABILITY_STONEFORM] =         { ["type"] = "self" },
	[AUTOBUFF_ABILITY_FOCUSEDCASTING] =    { ["type"] = "self", ["pwt"]=0 },
--	[AUTOBUFF_ABILITY_HOLYSHIELD] =        { ["type"] = "self", ["pwt"]=0 }, -- akpatch: пойдёт в скрипт клавиши атаки ближнего боя 
--	[AUTOBUFF_ABILITY_BERSERKERRAGE] =     { ["type"] = "self" }, -- akpatch: применять можно только из Berserker Stance, но проверки в коде нет (надо бы добавить)
	[AUTOBUFF_ABILITY_DIVINEFAVOR] =       { ["type"] = "self", ["pwt"]=0 },
	[AUTOBUFF_ABILITY_COLDBLOOD] =         { ["type"] = "self" },
	};

local cBlessing = {
	[0] = AUTOBUFF_ABILITY_BLESSING_MIGHT,
	[1] = AUTOBUFF_ABILITY_BLESSING_WISDOM,
	[2] = AUTOBUFF_ABILITY_BLESSING_SALVATION,
	[3] = AUTOBUFF_ABILITY_BLESSING_KINGS,
	[4] = AUTOBUFF_ABILITY_BLESSING_SANCTUARY,
	[5] = AUTOBUFF_ABILITY_BLESSING_LIGHT,
}

local cBlessingOther = {
	[0] = AUTOBUFF_ABILITY_BLESSING_FREEDOM,
	[1] = AUTOBUFF_ABILITY_BLESSING_PROTECTION,
}

local cBlessingPoly = {
	[AUTOBUFF_ABILITY_GREATBLESSING_MIGHT] = AUTOBUFF_ABILITY_BLESSING_MIGHT,
	[AUTOBUFF_ABILITY_GREATBLESSING_WISDOM] = AUTOBUFF_ABILITY_BLESSING_WISDOM,
	[AUTOBUFF_ABILITY_GREATBLESSING_SALVATION] = AUTOBUFF_ABILITY_BLESSING_SALVATION,
	[AUTOBUFF_ABILITY_GREATBLESSING_KINGS] = AUTOBUFF_ABILITY_BLESSING_KINGS,
	[AUTOBUFF_ABILITY_GREATBLESSING_SANCTUARY] = AUTOBUFF_ABILITY_BLESSING_SANCTUARY,
	[AUTOBUFF_ABILITY_GREATBLESSING_LIGHT] = AUTOBUFF_ABILITY_BLESSING_LIGHT,
}

local cAura = {
	[0] = AUTOBUFF_ABILITY_AURA_DEVOTION,
	[1] = AUTOBUFF_ABILITY_AURA_RETRIBUTION,
	[2] = AUTOBUFF_ABILITY_AURA_CONCENTRATION,
	[3] = AUTOBUFF_ABILITY_AURA_SHADOWRESIST,
	[4] = AUTOBUFF_ABILITY_AURA_FROSTRESIST,
	[5] = AUTOBUFF_ABILITY_AURA_FIRERESIST,
	[6] = AUTOBUFF_ABILITY_AURA_SANCTITY,
}

local cTrackList = {
--[[ akpatch: убрать способности отслеживания по карте
	[AUTOBUFF_ABILITY_FIND_MINERALS] =   "Spell_Nature_Earthquake",
	[AUTOBUFF_ABILITY_FIND_HERBS] =      "Unknown",
	[AUTOBUFF_ABILITY_SENSE_DEMONS] =    "Spell_Shadow_Metamorphosis",
	[AUTOBUFF_ABILITY_TRACK_BEASTS] =    "Unknown",
	[AUTOBUFF_ABILITY_TRACK_UNDEAD] =    "Unknown",
	[AUTOBUFF_ABILITY_TRACK_HIDDEN] =    "Unknown",
	[AUTOBUFF_ABILITY_TRACK_ELEMENTAL] = "Unknown",
	[AUTOBUFF_ABILITY_TRACK_DEMONS] =    "Unknown",
	[AUTOBUFF_ABILITY_TRACK_GIANTS] =    "Unknown",
	[AUTOBUFF_ABILITY_TRACK_DRAGONKIN] = "Unknown",
	[AUTOBUFF_ABILITY_FIND_TREASURE] =   "Unknown",
	[AUTOBUFF_ABILITY_SENSE_UNDEAD] =    "Unknown",
]]
}; -- 	[AUTOBUFF_ABILITY_TRACK_HUMANOIDS] = "Unknown",
-- Added dynamically now, based on if you're a Druid (goes to cSpellList) or a Hunter (goes to cTrackList).

local cAspectList = {
	[AUTOBUFF_ASPECT_MONKEY] =  "Unknown",
	[AUTOBUFF_ASPECT_HAWK] =    "Unknown",
	[AUTOBUFF_ASPECT_CHEETAH] = "Unknown",
	[AUTOBUFF_ASPECT_PACK] =    "Unknown",
	[AUTOBUFF_ASPECT_WILD] =    "Unknown",
	[AUTOBUFF_ASPECT_BEAST] =   "Unknown",
};

local cSealList = {
--[[ akpatch: убрать печати паладинов
	[AUTOBUFF_ABILITY_SEAL_COMMAND] =  { ["i"] = 1, ["type"] = "self" },
	[AUTOBUFF_ABILITY_SEAL_FURY] =     { ["i"] = 2, ["type"] = "self" },
	[AUTOBUFF_ABILITY_SEAL_JUSTICE] =  { ["i"] = 3, ["type"] = "self" },
	[AUTOBUFF_ABILITY_SEAL_LIGHT] =    { ["i"] = 4, ["type"] = "self" },
	[AUTOBUFF_ABILITY_SEAL_RIGHT] =    { ["i"] = 5, ["type"] = "self" },
	[AUTOBUFF_ABILITY_SEAL_WISDOM] =   { ["i"] = 6, ["type"] = "self" },
	[AUTOBUFF_ABILITY_SEAL_CRUSADER] = { ["i"] = 7, ["type"] = "self" },
]]
};

local cWarlockPet = { ["Lesser Invisibility"] = "Spell_Magic_LesserInvisibilty"; }; -- Beta function. /autobuff succubus

local cWeaponList = {
	[AUTOBUFF_ABILITY_SHAMAN_FLAMETONGUE] = 0,
	[AUTOBUFF_ABILITY_SHAMAN_FROSTBRAND] =  0,
	[AUTOBUFF_ABILITY_SHAMAN_ROCKBITER] =   0,
	[AUTOBUFF_ABILITY_SHAMAN_WINDFURY] =    0,
};

local cPolyList = {
	["all"] = {
		[AUTOBUFF_POLY_ALL_INVISIBILITY] = true,
		[AUTOBUFF_POLY_ALL_LESSERINVISIBILITY] = true,
		[AUTOBUFF_POLY_ALL_SHADOWMELD] = true,
		[AUTOBUFF_POLY_ALL_DRINK] = true,
		[AUTOBUFF_POLY_ALL_FOOD] = true,
		[AUTOBUFF_POLY_ALL_FIRSTAID] = true,
	},
	[string.lower(AUTOBUFF_CLASS_PRIEST)] = {
		[AUTOBUFF_POLY_PRIEST_MINDCONTROL] = true,
		[AUTOBUFF_POLY_PRIEST_SPIRITTAP] = true,
		[AUTOBUFF_POLY_PRIEST_MINDVISION] = true,
		[AUTOBUFF_POLY_PRIEST_INNERFOCUS] = true,
		[AUTOBUFF_POLY_PRIEST_SPIRITOFREDEMPTION] = true,
	},
	[string.lower(AUTOBUFF_CLASS_ROGUE)] = {},
	[string.lower(AUTOBUFF_CLASS_PALADIN)] = {},
	[string.lower(AUTOBUFF_CLASS_WARLOCK)] = {
		[AUTOBUFF_POLY_WARLOCK] = true,
		[AUTOBUFF_POLY_WARLOCK_SOULSIPHON] = true,
	},
	[string.lower(AUTOBUFF_CLASS_WARRIOR)] = {},
	[string.lower(AUTOBUFF_CLASS_HUNTER)] = {},
	[string.lower(AUTOBUFF_CLASS_MAGE)] = {
		[AUTOBUFF_POLY_MAGE] = true,
	},
	[string.lower(AUTOBUFF_CLASS_SHAMAN)] = {
		[AUTOBUFF_POLY_SHAMAN] = true,
	},
	[string.lower(AUTOBUFF_CLASS_DRUID)] = {
		[AUTOBUFF_POLY_DRUID_BEAR] = true,
		[AUTOBUFF_POLY_DRUID_CAT] = true,
		[AUTOBUFF_POLY_DRUID_AQUATIC] = true,
		[AUTOBUFF_POLY_DRUID_TRAVEL] = true,
		[AUTOBUFF_POLY_DRUID_DIREBEAR] = true,
		[AUTOBUFF_POLY_DRUID_MOONKIN] = true,
	}
};

local cDefault = {  -- Default saved settings.
	['e'] = 1,         -- Enabled
	['x'] = {           -- Spell Settings
		['d'] = {          -- Default Settings
			['c'] = 3,        -- Combat
			['h'] = 1,        -- Health
			['m'] = 40,       -- Mana
			['r'] = 10,       -- Rebuff
			['t'] = 0,        -- Hook Trigger  --akpatch: по умолчанию срабатывание только по вызову RunBinding("AUTOBUFF_TRIGGER"), ничего лишнего -- было 126
			['z'] = 1,        -- Class Specific (Stealth/Breath) UNUSED
			['p'] = 3,        -- Party
		},
		[AUTOBUFF_ABILITY_PWSHIELD] = {
			['d'] = 1,
		},
		[AUTOBUFF_ABILITY_ICEBARRIER] = {
			['d'] = 1,
		},
		[AUTOBUFF_ABILITY_BATTLESHOUT] = {
			['m'] = 10,
			['r'] = 5,
		},
--[[ akpatch: неэффективно по сравнению с instant заклинаниями исцеления
		[AUTOBUFF_ABILITY_FIREWARD] = {
			['d'] = 1,
		},
		[AUTOBUFF_ABILITY_FROSTWARD] = {
			['d'] = 1,
		},
]]
		[AUTOBUFF_ABILITY_WATER_BREATHING] = {
			['d'] = 1,
		},
		[AUTOBUFF_ABILITY_TRACK_HUMANOIDS] = {
			['m'] = 1,
		},
		[AUTOBUFF_ABILITY_LIFE_TAP] = {
			['m'] = -40, -- < 40% mana
			['h'] = 80, -- > 80% health
		},
		[AUTOBUFF_ABILITY_BERSERKING] = {
			['c'] = 1, -- IN Combat
			['h'] = -70, -- < 70% health
		},
		[AUTOBUFF_ABILITY_FADE] = {
			['c'] = 1, -- IN Combat
		},
	},
	['z'] = 0,
	['v'] = "11200-3",  -- VERSION
	['b'] = true, -- Button visibility
	["water"] = true, -- Warlock/Shaman Underwater 30-second trap (ON by default)
	["tap"] = true, -- Prevent casting while Spirit Tap / Soul Siphon are active (ON by default)
	["scaled"] = true, -- Warlock Life Tap scaling based on Item Bonuses (ON by default)
	["inner"] = true, -- Inner Fire casts at XX/20 charges (ON by default)
	["innercharges"] = 5, -- Number of charges (between 1 and 19) (5 by default)
};

local cSheep = "Spell_Nature_Polymorph";
local cEnslave = "Spell_Shadow_EnslaveDemon";
local cBanish = "Spell_Shadow_Cripple";
local cTracking = "Ability_Tracking";
local cStealth = "Ability_Stealth";
local cPre = "Interface\\Icons\\";
local cTime = 1000;
local cIconOn = "Interface\\AddOns\\AutoBuff\\ABEnabled";
local cIconOff = "Interface\\AddOns\\AutoBuff\\ABDisabled";
local cIconInnerFire = "Interface\\Icons\\Spell_Holy_InnerFire";

-- Used for the table index finder function.
local bIndex = nil;
local bValue = nil;

-- Used for LifeTap Scaling
local overtapEnabled = true;
local AFFLICTION_TAB = 1;
local IMP_LIFETAP_ID = 5;
local RANK_MULTIPLIER = {0.38,0.68,0.8,0.8,0.8,0.8};
local BASE_DAMAGE = {30,75,140,220,310,424};

-- Temp variables.
local vSit = 0;
local vBreath = 0;
local vRestingAlertTimer = 0;
local vError = {};
local vGUI = {};
local vTime = 0;
local vRejuv = 0;
local vRenew = 0;
local vTrack = nil;
local vWeapon = nil;
local vAspect = nil;
local vSeal = nil;
local vClass = nil;
local vSpellList = { };
local sSpellList = { };
local vTrackList = { };
local vAspectList = { };
local vSealList = { };
local vWeaponList = { };
local vC = nil;
local vLoaded = nil;
local vLoaded = {
	var = false;
	player = false;
	autobuff = false;
};
local vCombat = nil;
local AutoBuff_MFSx, AutoBuff_MBSx, AutoBuff_MLSx, AutoBuff_MRSx, AutoBuff_SRSx, AutoBuff_SLSx, AutoBuff_TARx, AutoBuff_TASx, AutoBuff_TAFx, AutoBuffCMSx, AutoBuff_CMFx, AutoBuff_WHEELUx, AutoBuff_WHEELDx, AutoBuff_TARGETx;

-- Titan Variables
TITAN_AUTOBUFF_ID =  "AutoBuff";
TITAN_AUTOBUFF_DESC =  "Auto-casts self-buffs, weapon buffs, tracking abilites, aspects, and seals.";
TITAN_AUTOBUFF_MENU_TEXT = "AutoBuff";
TITAN_AUTOBUFF_BUTTON_LABEL =  "AutoBuff";
TITAN_AUTOBUFF_TOOLTIP = "AutoBuff v"..cDefault['v'];
TITAN_AUTOBUFF_ICON_ON = "Interface\\AddOns\\AutoBuff\\ABEnabled";
TITAN_AUTOBUFF_ICON_OFF = "Interface\\AddOns\\AutoBuff\\ABDisabled";
TITAN_AUTOBUFF_ENABLE = "Enable AutoBuff";
TITAN_AUTOBUFF_BUTTONSHOW = "Show UI Button";
TITAN_AUTOBUFF_BUTTONRESET = "Reset UI Button";
TITAN_AUTOBUFF_DEBUG = "Debug Mode";
TITAN_AUTOBUFF_WATER = "Wait 30s to cast WaterBreathing";
TITAN_AUTOBUFF_TAP = "Off while Spirit Tap or Soul Siphon active";
TITAN_AUTOBUFF_SCALED = "Warlock Life Tap scaling (w/BonusScanner)";
TITAN_AUTOBUFF_INNER = "Priest Inner Fire casts at XX charges left";
TitanAutoBuffStates = {};
TitanAutoBuffStates.Enabled = nil;
TitanAutoBuffStates.Button = nil;
TitanAutoBuffStates.Debug = nil;
TitanAutoBuffStates.Water = nil;
TitanAutoBuffStates.Tap = nil;
TitanAutoBuffStates.Scaled = nil;
TitanAutoBuffStates.Inner = nil;
TITAN_AUTOBUFF_TOOLTIP_CONTENTS = "";
local u = {};

-- AutoBuffOptionsButton functions
local AutoBuffOptionsButton_BeingDragged = false;

function AutoBuffOptionsButton_OnLoad()
   	this:RegisterForClicks("LeftButtonUp", "RightButtonUp");
   	this:RegisterForDrag("LeftButton");
end

function AutoBuffOptionsButton_OnClick(arg1)
	if (arg1 == "LeftButton") then
		-- Open Options Window
		AutoBuffFrame_Toggle();
	elseif (arg1 == "RightButton") then
		-- Toggle on/off status
		AutoBuffToggle();
	end
end

function AutoBuffToggle()
	if (AutoBuff_Data[vC]['e'] == 1) then
		AutoBuff_Off();
	else
		AutoBuff_On();
	end
end

function AutoBuffDebug()
	if (AutoBuff_Data[vC]['d']) then
		AutoBuff_Data[vC]['d'] = nil;
		AutoBuff_Print("Debug is now off.");
		TitanAutoBuffStates.Debug = nil;
	else
		AutoBuff_Data[vC]['d'] = 1;
		AutoBuff_Print("Debug is now on.");
		TitanAutoBuffStates.Debug = 1;
	end
end

function AutoBuffWaterToggle()
	if (AutoBuff_Data[vC]["water"]) then
		AutoBuff_Data[vC]["water"] = false;
		AutoBuff_Print("Underwater Breathing spells will ignore swim timers.");
		TitanAutoBuffStates.Water = nil;
	else
		AutoBuff_Data[vC]["water"] = true;
		AutoBuff_Print("Underwater Breathing spells will require 30 seconds underwater time before casting (Default Behavior).");
		TitanAutoBuffStates.Water = 1;
	end
end

function AutoBuffTapToggle()
	if (AutoBuff_Data[vC]["tap"]) then
		AutoBuff_Data[vC]["tap"] = false;
		AutoBuff_Print("Will now cast spells while Spirit Tap or Soul Siphon are active.");
		TitanAutoBuffStates.Tap = nil;
	else
		AutoBuff_Data[vC]["tap"] = true;
		AutoBuff_Print("Will not cast spells while Spirit Tap or Soul Siphon are active (Default Behavior).");
		TitanAutoBuffStates.Tap = 1;
	end
end

function AutoBuffScaledToggle()
	if (AutoBuff_Data[vC]["scaled"]) then
		AutoBuff_Data[vC]["scaled"] = false;
		AutoBuff_Print("Warlock Life Tap spell will ignore scaling routines.");
		TitanAutoBuffStates.Scaled = nil;
	else
		AutoBuff_Data[vC]["scaled"] = true;
		if (IsAddOnLoaded("BonusScanner")) then
			AutoBuff_Print("Warlock Life Tap spell will be scaled for efficiency (Default Behavior).");
		else
			AutoBuff_Print("Warlock Life Tap scaling is dependent on BonusScanner. You must have that mod loaded before scaling will work.");
		end
		TitanAutoBuffStates.Scaled = 1;
	end
end

function AutoBuffInnerToggle()
	if (AutoBuff_Data[vC]["inner"]) then
		AutoBuff_Data[vC]["inner"] = false;
		AutoBuff_Print("Inner Fire will only cast when totally removed (or recast timer is up).");
		TitanAutoBuffStates.Inner = nil;
	else
		AutoBuff_Data[vC]["inner"] = true;
		AutoBuff_Print("Inner Fire will cast when "..AutoBuff_Data[vC]["innercharges"].." charges are left (Default Behavior).");
		TitanAutoBuffStates.Inner = 1;
	end
end

function AutoBuffOptionsButton_OnDragStart()
	if (not AutoBuffOptionsButton_BeingDragged) then
		this:StartMoving();
		AutoBuffOptionsButton_BeingDragged = true;
	end
end

function AutoBuffOptionsButton_OnDragStop()
	if (AutoBuffOptionsButton_BeingDragged) then
		this:StopMovingOrSizing()
		AutoBuffOptionsButton_BeingDragged = false;
	end
end

local function AutoBuff_ScaledLifeTap_GetLifeTapMultiplier()
  local name,iconPath,tier,column,rank = GetTalentInfo(AFFLICTION_TAB, IMP_LIFETAP_ID);
  local multiplier = 1;
  if (name == AUTOBUFF_ABILITY_LIFE_TAP_TALENT) then
    if rank == 1 then
      multiplier = 1.1;
    elseif rank == 2 then
      multiplier = 1.2;
    end
  else
    AutoBuff_Debug("Talent tree has changed.  Cannot determine Improved Life Tap Rank. Assuming 0 ranks.");
  end
  return multiplier;
end

local function AutoBuff_ScaledLifeTap_GetMaxLifeTapRank()
  local rank = 0;
  local count = 1;
  local foundSpell = false;
    
  while true do
    local spellName, spellRank = GetSpellName(count, BOOKTYPE_SPELL);

    if spellName == AUTOBUFF_ABILITY_LIFE_TAP then
      startPos,endPos,rank = string.find(spellRank, AUTOBUFF_SCALEDLIFETAP_RANKREGEXP);
      foundSpell = true;
    else
      if foundSpell then
        break;
      end
    end
    count = count + 1;
  end 
    
  AutoBuff_Debug("Highest rank of Life Tap is " .. rank);
  return rank;
end

local function AutoBuff_ScaledLifeTap_GetDamageBonus()
  local damageBonus = 0;
	local sentDebug = false;
  if IsAddOnLoaded("BonusScanner") then
    damageBonus = BonusScanner:GetBonus("SHADOWDMG") + BonusScanner:GetBonus("DMG");
	else
		AutoBuff_Debug("BonusScanner is not loaded.");
		sentDebug = true;
  end
  if (not sentDebug) then AutoBuff_Debug("BonusScanner reports total shadow damage bonus as: " .. damageBonus); end
	return damageBonus;
end

function AutoBuff_ScaledLifeTap_CastLifeTap()
  local damageModifier = AutoBuff_ScaledLifeTap_GetDamageBonus();
  local lifetapMultiplier = AutoBuff_ScaledLifeTap_GetLifeTapMultiplier();
  local maxRank = AutoBuff_ScaledLifeTap_GetMaxLifeTapRank();
  local castSpell = false;
  
  for i=maxRank,1,-1 do 
    if ((i == 1 and overtapEnabled and (UnitManaMax("player") ~= UnitMana("player")))) or ((UnitHealth("player")>=BASE_DAMAGE[i]+RANK_MULTIPLIER[i]*damageModifier and (UnitManaMax("player")-UnitMana("player")>=(BASE_DAMAGE[i]+RANK_MULTIPLIER[i]*damageModifier)*lifetapMultiplier))) then 
      CastSpellByName(AUTOBUFF_ABILITY_LIFE_TAP .. "(" .. AUTOBUFF_LIST_RANK .. " "..i..")");
      AutoBuff_Debug("Casting Scaled Life Tap (Rank " .. i .. ")");  
      castSpell = true;
      break;
    end
  end
  
  if not castSpell then
    AutoBuff_Debug("Canceling Life Tap (it isn't needed right now).");
  end
end

-- myAddOns Support
AutoBuff_myAddOns = {
	name = 'AutoBuff',
	description = 'Auto-self buff',
	version = cDefault['v'],
	author = 'Dsanai',
	category = MYADDONS_CATEGORY_CLASS,
	frame = '_AutoBuff',
	optionsframe = 'AutoBuffFrame'
};

UIPanelWindows["AutoBuffFrame"] = {area = "center", pushable = 0};

function AutoBuff_OnLoad()
	this:RegisterEvent("UNIT_NAME_UPDATE");
	this:RegisterEvent("PLAYER_ENTERING_WORLD");
	this:RegisterEvent("VARIABLES_LOADED");
	this:RegisterEvent("PLAYER_REGEN_ENABLED");
	this:RegisterEvent("PLAYER_REGEN_DISABLED");
	this:RegisterEvent("LEARNED_SPELL_IN_TAB");
	this:RegisterEvent("UI_ERROR_MESSAGE");
	this:RegisterEvent("MIRROR_TIMER_START");
	this:RegisterEvent("MIRROR_TIMER_STOP");
	this:RegisterEvent("PLAYER_TARGET_CHANGED");
	
	SlashCmdList["AUTOBUFF"] = AutoBuff_SlashHandler;
	SLASH_AUTOBUFF1 = "/autobuff";
	SLASH_AUTOBUFF2 = "/ab";
	
	-- Fubar Includes
	if (IsAddOnLoaded("FuBar")) then
		FuBarAutoBuff_OnLoad();
	end

	-- AutoBuff_MFSx = MoveForwardStart;		-- [Start] These hook the movement functions.
	-- AutoBuff_MBSx = MoveBackwardStart;
	-- AutoBuff_TLSx = TurnLeftStart;
	-- AutoBuff_TRSx = TurnRightStart;
	-- AutoBuff_SLSx = StrafeLeftStart;
	-- AutoBuff_SRSx = StrafeRightStart;
	-- AutoBuff_MFFx = MoveForwardStop;		-- [Stop]
	-- AutoBuff_MBFx = MoveBackwardStop;
	-- AutoBuff_TLFx = TurnLeftStop;
	-- AutoBuff_TRFx = TurnRightStop;
	-- AutoBuff_SLFx = StrafeLeftStop;
	-- AutoBuff_SRFx = StrafeRightStop;
	-- AutoBuff_TARx = ToggleAutoRun;			-- [ToggleAutorun]
	
	-- AutoBuff_TASx = TurnOrActionStart;
	-- AutoBuff_TAFx = TurnOrActionStop;
	--AutoBuff_CMSx = CameraOrSelectOrMoveStart;
	--AutoBuff_CMFx = CameraOrSelectOrMoveStop;
	
	--AutoBuff_JMPx = Jump;
	
	--Jump = AutoBuff_JMP;
	-- MoveForwardStart = AutoBuff_MFS;
	-- MoveBackwardStart = AutoBuff_MBS;
	-- TurnLeftStart = AutoBuff_TLS;
	-- TurnRightStart = AutoBuff_TRS;
	-- StrafeLeftStart = AutoBuff_SLS;
	-- StrafeRightStart = AutoBuff_SRS;
	-- MoveForwardStop = AutoBuff_MFF;
	-- MoveBackwardStop = AutoBuff_MBF;
	-- TurnLeftStop = AutoBuff_TLF;
	-- TurnRightStop = AutoBuff_TRF;
	-- StrafeLeftStop = AutoBuff_SLF;
	-- StrafeRightStop = AutoBuff_SRF;
	-- ToggleAutoRun = AutoBuff_TAR;
	-- TurnOrActionStart = AutoBuff_TAS;
	-- TurnOrActionStop = AutoBuff_TAF;
	--CameraOrSelectOrMoveStart = AutoBuff_CMS;
	--CameraOrSelectOrMoveStop = AutoBuff_CMF;
	
	AutoBuff_WHEELUx = CameraZoomIn;
	AutoBuff_WHEELDx = CameraZoomOut;
	CameraZoomIn  = AutoBuff_WHEELU;
	CameraZoomOut = AutoBuff_WHEELD;	

	if ButtonHole then -- ButtonHole support (did it like author said, but don't think it works)
		ButtonHole.application.RegisterMod({id='AutoBuffEmerald1800', name='AutoBuff',tooltip='Automatically casts self-buffs, weapon buffs, tracking abilites, and aspects.',buttonFrame='AutoBuffOptionsButton',updateFunction='AutoBuffOptionsButton_OnDragStart'});
	end
	
	u = Utility_Class:New();
	
end

function AutoBuff_ZMI(arg1)
	AutoBuff_Check(0);
	AutoBuff_ZMIx(arg1);
end

function AutoBuff_ZMO(arg1)
	AutoBuff_Check(0);
	AutoBuff_ZMOx(arg1);
end

function AutoBuff_OnEvent(event)

    if event == "PLAYER_ENTERING_WORLD" and not AutoBuff_InitOnce then
       AutoBuff_TableConfig();	
       AutoBuff_PaladinSetup();

       -- Apply INDEX numbers to the cSpellList (add element to each, named ["i"] = #
       local indexAssignment = 1;
       for key, value in cSpellList do
           cSpellList[key]["i"] = indexAssignment;
           indexAssignment = indexAssignment + 1;
           --AutoBuff_Print("cSpellList INDEXING: "..key.." to "..indexAssignment);
       end
       AutoBuff_InitOnce = true
    end

	if (event == "UNIT_NAME_UPDATE" and arg1 == "player") or (event == "PLAYER_ENTERING_WORLD") then
		if (vLoaded.autobuff ~= true) then
			vLoaded.player = true;
		end
		
	elseif (event == "VARIABLES_LOADED") then
		vLoaded.var = true;
		if (myAddOnsFrame_Register) then
			myAddOnsFrame_Register(AutoBuff_myAddOns);
		elseif (myAddOnsFrame) then
			myAddOnsList.AutoBuff = AutoBuff_myAddOns;
		end
		
	elseif (event == "PLAYER_TARGET_CHANGED") then
		--AutoBuff_Check(0);
		AutoBuff_TARGET();

	elseif (event == "PLAYER_REGEN_ENABLED") then
		vCombat = nil;
	
	elseif (event == "PLAYER_REGEN_DISABLED") then
		vCombat = true;
	
	elseif (event == "LEARNED_SPELL_IN_TAB") then
		AutoBuff_Reload();
	
	elseif (event == "MIRROR_TIMER_START" and arg6=="Breath") then
		--AutoBuff_Debug("---MirrorTimerStart with arg6="..arg6);
		vBreath = time() +30;
		
	elseif (event == "MIRROR_TIMER_STOP") then
		--AutoBuff_Debug("---MirrorTimerStop");
		vBreath = 0;
		
	elseif (event == "UI_ERROR_MESSAGE") then
		if (arg1 == SPELL_FAILED_AURA_BOUNCED) then
			vTime = time() + 30; end -- A more powerful spell is already active
		if (arg1 == SPELL_FAILED_ONLY_OUTDOORS) then
			vTime = time() + 30; end -- Nature's Grasp trap
		if (arg1 == SPELL_FAILED_SILENCED) then
			vTime = time() + 5; end -- Silenced
		if (arg1 == SPELL_FAILED_REAGENTS) then
			vTime = time() + 30; end -- Out of regeant(s)
		if (arg1 == SPELL_FAILED_MAINHAND_EMPTY) then
			vTime = time() + 30; end -- No main-hand weapon
		if (arg1 == SPELL_FAILED_NOT_STANDING) then
			vSit = time() + 5; end
			
	end
	
	if (vLoaded.player) and (vLoaded.var) and (vLoaded.autobuff ~= true) then
		-- Only load when Character + Vars are loaded
		
		-- Expand Trigger text on GUI if using french locale.
		if (GetLocale() == "frFR") then
			AutoBuffFrameOptionsTrigger_Text:SetWidth(AutoBuffFrameOptionsTrigger_Text:GetWidth() +40);
		end
		
		local vServer = GetCVar("realmName");
		local vPlayer = UnitName("player");
	
		vClass = string.lower(UnitClass("player"));

		-- Можно отредактировать SavedVariables\AutoBuff.lua, добавив туда
		-- копию отдельных настроек для конкретного класса
		for _,class in ipairs{vClass, "", AUTOBUFF_CLASS_HUNTER,AUTOBUFF_CLASS_SHAMAN,AUTOBUFF_CLASS_PALADIN,AUTOBUFF_CLASS_DRUID,AUTOBUFF_CLASS_WARLOCK,AUTOBUFF_CLASS_PRIEST,AUTOBUFF_CLASS_MAGE,AUTOBUFF_CLASS_ROGUE,AUTOBUFF_CLASS_WARRIOR, ""} do
		  local t = ""
		  if class ~= "" then
		     class = string.lower(class)
		     t = "("..class..")"
		  end
          vC = vPlayer..t.." of "..vServer;
          if AutoBuff_Data == nil then break end
          local data = AutoBuff_Data[vC]   -- Stores character+class specific saved variables
		  --print("AutoBuff:", vC, data)
		  if data ~= nil then
		     if class ~= "" and class ~= vClass then
                vC = vPlayer.."("..vClass..") of "..vServer;
		        AutoBuff_Data[vC] = data
		        --print("AutoBuff copies from", class)
		     end
		     break
		  end
		end

--[[ akpatch: убрать способности отслеживания по карте
		if (vClass == string.lower(AUTOBUFF_CLASS_DRUID)) then -- fix Druid Track Humanoids setup
			if not cSpellList[AUTOBUFF_ABILITY_TRACK_HUMANOIDS] then
				cSpellList[AUTOBUFF_ABILITY_TRACK_HUMANOIDS] = { ["i"] = table.getn(cSpellList)+1, ["type"] = "self" };
			end
		elseif (vClass == string.lower(AUTOBUFF_CLASS_HUNTER)) then
			--table.insert(cTrackList, AUTOBUFF_ABILITY_TRACK_HUMANOIDS);
			if not cTrackList[AUTOBUFF_ABILITY_TRACK_HUMANOIDS] then
				cTrackList[AUTOBUFF_ABILITY_TRACK_HUMANOIDS] = "Unknown";
			end
		end
]]

		AutoBuff_LoadDefaults(); 			-- Check SavedVariables against defaults,
								-- if any missing entries, defaults for those entries are loaded
		AutoBuff_TableConfig();				-- table.setn's the 3 constant tables, cSpellList, cTrackList and cWeaponList
		
		-- Fix my ['w'] vs. ['water'] screw-up
		if (AutoBuff_Data[vC]['w']==true or not AutoBuff_Data[vC]['w']) then
			AutoBuff_Data[vC]['w'] = "off";
		end

		AutoBuff_Reload();				-- Next we run through the constant tables for list of spells,
								-- and create temporary ones that have just those that are truly available
		
		if (cPolyList[vClass] == nil) then
			AutoBuff_Print("Your language is not supported!");
		else
			vLoaded.autobuff = true; 			-- Loading complete.
			AutoBuff_Debug("AutoBuff Loaded.");
		end
		
		if (AutoBuff_Data[vC]['b']) then -- Set Button Visibility State
			AutoBuffOptionsButton:Show();
			TitanAutoBuffStates.Button = 1;
		else
			AutoBuffOptionsButton:Hide();
			TitanAutoBuffStates.Button = nil;
		end
		
		if (AutoBuff_Data[vC]['d']) then -- Set Debug State
			TitanAutoBuffStates.Debug = 1;
		else
			TitanAutoBuffStates.Debug = nil;
		end

		if (AutoBuff_Data[vC]["water"]) then -- Set Water State
			TitanAutoBuffStates.Water = 1;
		else
			TitanAutoBuffStates.Water = nil;
		end

		if (AutoBuff_Data[vC]["tap"]) then -- Set Spirit Tap Block State
			TitanAutoBuffStates.Tap = 1;
		else
			TitanAutoBuffStates.Tap = nil;
		end

		if (AutoBuff_Data[vC]["scaled"]) then -- Set Life Tap Scaling State
			TitanAutoBuffStates.Scaled = 1;
		else
			TitanAutoBuffStates.Scaled = nil;
		end

		if (AutoBuff_Data[vC]["inner"]) then -- Set Inner Fire recast State
			TitanAutoBuffStates.Inner = 1;
		else
			TitanAutoBuffStates.Inner = nil;
		end

		if (AutoBuff_Data[vC]["innercharges"]) then -- Set Inner Fire recast charges
			TITAN_AUTOBUFF_INNER = "Priest Inner Fire casts at "..AutoBuff_Data[vC]["innercharges"].." charges left";
		else
			AutoBuff_Data[vC]["innercharges"] = cDefault["innercharges"];
			TITAN_AUTOBUFF_INNER = "Priest Inner Fire casts at "..AutoBuff_Data[vC]["innercharges"].." charges left";
		end
		if (IsAddOnLoaded("FuBar")) then AutoBuffFu:Update(); end

		if (AutoBuff_Data[vC]['e'] == 1) then -- Fix button texture based on On/Off state
			AutoBuffOptionsButton:SetNormalTexture(cIconOn);
			AutoBuffOptionsButton:SetPushedTexture(cIconOff);
			if (AutoBuffFu) then
				AutoBuffFu:SetIcon(TITAN_AUTOBUFF_ICON_ON..".tga");
			end
			if (IsAddOnLoaded("Titan")) then
				local button = TitanUtils_GetButton(TITAN_AUTOBUFF_ID, true);
				if (button) then
					button.registry.icon = TITAN_AUTOBUFF_ICON_ON;
					TitanPanelButton_UpdateButton(TITAN_AUTOBUFF_ID);
				end
				--TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\t"..TitanUtils_GetColoredText("", u.ColorList[string.lower("yellow")]).."\n";
			end
			TitanAutoBuffStates.Enabled = 1;
		else
			AutoBuffOptionsButton:SetNormalTexture(cIconOff);
			AutoBuffOptionsButton:SetPushedTexture(cIconOn);
			if (AutoBuffFu) then
				AutoBuffFu:SetIcon(TITAN_AUTOBUFF_ICON_OFF..".tga");
			end
			if (IsAddOnLoaded("Titan")) then
				local button = TitanUtils_GetButton(TITAN_AUTOBUFF_ID, true);
				if (button) then
					button.registry.icon = TITAN_AUTOBUFF_ICON_OFF;
					TitanPanelButton_UpdateButton(TITAN_AUTOBUFF_ID);
				end
				--TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\t"..TitanUtils_GetColoredText("", u.ColorList[string.lower("yellow")]).."\n";
			end
			TitanAutoBuffStates.Enabled = nil;
		end
		
	end
	--UpdateABClickyBox();
end

function AutoBuff_Trigger(spell)
	local n = AutoBuff_Option(spell, 't');
	if (n == nil) then n = AutoBuff_Option('d', 't'); end
	local i,t; local z = { 0, 0, 0, 0, 0, 0 };
	for i=6,1,-1 do
		t = n - 2^i;
		if (t >= 0) then
			n = t; z[i] = 1;
		end
		if (n == 0) then
			break; end
		end
	--	forward, strafe, turn, lmb, rmb
	AutoBuff_Debug("["..z[1]..", "..z[2]..", "..z[3]..", "..z[4]..", "..z[5]..", "..z[6].."]");
	return z;
end

function AutoBuff_On()
	AutoBuff_Data[vC]['e'] = 1;
	AutoBuff_Print(AUTOBUFF_ENABLED);
	AutoBuffOptionsButton:SetNormalTexture(cIconOn);
	AutoBuffOptionsButton:SetPushedTexture(cIconOff);
	if (AutoBuffFu) then
		AutoBuffFu:SetIcon(TITAN_AUTOBUFF_ICON_ON..".tga");
	end
	-- Change Titan icon, if applicable
	if (IsAddOnLoaded("Titan")) then
		local button = TitanUtils_GetButton(TITAN_AUTOBUFF_ID, true);
		if (button) then
			button.registry.icon = TITAN_AUTOBUFF_ICON_ON;
			TitanPanelButton_UpdateButton(TITAN_AUTOBUFF_ID);
		end
		--TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\t"..TitanUtils_GetColoredText("", u.ColorList[string.lower("yellow")]).."\n";
	end
	TitanAutoBuffStates.Enabled = 1;
end

function AutoBuff_Off()
	AutoBuff_Data[vC]['e'] = 0;
	AutoBuff_Print(AUTOBUFF_DISABLED);
	AutoBuffOptionsButton:SetNormalTexture(cIconOff);
	AutoBuffOptionsButton:SetPushedTexture(cIconOn);
	if (AutoBuffFu) then
		AutoBuffFu:SetIcon(TITAN_AUTOBUFF_ICON_OFF..".tga");
	end
	-- Change Titan icon, if applicable
	if (IsAddOnLoaded("Titan")) then
		local button = TitanUtils_GetButton(TITAN_AUTOBUFF_ID, true);
		if (button) then
			button.registry.icon = TITAN_AUTOBUFF_ICON_OFF;
			TitanPanelButton_UpdateButton(TITAN_AUTOBUFF_ID);
		end
		--TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\t"..TitanUtils_GetColoredText("", u.ColorList[string.lower("yellow")]).."\n";
	end
	TitanAutoBuffStates.Enabled = nil;
end

function AutoBuff_HideButton() -- toggle
	if (AutoBuff_Data[vC]['b']) then
		AutoBuff_Data[vC]['b'] = false;
		AutoBuffOptionsButton:Hide();
		AutoBuff_Print(AUTOBUFF_BUTTON_HIDDEN);
		TitanAutoBuffStates.Button = nil;
	else
		AutoBuff_Data[vC]['b'] = true;
		AutoBuffOptionsButton:Show();
		AutoBuff_Print(AUTOBUFF_BUTTON_SHOWN);
		TitanAutoBuffStates.Button = 1;
	end
end

function AutoBuff_ResetButton() -- reset position
	AutoBuffOptionsButton:ClearAllPoints();
	AutoBuffOptionsButton:SetPoint("CENTER", "UIParent", "TOPRIGHT", -32, -147); --akpatch: set Button position by default
	AutoBuff_Data[vC]['b'] = true;
	AutoBuffOptionsButton:Show();
	TitanAutoBuffStates.Button = 1;
end

function AutoBuff_SlashHandler(msg)

	-- Thanks to AutoRepair for this wicked seperator :)
	if (msg) then msg = string.lower(msg); end
	local _,_,c,p = string.find(msg,"([%w%p]+)%s*(.*)$");
	
	if (c == "on") then
		AutoBuff_On();
		
	elseif (c == "off") then
		AutoBuff_Off();
		
	elseif (c == "hide") then
		AutoBuff_HideButton();
		
	elseif (c == "resetbutton") then
		AutoBuff_ResetButton();
		
	elseif (c == "toggle") then
		if (p) and (strlen(p) > 0) then
			if (vSpellList[p]) then
				local g = 1;
				if (AutoBuff_Option(p, 'd') == 1) then g = "default"; end
				AutoBuff_Option(p, 'd', g, 1);
				if (AutoBuff_IsBlessing(p)) then AutoBuff_FixBlessing(p); end if (AutoBuff_IsAura(p)) then AutoBuff_FixAura(p); end
			elseif (vWeaponList[p]) then
				if (vWeapon == p) then p = "off"; end
				AutoBuff_Data[vC]['w'] = p;
				AutoBuff_WeaponLoad("show")
			else AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, p)); end
		else
			if (AutoBuff_Data[vC]['e'] == 1) then
				AutoBuff_Off();
			else
				AutoBuff_On();
			end
		end
		
	elseif (c == "debug") then
		AutoBuffDebug();
		
	elseif (c == "water") then
		AutoBuffWaterToggle();
		
	elseif (c == "tap") then
		AutoBuffTapToggle();
	
	elseif (c == "scaled") then
		AutoBuffScaledToggle();
		
	elseif (c == "inner") then
		AutoBuffInnerToggle();
		
	elseif (c == "checkbuffs") or (c == "check") or (c == "run") then
		AutoBuff_Check(0);
		
	elseif (c == "reset") then
		if (p == "confirm") then
			AutoBuff_Data[vC] = nil;
			AutoBuff_LoadDefaults();
			AutoBuff_Reload();
			AutoBuff_Print(AUTOBUFF_RESET);
		else
			AutoBuff_Print(AUTOBUFF_RESET_CONFIRM);
		end
		
	elseif (c == "rank") then
		local _,_,v,a = string.find(p,"([%w%p]+)%s*(.*)$");
		if (v) and (strlen(v) > 0) and ((v == "default") or ((tonumber(v)) and (tonumber(v) > 0) and (tonumber(v) < 20))) then
			if (v ~= "default") then v = math.floor(tonumber(v)); end
			if (not a) or (strlen(a) == 0) then a = "none"; end
			if (not vSpellList[a]) and (not vWeaponList[a]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, a));
			elseif (v == "default") or ((vSpellList[a]) and (vSpellList[a]['k']) and (v <= vSpellList[a]['k'])) or ((vWeaponList[a]) and (vWeaponList[a] ~= true) and (v <= vWeaponList[a])) or ((vSealList[a]) and (vSealList[a]['k']) and (v <= vSealList[a]['k'])) then
				AutoBuff_Option(a, 'k', v, 1);
			else
				AutoBuff_Print(AUTOBUFF_NOSUCHRANK);
			end
		else AutoBuff_Print(AUTOBUFF_RANK_USAGE1.."\n"..AUTOBUFF_RANK_USAGE2.."\n"..AUTOBUFF_RANK_USAGE3.."\n"..AUTOBUFF_RANK_USAGE4); end
	elseif (c == "rebuff") then
		local _,_,v,a = string.find(p,"([%w%p]+)%s*(.*)$");
		if (v) and (strlen(v) > 0) and ((v == "default") or ((tonumber(v)) and (tonumber(v) >= 0) and (tonumber(v) < 300))) then
			if (v ~= "default") then v = math.floor(tonumber(v)); end
			if (a) and (strlen(a) > 0) and (not vSpellList[a]) and (not vWeaponList[a]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, a));
			else AutoBuff_Option(a, 'r', v, 1); end
		else AutoBuff_Print(AUTOBUFF_REBUFF_USAGE1.."\n"..AUTOBUFF_REBUFF_USAGE2.."\n"..AUTOBUFF_REBUFF_USAGE3.."\n"..AUTOBUFF_REBUFF_USAGE4.."\n"
								..AUTOBUFF_REBUFF_USAGE5); end
	
	elseif (c == "trigger") then
		local _,_,v,a = string.find(p,"([%w%p]+)%s*(.*)$");
		if (v) and
		(strlen(v) > 0) and	((v == "default") or ((tonumber(v)) and	(tonumber(v) >= 0) and (tonumber(v) <= 126) and ((tonumber(v) /2) == floor(tonumber(v) /2)))) then
			if (a) and (strlen(a) > 0) and (not vSpellList[a]) and (not vWeaponList[a]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, a));
			else AutoBuff_Option(a, 't', v, 1); end
		else AutoBuff_Print(AUTOBUFF_TRIGGER_USAGE1.."\n"..AUTOBUFF_TRIGGER_USAGE2.."\n"..AUTOBUFF_TRIGGER_USAGE3.."\n"..AUTOBUFF_TRIGGER_USAGE4.."\n"
								..AUTOBUFF_TRIGGER_USAGE5); end
	
	elseif (c == "reload") then
		AutoBuff_Reload();
		AutoBuff_Print(AUTOBUFF_RELOADED);
		
	elseif (c == "combat") then
		local _,_,v,a = string.find(p,"([%w%p]+)%s*(.*)$");
		if (v) and (strlen(v) > 0) and ((v == "default") or (v == ">") or (v == "<") or (v == "<>")) then
			if (v == "<") then v = 1; elseif (v == ">") then v = 2; elseif (v == "<>") then v = 3; end
			if (a) and (strlen(a) > 0) and (not vSpellList[a]) and (not vWeaponList[a]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, a));
			else AutoBuff_Option(a, 'c', v, 1); end
		else AutoBuff_Print(AUTOBUFF_COMBAT_USAGE1.."\n"..AUTOBUFF_COMBAT_USAGE2.."\n"..AUTOBUFF_COMBAT_USAGE3.."\n"..AUTOBUFF_COMBAT_USAGE4
							.."\n"..AUTOBUFF_COMBAT_USAGE5); end
	
	elseif (c == "party") then
		local _,_,v,a = string.find(p,"([%w%p]+)%s*(.*)$");
		if (v) and (strlen(v) > 0) and ((v == "default") or (v == ">") or (v == "<") or (v == "<>")) then
			if (v == "<") then v = 1; elseif (v == ">") then v = 2; elseif (v == "<>") then v = 3; end
			if (a) and (strlen(a) > 0) and (not vSpellList[a]) and (not vWeaponList[a]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, a));
			else AutoBuff_Option(a, 'p', v, 1); end
		else AutoBuff_Print(AUTOBUFF_PARTY_USAGE1.."\n"..AUTOBUFF_PARTY_USAGE2.."\n"..AUTOBUFF_PARTY_USAGE3.."\n"..AUTOBUFF_PARTY_USAGE4
							.."\n"..AUTOBUFF_PARTY_USAGE5); end
	
	elseif (c == "track") then
		if (p) and (strlen(p) > 0) then
			if (p == "auto") then p = nil;
			elseif (p ~= "off") and (not vTrackList[p]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, p)); end
			AutoBuff_Data[vC]['t'] = p;
			AutoBuff_TrackLoad("show")
		else
			AutoBuff_Print(AUTOBUFF_TRACK_USAGE1.."\n"..AUTOBUFF_TRACK_USAGE2);
		end
		
	elseif (c == "aspect") then
		if (p) and (strlen(p) > 0) then
			if (p == "auto") then p = nil;
			elseif (p ~= "off") and (not vAspectList[p]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, p)); end
			AutoBuff_Data[vC]['a'] = p;
			AutoBuff_AspectLoad("show");
		else
			AutoBuff_Print(AUTOBUFF_ASPECT_USAGE1.."\n"..AUTOBUFF_ASPECT_USAGE2);
		end
		
	elseif (c == "seal") then
		if (p) and (strlen(p) > 0) then
			if (p == "auto") then p = nil;
			elseif (p ~= "off") and (not vSealList[p]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, p)); end
			AutoBuff_Data[vC]['seal'] = p;
			AutoBuff_SealLoad("show");
		else
			AutoBuff_Print(AUTOBUFF_SEAL_USAGE1.."\n"..AUTOBUFF_SEAL_USAGE2);
		end
		
	elseif (c == "weapon") then
		if (p) and (strlen(p) > 0) then
			if (p == "auto") then p = nil;
			elseif (p ~= "off") and (not vWeaponList[p]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, p)); end
			AutoBuff_Data[vC]['w'] = p;
			AutoBuff_WeaponLoad("show")
		else
			AutoBuff_Print(AUTOBUFF_WEAPON_USAGE1.."\n"..AUTOBUFF_WEAPON_USAGE2);
		end
		
	elseif (c == "mana") then
		local _,_,v,a = string.find(p,"([%w%p]+)%s*(.*)$");
		if (v) and (strlen(v) > 0) and ((v == "default") or ((tonumber(v)) and (tonumber(v) >= -100) and (tonumber(v) < 100))) then
			if (v ~= "default") then v = math.floor(tonumber(v)); end
			if (a) and (strlen(a) > 0) and (not vSpellList[a]) and (not vWeaponList[a]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, a));
			else AutoBuff_Option(a, 'm', v, 1); end
		else AutoBuff_Print(AUTOBUFF_MANA_USAGE1.."\n"..AUTOBUFF_MANA_USAGE2.."\n"..AUTOBUFF_MANA_USAGE3); end
		
	elseif (c == "health") then
		local _,_,v,a = string.find(p,"([%w%p]+)%s*(.*)$");
		if (v) and (strlen(v) > 0) and ((v == "default") or ((tonumber(v)) and (tonumber(v) >= -100) and (tonumber(v) < 100))) then
			if (v ~= "default") then v = math.floor(tonumber(v)); end
			if (a) and (strlen(a) > 0) and (not vSpellList[a]) and (not vWeaponList[a]) then AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, a));
			else AutoBuff_Option(a, 'h', v, 1); end
		else AutoBuff_Print(AUTOBUFF_HEALTH_USAGE1.."\n"..AUTOBUFF_HEALTH_USAGE2.."\n"..AUTOBUFF_HEALTH_USAGE3); end
		
	elseif (c == "innercharges") then
		local _,_,v = string.find(p,"([%w%p]+)$");
		if (v) and (strlen(v) > 0) and ((v == "default") or ((tonumber(v)) and (tonumber(v) > 0) and (tonumber(v) <= 19))) then
			if (v ~= "default") then
				AutoBuff_Data[vC]["innercharges"] = math.floor(tonumber(v));
			else
				AutoBuff_Data[vC]["innercharges"] = 5;
			end
			TITAN_AUTOBUFF_INNER = "Priest Inner Fire casts at "..AutoBuff_Data[vC]["innercharges"].." charges left";
			AutoBuff_Print("Inner Fire will now be cast when there are "..AutoBuff_Data[vC]["innercharges"].." charges left");
			if (IsAddOnLoaded("FuBar")) then AutoBuffFu:Update(); end
		else AutoBuff_Print(AUTOBUFF_INNERCHARGES_USAGE1.."\n"..AUTOBUFF_INNERCHARGES_USAGE2.."\n"..AUTOBUFF_INNERCHARGES_USAGE3); AutoBuff_Print("It is currently set to "..AutoBuff_Data[vC]["innercharges"].."."); end
		
	elseif (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) and (c == "succubus") then
		if (AutoBuff_Data[vC]['s'] == nil) then
			AutoBuff_Data[vC]['s'] = 1;
			AutoBuff_Print("Succubus, |cffa0ffa0"..AUTOBUFF_ENABLED..FONT_COLOR_CODE_CLOSE);
		else
			AutoBuff_Data[vC]['s'] = nil;
			AutoBuff_Print("Succubus, |cffffa0a0"..AUTOBUFF_DISABLED..FONT_COLOR_CODE_CLOSE);
		end
		
	elseif (c == "enable") then
		if (p) and (strlen(p) > 0) then
			if (vSpellList[p]) then AutoBuff_Option(p, 'd', "default", 1); if (AutoBuff_IsBlessing(p)) then AutoBuff_FixBlessing(p); end if (AutoBuff_IsAura(p)) then AutoBuff_FixAura(p); end
			else AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, p)); end
		else 
			AutoBuff_Print(AUTOBUFF_SETABILITY_ENABLE_USAGE1.."\n"..AUTOBUFF_SETABILITY_ENABLE_USAGE2.."\n"
							..AUTOBUFF_SETABILITY_ENABLE_USAGE3.."\n"..AUTOBUFF_SETABILITY_ENABLE_USAGE4);
		end
		
	elseif (c == "disable") then
		if (p) and (strlen(p) > 0) then
			if (vSpellList[p]) then AutoBuff_Option(p, 'd', 1, 1);
			else AutoBuff_Print(string.format(AUTOBUFF_NOTSUPPORTED, p)); end
		else 
			AutoBuff_Print(AUTOBUFF_SETABILITY_DISABLE_USAGE1.."\n"..AUTOBUFF_SETABILITY_DISABLE_USAGE2.."\n"
							..AUTOBUFF_SETABILITY_DISABLE_USAGE3.."\n"..AUTOBUFF_SETABILITY_DISABLE_USAGE4);
		end
		
	elseif (c == "list") then
		local i,x,v,k,m;
		AutoBuff_Seperator();
		local default, spell, weapon, track, aspect, seal, text = "", "", "", "", "", "", "";
		text = AUTOBUFF_LIST_START.."\n-\n";
		i = 1;
		while (i > -1) do
			x = AutoBuff_SpellList(i);
			if (not x) then break; end
			x = string.lower(x);
			if (vSpellList[x]) then spell = spell..AutoBuff_ListItem(x).."\n"; end
			i=i+1;
		end
		for iName, xName in vWeaponList do
			weapon = weapon..AutoBuff_ListItem(iName).."\n";
		end
		for iName, xName in vTrackList do
			track = track..AutoBuff_ListItem(iName).."\n";
		end
		for iName, xName in vAspectList do
			aspect = aspect..AutoBuff_ListItem(iName).."\n";
		end
		for iName, xName in vSealList do
			seal = seal..AutoBuff_ListItem(iName).."\n";
		end
		default = AutoBuff_ListItem('d');
		if (strlen(spell) >0) then text = text..spell.."-\n"; end
		if (strlen(weapon) >0) then text = text..weapon.."-\n"; end
		if (strlen(track) >0) then text = text..track.."-\n"; end
		if (strlen(aspect) >0) then text = text..aspect.."-\n"; end
		if (strlen(seal) >0) then text = text..seal.."-\n"; end
		text = text..string.upper(AUTOBUFF_LIST_DEFAULT).." - "..default.."\n-";
		AutoBuff_Print(text);
	elseif (c == "help") then
		AutoBuff_Print(AUTOBUFF_USAGE.."\n"..AUTOBUFF_USAGE_LIST);
		
	else
		AutoBuffFrame_Toggle();
		
	end
end

function AutoBuff_ListItem(i)
	local m = "";
	if (i ~= 'd') then m = m.."|cffffffa0"..string.upper(i)..FONT_COLOR_CODE_CLOSE.." - "; end
	if ((AutoBuff_Data[vC]['x'][i]) and (AutoBuff_Data[vC]['x'][i]['d'] == 1)) or ((vTrackList[i]) and (vTrack ~= i)) or ((vWeaponList[i]) and (vWeapon ~= i)) or ((vAspectList[i]) and (vAspect ~= i)) or ((vSealList[i]) and (vSeal ~= i)) then return m.."|cffff5050"..AUTOBUFF_LIST_DISABLED..FONT_COLOR_CODE_CLOSE;
	-- EMERALD: I think this is where the "change aspect, AB disables" is happening. Why was this written?
	elseif (vTrackList[i]) then return m..AUTOBUFF_ENABLED;
	elseif (vAspectList[i]) then return m..AUTOBUFF_ENABLED;
	elseif (vSealList[i]) then return m..AUTOBUFF_ENABLED; end
	if (AutoBuff_Data[vC]['x'][i] == nil) then return m..AUTOBUFF_LIST_USINGDEFAULTS; end
	local trigger, health, mana, rebuff, combat, rank = "","","","","","";
	for v, k in AutoBuff_Data[vC]['x'][i] do
		if (v == 'h') then
			if (k < 0) then t = "<"; k = k * -1;
			else t = ">"; end
			health = "|cffffa0a0"..AUTOBUFF_LIST_HEALTH..", "..t..k.."%"..FONT_COLOR_CODE_CLOSE.." ";
		elseif (v == 'm')  then
			if (k < 0) then t = "<"; k = k * -1;
			else t = ">"; end
			mana = "|cff5e9ae4"..AUTOBUFF_LIST_MANA..", "..t..k.."%"..FONT_COLOR_CODE_CLOSE.." ";
		elseif (v == 'c')  then
			if (k == 1) then combat = AUTOBUFF_LIST_COMBAT_IN; end
			if (k == 2) then combat = AUTOBUFF_LIST_COMBAT_OUT; end
			if (k == 3) then combat = AUTOBUFF_LIST_COMBAT_ALWAYS; end
			combat = "|cfff0802e"..combat..FONT_COLOR_CODE_CLOSE.." ";
		--elseif (v == 'r') and (not AutoBuff_IsAura(i)) and (i ~= string.lower(AUTOBUFF_ABILITY_TRUESHOTAURA)) then
		elseif (v == 'r') and (not AutoBuff_IsAura(i)) then
			rebuff = "|cffa0a0a0"..string.format(AUTOBUFF_LIST_REBUFF,k)..FONT_COLOR_CODE_CLOSE.." ";
		elseif (v == 't') then
			trigger = "|cffe0e0e0"..AUTOBUFF_LIST_TRIGGER..", "..k..FONT_COLOR_CODE_CLOSE.." ";
		elseif (v == 'k') then
			rank = "|cffffa0ff"..AUTOBUFF_LIST_RANK..", "..k..FONT_COLOR_CODE_CLOSE.." ";
		end
	end
	if (strlen(trigger..health..mana..rebuff..combat..rank) < 1) then rebuff = AUTOBUFF_LIST_USINGDEFAULTS; end
	m = m..trigger..health..mana..rebuff..combat..rank;
	return m;
end

function AutoBuff_IsBlessing(n)
	local a,d;
	n = string.lower(n);
	for _, d in cBlessing do
		a = string.lower(d);
		if (n == a) then a = 1; break; end
	end
	if (a == 1) then return 1; end
end

function AutoBuff_IsAura(n)
	local a,d;
	n = string.lower(n);
	for _, d in cAura do
		a = string.lower(d);
		if (n == a) then a = 1; break; end
	end
	if (a == 1) then return 1; end
end

function AutoBuff_FixBlessing(b)
	b = string.lower(b);
	local n,a;
	for _, n in cBlessing do
		a = string.lower(n);
		if (a ~= b) and (vSpellList[a]) then AutoBuff_Option(a, 'd', 1); end
	end
end

function AutoBuff_FixAura(b)
	b = string.lower(b);
	local n,a;
	for _, n in cAura do
		a = string.lower(n);
		if (a ~= b) and (vSpellList[a]) then AutoBuff_Option(a, 'd', 1); end
	end
end

function AutoBuff_PaladinSetup()
	local i,n,d,o,x;
	x = table.getn(cSpellList);
	o = 0;
	if true--[[akpatch]] or UnitPowerType("player") == 0 then  -- !!! не работало, если вызывалось прежде PLAYER_ENTERING_WORLD
	while (o > -1) do
		n = cBlessing[o];
		if (not n) then break; end
		i=0;
		cSpellList[n] = { ['type'] = "friendly", ['i'] = (x+o+1) };
		for _, d in cBlessing do
			if (n ~= d) then cSpellList[n][i] = string.lower(d); i=i+1; end
		end
		for _, d in cBlessingOther do
			cSpellList[n][i] = string.lower(d); i=i+1
		end
		o=o+1;
	end
	end
	x = x+o;
	o = 0;
	while (o > -1) do
		n = cAura[o];
		if (not n) then break; end
		i=0;
		cSpellList[n] = { ['type'] = "self", ['i'] = (x+o+1) };
		for _, d in cAura do
			if (n ~= d) then cSpellList[n][i] = string.lower(d); i=i+1; end
		end
		o=o+1;
	end
end

function AutoBuff_BuffName(i, filter)
	--AutoBuffTooltip:SetOwner(WorldFrame,"ANCHOR_NONE");
	if (filter == nil) then	filter = "HELPFUL|HARMFUL"; end
	local iBuff,iBuffConc = GetPlayerBuff(i, filter);
	if (iBuff >= 0) and (iBuff <= 99) then -- akpatch: увеличить максимальный предел
		--local tooltip = AutoBuffTooltip;
		--tooltip:Hide();
		--tooltip:SetPlayerBuff(iBuff);
		local tooltip = AutoBuffTooltip;
		tooltip:SetOwner(tooltip,"ANCHOR_NONE");
		tooltip:ClearLines();
		tooltip:SetPlayerBuff(iBuff);
		local toolTipText = getglobal("AutoBuffTooltipTextLeft1");
		if (toolTipText) then
			local name = toolTipText:GetText();
			if ( name ~= nil ) then	return iBuff, name, iBuffConc; end
		end
	end
end

function AutoBuff_IsBuffActive(buffname)
	--AutoBuffTooltip:SetOwner("UIParent", "ANCHOR_NONE");
	if (not buffname) then
		return;
	end;
	unit="player";
  local i = 1;
  while UnitBuff(unit, i) do 
		AutoBuffTooltip:ClearLines();
		AutoBuffTooltip:SetUnitBuff(unit,i);
    if string.find(AutoBuffTooltipTextLeft1:GetText() or "", buffname) then
      return true, i
    end;
    i = i + 1;
  end;
end

function AutoBuff_IsDebuffActive(buffname)
	--AutoBuffTooltip:SetOwner("UIParent", "ANCHOR_NONE");
	if (not buffname) then
		return;
	end;
	unit="player";
  local i = 1;
  while UnitDebuff(unit, i) do 
		AutoBuffTooltip:ClearLines();
		AutoBuffTooltip:SetUnitDebuff(unit,i);
    if string.find(AutoBuffTooltipTextLeft1:GetText() or "", buffname) then
      return true, i
    end;
    i = i + 1;
  end;
end

function AutoBuff_BuffLine(i, line, filter)
	--AutoBuffTooltip:SetOwner(WorldFrame,"ANCHOR_NONE");
	if (filter == nil) then	filter = "HELPFUL|HARMFUL"; end
	local iBuff,_ = GetPlayerBuff(i, filter);
	if (iBuff >= 0) and (iBuff < 100) then -- akpatch: увеличить максимальный предел
		--local tooltip = AutoBuffTooltip;
		--tooltip:SetPlayerBuff(iBuff);
		--tooltip:Hide();
		local tooltip = AutoBuffTooltip;
		tooltip:SetOwner(tooltip,"ANCHOR_NONE");
		tooltip:ClearLines();
		tooltip:SetPlayerBuff(iBuff);
		local toolTipText = getglobal("AutoBuffTooltipTextLeft"..line);
		if (toolTipText) then
			local name = toolTipText:GetText();
			if ( name ~= nil ) then	return iBuff, name; end
		end
	end
end

function AutoBuff_ShieldMod_SetCTShieldMod() -- EMERALD
	--local highestRank = AutoBuff_GetHighestSpellRank("Power Word: Shield");
	local highestRank = AutoBuff_Rank(AUTOBUFF_ABILITY_PWSHIELD);
	highestRank = tonumber(highestRank);
	AutoBuff_Debug("highestRank="..tostring(highestRank));
	local dmg;
	if (highestRank) then
		if (highestRank==1) then
			dmg = "48";
		elseif (highestRank==2) then
			dmg = "94";
		elseif (highestRank==3) then
			dmg = "166";
		elseif (highestRank==4) then
			dmg = "242";
		elseif (highestRank==5) then
			dmg = "301";
		elseif (highestRank==6) then
			dmg = "381";
		elseif (highestRank==7) then
			dmg = "484";
		elseif (highestRank==8) then
			dmg = "605";
		elseif (highestRank==9) then
			dmg = "763";
		elseif (highestRank==10) then
			dmg = "942";
		end
		if (dmg) then
			CT_ShieldMod_ShieldDamageLeft = tonumber(dmg);
			CT_ShieldFrame:Hide();
			CT_ShieldFrame:Show();
		end
	end
end

function AutoBuff_CanCast(spell, trigger, ltime)
	local translatedSpell = spell;
	if (spell=="track") then translatedSpell = string.lower(vTrack);
	elseif (spell=="aspect") then translatedSpell = string.lower(vAspect);
	elseif (spell=="seal") then translatedSpell = string.lower(vSeal);
	end
	local t = AutoBuff_Trigger(translatedSpell);
	AutoBuff_Debug("CanCast: trigger="..trigger..", translatedSpell="..translatedSpell);
	if (AutoBuff_CheckCombat(translatedSpell)) then AutoBuff_Debug("AutoBuff_CheckCombat=true"); else AutoBuff_Debug("AutoBuff_CheckCombat=false"); end
	if (AutoBuff_CheckParty(translatedSpell)) then AutoBuff_Debug("AutoBuff_CheckParty=true"); else AutoBuff_Debug("AutoBuff_CheckParty=false"); end
	if (AutoBuff_Mana(translatedSpell)) then AutoBuff_Debug("AutoBuff_Mana=true"); else AutoBuff_Debug("AutoBuff_Mana=false"); end
	if (AutoBuff_Health(translatedSpell)) then AutoBuff_Debug("AutoBuff_Health=true"); else AutoBuff_Debug("AutoBuff_Health=false"); end
	if (AutoBuff_Option(translatedSpell,'d')) then AutoBuff_Debug("Enabled=false"); else AutoBuff_Debug("Enabled=true"); end
	--if () then AutoBuff_Debug(""); else AutoBuff_Debug(""); end
	--AutoBuff_Debug("");

	if (translatedSpell == string.lower(AUTOBUFF_ABILITY_UNENDING_BREATH) or translatedSpell == string.lower(AUTOBUFF_ABILITY_WATER_BREATHING)) then
		local ltimer = time();
		if (AutoBuff_Data[vC]["water"]) then
			if (vBreath > ltimer) or vBreath == 0 then
				AutoBuff_Debug("  Cannot cast "..translatedSpell.." because you haven't been underwater for more than 30 seconds. Type \"/autobuff water\" to change this behavior.");
				AutoBuff_Debug("  vBreath="..vBreath..", ltimer="..ltimer);
				return nil;
			end
		end
	end
	
	if ((trigger == 0) or (t[trigger] == 1)) and
	(not AutoBuff_Option(translatedSpell,'d')) and
	(AutoBuff_CheckCombat(translatedSpell)) and
	(AutoBuff_CheckParty(translatedSpell)) and
	((not ltime) or ((ltime ~= -1) and (AutoBuff_Rebuff(translatedSpell, ltime)))) and
	(((spell == "track") or (spell == "aspect")) or
	(AutoBuff_Mana(translatedSpell)) and
	(AutoBuff_Health(translatedSpell))) then
		local spell_texture = GetSpellTexture(AutoBuff_Ability(translatedSpell), BOOKTYPE_SPELL);
		if (spell=="track") then return 1; end
		if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) then
			if (spell == string.lower(AUTOBUFF_ABILITY_SOULLINK)) then
				if (UnitHealth("pet") > 1) then -- Only cast Soul Link if the demon is out
					-- Scan debuffs, don't cast if your pet is Banished or Enslaved
					local i = 1;
					while (UnitDebuff("pet", i)) do
						if (UnitDebuff("pet", i)==cPre..cEnslave or UnitDebuff("pet", i)==cPre..cBanish) then
							return nil;
						end
						i = i + 1;
					end
					return 1;
				end
			elseif (spell == string.lower(AUTOBUFF_ABILITY_DARK_PACT)) then
				if (UnitMana("pet") > 1) then -- Only Dark Pact if demon is out and has mana
					if ((UnitManaMax("player")-UnitMana("player")) >= 150) then -- Only if needed
						return 1;
					else
						return nil;
					end
				else
					return nil;
				end
			else
				return 1;
			end
			
		elseif (vClass == string.lower(AUTOBUFF_CLASS_ROGUE)) then
			-- Don't cast any spells when rogue is stealthed
			local i = 1;
			while (UnitBuff("player", i)) do
				if (UnitBuff("player", i)==cPre..cStealth) then
					AutoBuff_Debug("ROGUE: Can't cast spells in Stealth Mode!");
					return nil;
				end
				i = i + 1;
			end
			return 1;
			
		else
			return 1;
		end
		
	end
end

function AutoBuff_Check(trigger) -- EMERALD: TriggerFire
	-- Check for frames that, while visible, should block spellcasting
	if (CastingBarFrame and CastingBarFrame:IsVisible()) then return; end
	if (eCastingBar and eCastingBar:IsVisible()) then return; end
	if (Perl_ArcaneBarFrame and Perl_ArcaneBarFrame:IsVisible()) then return; end
	if (LootFrame and LootFrame:IsVisible()) then AutoBuff_Debug("Can't cast: LootFrame is visible!"); return; end
	
	local ltime = time();
	if (vTime > ltime) or (vSit > ltime) then return; end
	
	if (AutoBuff_Data[vC]['e'] == 1) and
	 (not UnitOnTaxi("player")) and
	 (not CursorHasItem()) and
	 (not CursorHasSpell()) and
	 (not SpellIsTargeting()) and
	 (not UnitIsDeadOrGhost("player")) then
		AutoBuff_Debug("----------------------------");
		AutoBuff_Debug("### Beginning buff-check ###");
		local buffline,mounted,poly,buffIndex,buffName,buffConc,i,done,iName,xName,iiName,xxName,id;
		local polyShadowform = nil;
		local polyMoon = nil;
		local polyCat = nil;
		local polyBlessing = nil;
		local iBuff = {};
		
		for i=0,99 do -- Cycle currently active buffs -- akpatch: увеличить максимальный предел
			buffIndex, buffName, buffConc = AutoBuff_BuffName(i, "HELPFUL|HARMFUL");
			if not buffName then break else -- akpatch: оптимизация цикла
			
				-- This is done outside of the Class Poly loop because we don't store Greater Blessings in Class Poly's
				if (vClass == string.lower(AUTOBUFF_CLASS_PALADIN)) then
					if (cBlessingPoly[buffName]) then -- A greater blessing was found on the player
						polyBlessing = string.lower(buffName);
					end
				end
				
				buffName = string.lower(buffName);
				
				for iName, xName in cPolyList[vClass] do -- Cycle list of Class Poly's
				
					-- Don't POLY for AUTOBUFF_POLY_PRIEST_SPIRITTAP if mana is currently full
					if (vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
						if (buffName == string.lower(AUTOBUFF_POLY_PRIEST_SPIRITTAP) and AutoBuff_Data[vC]["tap"]) then
							AutoBuff_Debug("  Spirit Tap is currently active...");
							if (UnitMana("player")==UnitManaMax("player")) then
								-- Mana is full, we can go ahead and cast even though Spirit Tap is active.
								AutoBuff_Debug("  Player's Mana is full, ignoring Spirit Tap.");
							else
								AutoBuff_Debug("  Player's Mana is regenerating -- blocking other spells from firing.");
								poly = string.lower(iName);
								do break end;
							end
						end
						-- Prevent Holy spells from firing while in Shadowform
						if (buffName == string.lower(AUTOBUFF_POLY_PRIEST_SHADOWFORM)) then
							polyShadowform = true;
						end
					
					elseif (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) then
						if (buffName == string.lower(AUTOBUFF_POLY_WARLOCK_SOULSIPHON) and AutoBuff_Data[vC]["tap"]) then
							AutoBuff_Debug("  Soul Siphon is currently active...");
							if (UnitMana("player")==UnitManaMax("player")) then
								-- Mana is full, we can go ahead and cast even though Soul Siphon is active.
								AutoBuff_Debug("  Player's Mana is full, ignoring Soul Siphon.");
							else
								AutoBuff_Debug("  Player's Mana is regenerating -- blocking other spells from firing.");
								poly = string.lower(iName);
								do break end;
							end
						end
						
					elseif (vClass == string.lower(AUTOBUFF_CLASS_DRUID)) then
						-- Don't POLY for AUTOBUFF_POLY_DRUID_CAT if casting Track Humanoids
						if (buffName == string.lower(AUTOBUFF_POLY_DRUID_CAT)) then
							polyCat = true;
						-- Don't allow Mark of the Wild if you're a Moonkin
						elseif (buffName == string.lower(AUTOBUFF_POLY_DRUID_MOONKIN)) then
							polyMoon = true;
						end
					end
					
					if (buffName == string.lower(iName)) then
						if (string.lower(iName)~=string.lower(AUTOBUFF_POLY_DRUID_CAT) and string.lower(iName)~=string.lower(AUTOBUFF_POLY_DRUID_MOONKIN) and string.lower(iName)~=string.lower(AUTOBUFF_POLY_PRIEST_SHADOWFORM) and string.lower(iName)~=string.lower(AUTOBUFF_POLY_PRIEST_SPIRITTAP) and string.lower(iName)~=string.lower(AUTOBUFF_POLY_WARLOCK_SOULSIPHON)) then
							-- Only break if this poly isn't polyCat, polyMoon, or polyShadowform (nor SpiritTap)
							AutoBuff_Debug("  STOP -- Poly found: "..iName);
							poly = string.lower(iName);
							do break end;
						end
					end
					
					-- PRIEST LOGIC:
					-- SpiritTap+FullMana = GO
					-- SpiritTap+FullMana+Shadowform = GO
					-- SpiritTap+LowMana = STOP
					-- SpiritTap+LowMana+Shadowmeld(ALL_POLY) = STOP
					
				end -- for iName, xName in cPolyList[vClass] do
				
				for iName, xName in cPolyList["all"] do -- Cycle list of All Poly's (invis, shadowmeld)
					if (buffName == string.lower(iName)) then
						AutoBuff_Debug("  STOP -- Poly found: "..iName);
						poly = string.lower(iName);
						do break end;
					end
				end
				
				if (buffConc == 1) then
					iBuff[buffName] = -1;
				else
					iBuff[buffName] = GetPlayerBuffTimeLeft(buffIndex);
				end
				
				-- MOUNT CHECK
				_, buffline = AutoBuff_BuffLine(i, 2, "HELPFUL|HARMFUL");
				if (buffline) then
					buffline = string.lower(buffline);
					if ((buffline == string.lower(AUTOBUFF_MOUNT_60)) or (buffline == string.lower(AUTOBUFF_MOUNT_100)) or (buffline == string.lower(AUTOBUFF_MOUNT_60_2)) or (buffline == string.lower(AUTOBUFF_MOUNT_100_2)) or (buffline == string.lower(AUTOBUFF_MOUNT_60_3)) or (buffline == string.lower(AUTOBUFF_MOUNT_100_3))) then
						mounted = true;
					end
				end -- if (buffline) then
				
			end -- if (buffName) then
		end -- for i
		
		for i=1,10 do buffName = UnitDebuff("player",i);
			if (buffName and buffName == cPre..cSheep) then
				poly = "Sheep";
			end
		end
		
		if (poly == nil) then
		
			if (not mounted or (mounted and vClass==string.lower(AUTOBUFF_CLASS_PALADIN))) then
				for iName, xName in vSpellList do
					local several = nil;
					local polyCatCast = nil;
					local polyMoonCast = nil;
					local polyRogue = nil;
					local polyPaladin = nil;
					local polyRejuvRenew = nil;
					if (AutoBuff_CanCast(iName, trigger, iBuff[iName])) then
						for iiName, xxName in vSpellList[iName] do
							if (iiName ~= "type") and (iBuff[xxName]) then several = true; break; end
						end
						if (not several) then
							id = AutoBuff_Ability(iName);
							if (AutoBuff_Cooldown(id) == 0) then
							
								if (vClass==string.lower(AUTOBUFF_CLASS_PRIEST) and polyShadowform) then
									-- put Holy spells in if statements, below, to prevent casting those spells in Shadow form
									if (iName == string.lower(AUTOBUFF_ABILITY_FEARWARD) or iName == string.lower(AUTOBUFF_ABILITY_RENEW)) then
										AutoBuff_Debug("  Cannot cast "..iName.." - Shadowform is active.");
									else
										polyShadowform = nil;
									end
								
								elseif (vClass==string.lower(AUTOBUFF_CLASS_ROGUE)) then
									if (iName == string.lower(AUTOBUFF_ABILITY_FEINT) or iName == string.lower(AUTOBUFF_ABILITY_BLADE_FLURRY)) then
										if (UnitAffectingCombat("player") and UnitExists("target") and UnitReaction("target","player") <= 4 and CheckInteractDistance("target",1)) then
											-- Only if (1) in combat, (2) has target, (3) target is attackable, (4) 5 yards or closer.
											polyRogue = nil;
										else
											polyRogue = true;
											AutoBuff_Debug("  Cannot cast "..iName.." - Combat conditions are not correct (in combat, target attackable, 5 yards or less)");
										end
									end
								
								elseif (vClass==string.lower(AUTOBUFF_CLASS_DRUID) and polyMoon and iName ~= string.lower(AUTOBUFF_ABILITY_TRACK_HUMANOIDS) and iName ~= string.lower(AUTOBUFF_ABILITY_COWER)) then
									-- put Balance spells in if statements, below, to prevent casting those spells in Moonkin form
									if (iName == string.lower(AUTOBUFF_ABILITY_MOTW) or iName == string.lower(AUTOBUFF_ABILITY_REJUV)) then
										AutoBuff_Debug("  Cannot cast "..iName.." - Moonkin form is active.");
										polyMoonCast = true;
									else
										polyMoonCast = nil;
									end
								
								elseif (vClass==string.lower(AUTOBUFF_CLASS_DRUID)) then
									if (iName == string.lower(AUTOBUFF_ABILITY_TRACK_HUMANOIDS) or iName == string.lower(AUTOBUFF_ABILITY_COWER)) then
										if (polyCat) then
											if (iName == string.lower(AUTOBUFF_ABILITY_TRACK_HUMANOIDS)) then
												if (GetTrackingTexture()) then
													local iconTrack = GetTrackingTexture();
													AutoBuff_Debug("  Track already enabled: "..iconTrack);
													if (iconTrack==cPre..cTracking) then
														polyCatCast = true; -- don't recast if it's already on!
													end
												else
													polyCatCast = nil; --polyCat = nil; -- Can cast, clear polyCatCast.
												end
											elseif (iName == string.lower(AUTOBUFF_ABILITY_COWER)) then
												if (UnitAffectingCombat("player") and UnitExists("target") and UnitReaction("target","player") <= 4 and CheckInteractDistance("target",1)) then
													-- Only if (1) in combat, (2) has target, (3) target is attackable, (4) 5 yards or closer.
													polyCatCast = nil; -- Can cast, clear polyCatCast.
												else
													AutoBuff_Debug("  Cannot cast "..iName.." - Combat conditions are not correct (in combat, target attackable, 5 yards or less)");
													polyCatCast = true;
												end
											end
										elseif (polyMoon) then
											AutoBuff_Debug("  Cannot cast "..iName.." - You're not in cat form.");
											polyCatCast = true;
										else -- not polyCat
											AutoBuff_Debug("  Cannot cast "..iName.." - You're not in cat form.");
											polyCatCast = true;
										end
									else
										if (polyCat) then
											AutoBuff_Debug("  Cannot cast "..iName.." - Only Track Humanoids or Cower can be cast in cat form.");
											polyCatCast = true;
										end
									end
									
								elseif (vClass == string.lower(AUTOBUFF_CLASS_PALADIN)) then
									if (mounted) then
										if (not AutoBuff_IsAura(iName)) then
											polyPaladin = true; -- don't cast anything other than an Aura while mounted
										end
									elseif (polyBlessing and polyBlessing==iName) then
										-- Lesser spell (same effect as the Greater Blessing on the player currently) attempting to be cast
										AutoBuff_Debug("  Cannot cast "..iName.." - A Greater Blessing with the same effect is already active.");
										polyPaladin = true;
									end

								--elseif (vClass==string.lower(AUTOBUFF_CLASS_)) then
								end
								
								if iName==string.lower(AUTOBUFF_ABILITY_REJUV) then
									local ltime = time();
									if (vRejuv > ltime) then polyRejuvRenew = true; end
								elseif iName==string.lower(AUTOBUFF_ABILITY_RENEW) then
									local ltime = time();
									if (vRenew > ltime) then polyRejuvRenew = true; end
								end
								
								-- CASTING ROUTINE
								if (not polyShadowform and not polyCatCast and not polyMoonCast and not polyRogue and not polyPaladin and not polyRejuvRenew) then
									AutoBuff_Debug("  Casting Buff: "..iName);
									done = true;
									AutoBuff_UseAbility(iName,xName.type);
									AutoBuff_Debug("  iName="..iName);
									if iName==string.lower(AUTOBUFF_ABILITY_PWSHIELD) then
										-- Set CT_ShieldMod's initial damage ounter
										if (CT_ShieldFrame) then
											AutoBuff_ShieldMod_SetCTShieldMod();
											AutoBuff_Debug("Setting CT_Shield");
										end
									elseif iName==string.lower(AUTOBUFF_ABILITY_REJUV) then
										-- Set vRejuv, which allows the spell time to work before it can fire again
										vRejuv = time() + 15; -- Rejuv is 12 sec, but Renew is 15 (and Improved Rejuv Duration is 15), so I'm going with the higher common number.
									elseif iName==string.lower(AUTOBUFF_ABILITY_RENEW) then
										vRenew = time() + 15;
									end
									do break end;
								end
								
							end
						end
					end
				end
				if (not done) then
					local m,o,_,_,_,_ = GetWeaponEnchantInfo();
					if (o) then o = floor(o/1000); end
					if (vWeapon) and AutoBuff_CanCast(vWeapon, trigger, o) then
						--local mhHasItem,_,_=GameTooltip:SetInventoryItem("player",16);
						--local ohHasItem,_,_=GameTooltip:SetInventoryItem("player",17);
						--if (mhHasItem or ohHasItem) then
							AutoBuff_Debug("  Weapon Buff: "..vWeapon);
							AutoBuff_UseAbility(vWeapon,'self');
						--else
							--AutoBuff_Debug("  Weapon Buff cannot be cast. You have no melee weapon equipped.");
						--end
					end
					local a, b, c, d, e;
					if (vWeapon) then a = vWeapon; else a = "false"; end
					if (m) then
						b = m;
						if (AutoBuff_Rebuff(vWeapon, floor(o/1000))) then c = "true"; else c = "false"; end
					else b = "false"; c = "none";
					end
					if (AutoBuff_Mana(vWeapon)) then d = "true"; else d = "false"; end
					if (AutoBuff_Health(vWeapon)) then e = "true"; else e = "false"; end
					AutoBuff_Debug("  Weapon, "..a.."; m, "..b.."; rebuff, "..c.."; mana, "..d.."; health, "..e);
				end
			end		
		end

		if (vSeal and not mounted and not poly) then
			AutoBuff_Debug("Check Seal Setting...");
			local buffline,mounted,poly,buffIndex,buffName,buffConc,i,done,iName,xName,iiName,xxName,id; local iBuff = {};
			local hasSeal = false;
			for i=0,99 do -- akpatch: увеличить максимальный предел
				buffIndex, buffName, buffConc = AutoBuff_BuffName(i, "HELPFUL|HARMFUL");
				if not buffName then break else -- akpatch: оптимизация цикла
					if (string.find(buffName,AUTOBUFF_SEAL)) then hasSeal = true; break; end
				end
			end
			if (not hasSeal) then
				if (AutoBuff_CanCast("seal", trigger, nil)) then
					AutoBuff_UseAbility(vSeal,'self');
					AutoBuff_Debug("  Seal not found. Casting "..vSeal);
				else
					AutoBuff_Debug("  Seal not found, but I can't cast right now.");
				end
			else
				AutoBuff_Debug("  Seal found. Doing nothing.");
			end
		end

		if (vAspect and not mounted and not poly) then
			AutoBuff_Debug("Check Aspect Setting...");
			local buffline,mounted,poly,buffIndex,buffName,buffConc,i,done,iName,xName,iiName,xxName,id; local iBuff = {};
			local hasAspect = false;
			for i=0,99 do -- akpatch: увеличить максимальный предел
				buffIndex, buffName, buffConc = AutoBuff_BuffName(i, "HELPFUL|HARMFUL");
				if not buffName then break else -- akpatch: оптимизация цикла
					--buffName = string.lower(buffName);
					--buffCompare = string.lower(AUTOBUFF_ASPECT_OF);
					--AutoBuff_Debug("  Comparing "..buffName.." to "..vAspect);
					if (string.find(buffName,AUTOBUFF_ASPECT_OF)) then hasAspect = true; break; end
				end
			end
			if (not hasAspect) then
				if (AutoBuff_CanCast("aspect", trigger, nil)) then
					AutoBuff_UseAbility(vAspect,'self');
					AutoBuff_Debug("  Aspect not found. Casting "..vAspect);
				else
					AutoBuff_Debug("  Aspect not found, but I can't cast right now.");
				end
			else
				AutoBuff_Debug("  Aspect found. Doing nothing.");
			end
		end

		if (vClass == string.lower(AUTOBUFF_CLASS_DRUID) and polyCat and not AutoBuff_Option(string.lower(AUTOBUFF_ABILITY_TRACK_HUMANOIDS),'d')) then -- Druid + Cat + Track Humanoids (enabled)
			done = true; -- Do NOT check normal tracking if Track Humanoids is being fired on the Cat form.
		end
		
		if ((not done or vClass == string.lower(AUTOBUFF_CLASS_ROGUE))) then
			AutoBuff_Debug("Check Track Setting...");
			if (vTrack) then
				AutoBuff_Debug("  Found: "..vTrack);
				if (not GetTrackingTexture()) then
					if (AutoBuff_CanCast("track", trigger, nil)) then
						AutoBuff_Debug("  Tracking Ability: "..vTrack);
						AutoBuff_UseAbility(vTrack,'self');
					else
						AutoBuff_Debug("  Track failed 'CanCast'.");
					end
				else
					AutoBuff_Debug("  Track already enabled: "..GetTrackingTexture());
				end
			end
		else AutoBuff_Debug("  Already done, not checking track.");
		end
		if (done) and (vTime < ltime) then vTime = ltime; end
		
		if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) and (vCombat == nil) and (AutoBuff_Data[vC]['s']) and not poly then
			for iName, xName in cWarlockPet do
				local petspell = AutoBuff_CheckPetAbility(iName);
				local petbuff;
				if (petspell) then
					AutoBuff_Debug("  Petspell button: "..petspell);
					for i=1,10 do if (UnitBuff("pet",i) == cPre..xName) then petbuff = true; end end
					if (not petbuff) and AutoBuff_Mana_Pet() then CastPetAction(petspell); end
				end
			end
		end
		
		AutoBuff_Debug("### Finished buff-check ###");
	end
end

function AutoBuff_CheckCombat(spell)
	local s = string.lower(spell);
	local x = AutoBuff_Option(s,'c');
	if (not x) then x = AutoBuff_Option('d','c'); end
	if (UnitAffectingCombat("player")) then -- Should prevent most false positives
		vCombat = true;
	else
		vCombat = nil;
	end
	if (not x) or (x == 3) then return true;
	elseif (vCombat) and (x == 1) then return true;
	elseif (not vCombat) and (x == 2) then return true; end
end

function AutoBuff_CheckParty(spell)
	local s = string.lower(spell);
	local x = AutoBuff_Option(s,'p');
	local p = nil;
	if (GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0) then p = 1; end
	if (not x) then x = AutoBuff_Option('d','p'); end
	if (not x) or (x == 3) then return true;
	elseif (p) and (x == 1) then return true;
	elseif (not p) and (x == 2) then return true; end
end

function AutoBuff_Rebuff(name, ltime)
	if (ltime) then ltime = floor(ltime); end
	local r = AutoBuff_Option(name, 'r');
	if (not r) then r = AutoBuff_Option('d', 'r'); end
	local t = ltime;
	if (not t) then t = "nil"; end
	if (not name) then name = "[default]"; end
	
	if (string.lower(name) == string.lower(AUTOBUFF_ABILITY_INNER_FIRE)) and (AutoBuff_Data[vC]["inner"]) then -- We want to fire this at XX/20 charges left, instead of removed totally
		local i = 1;
		while (UnitBuff("player", i)) do
			buff, numbuff = UnitBuff("player", i);
			-- Already buffed with Inner Fire
			if (buff==cIconInnerFire) then
				AutoBuff_Debug("Found InnerFire with "..numbuff.." out of "..AutoBuff_Data[vC]["innercharges"].." charges left.");
			end
			if (buff==cIconInnerFire) and (numbuff <= AutoBuff_Data[vC]["innercharges"]) then
				return true; -- Recast, because we're at or under XX charges
			end
			i = i + 1;
		end
	end
	
	AutoBuff_Debug("Rebuff, "..name.." r:"..r.." t:"..t);
	if (not ltime) or (r > ltime) then
		AutoBuff_Debug("Rebuff should fire!");
		return true;
	end
end

function AutoBuff_Mana(name)
	local c = (UnitMana("player")/UnitManaMax("player"))*100;
	AutoBuff_Debug("Player Mana is at "..c.."%.");
	local n = AutoBuff_Option(name,'m');
	if (n == nil) then n = AutoBuff_Option('d','m'); end
	if (n > 0) and (c > n) then return true;
	elseif (n < 0) and (c < (n*-1)) then return true; end
end

function AutoBuff_Mana_Pet()
	local c = (UnitMana("pet")/UnitManaMax("pet"))*100;
	local n = 35;
	if (c > n) then return true; end
end

function AutoBuff_CheckPetAbility(spellName)
	local name, i;
	for i=1,10 do
		name, _, _, _, _, _, _ = GetPetActionInfo(i)
		if (name) and (string.lower(name) == string.lower(spellName)) then return i; end
	end
end

function AutoBuff_Health(name)
	local c = (UnitHealth("player")/UnitHealthMax("player"))*100;
	local n = AutoBuff_Option(name,'h');
	if (n == nil) then n = AutoBuff_Option('d','h'); end
	if (n > 0) and (c > n) then return true;
	elseif (n < 0) and (c < (n*-1)) then return true; end
end

function AutoBuff_GetHighestSpellRank(spell)
	if (spell) then spell = string.lower(spell);
	else return; end
	local i=1
	local id = nil;
	while true do
   		local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL);
   		if (not spellName) then break; end
		if (string.lower(spellName) == spell) then id = spellRank; end
   		i = i+1;
	end
	
	local _,_,realRank = string.find(id, "([%d]+)$");
	
	if (GetLocale() == "koKR") then -- Korean ranks are reversed.
		local _,_,realRank = string.find(id, "(%d+%.?%d*)");
	end
	return tonumber(realRank);
end

function AutoBuff_Cooldown(id)
	if (id) then return GetSpellCooldown(id, BOOKTYPE_SPELL); end
end

function AutoBuff_UseAbility(spell, type)
	--local testScaled = "";
	--if (AutoBuff_Data[vC]["scaled"]) then testScaled = "true"; else testScaled = "false"; end
	--AutoBuff_Debug("spell: "..spell.." life tap: "..AUTOBUFF_ABILITY_LIFE_TAP.." BonusScanner: "..IsAddOnLoaded("BonusScanner").." scaled? "..testScaled);
	if (spell==string.lower(AUTOBUFF_ABILITY_LIFE_TAP)) and IsAddOnLoaded("BonusScanner") and (AutoBuff_Data[vC]["scaled"]) then
		AutoBuff_ScaledLifeTap_CastLifeTap();
		AutoBuff_Debug("Going into Scaled Life Tap routine.");
	else
		local i=1; local name, d;
		local id = AutoBuff_Ability(spell);
		if id then
			if (AutoBuff_Cooldown(id) == 0) then
				if (type == "friendly") and (UnitIsFriend("player", "target")) and (not UnitIsUnit("player","target")) then
					name = UnitName("target");
					ClearTarget();
				end
				CastSpell(id,BOOKTYPE_SPELL);
				if (SpellIsTargeting() and SpellCanTargetUnit("player")) then
					SpellTargetUnit("player");
				end
				if (name) then TargetByName(name); end
			end
		end
	end
end

function AutoBuff_Ability(spell, rank)
	if (spell) then spell = string.lower(spell);
	else return; end
	local o = AutoBuff_Option(spell, 'k');
	local i=1;
	local id = nil;
	while true do
   		local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL);
   		if (not spellName) then break; end
		if (string.lower(spellName) == spell) then
			id = i;
			if (o) then
				local _,_,realRank = string.find(spellRank, "([%d]+)$");
				if (tonumber(realRank) == o) then break; end
			end
		end
   		i = i+1;
	end
	if (id) then local a,b = "", ""; a,b = GetSpellName(id, BOOKTYPE_SPELL); AutoBuff_Debug("Got Spell ID for, "..a.." "..b); end
	return id;
end

function AutoBuff_Rank(spell)
	AutoBuff_Debug("AutoBuff_Rank: entering function");
	if (spell) then spell = string.lower(spell);
	else return; end
	local o = AutoBuff_Option(spell, 'k');
	local i=1;
	while true do
   		local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL);
   		if (not spellName) then break; end
		if (string.lower(spellName) == spell) then
			if (o) then
				local _,_,realRank = string.find(spellRank, "([%d]+)$");
				if (tonumber(realRank) == o) then break; end
			end
		end
   		i = i+1;
	end
	if (o) then return o;
	elseif (realRank) then return realRank;
	else
		return AutoBuff_GetHighestSpellRank(spell);
	end
end

function AutoBuff_Debug(text) 						-- Prints debug information only if switched on
	if (AutoBuff_Data[vC]['d'] == 1) then DEFAULT_CHAT_FRAME:AddMessage("|cff5e9ae4AutoBuff"..FONT_COLOR_CODE_CLOSE.."/".."|cffffa0a0Debug"..FONT_COLOR_CODE_CLOSE..": "..text); end
end

function AutoBuff_TableIndex(tbl, index)			-- This and the next function are used to get the table index name
	bIndex = index;									-- by giving the index as an integer.
	bValue = 0;
	return table.foreach(tbl, AutoBuff_foreach);
end

function AutoBuff_foreach(index, value)
	if (bValue == bIndex) then return index; end
	bValue = bValue +1;
end

function AutoBuff_TableConfig()
	AutoBuff_setn(cSpellList);
	AutoBuff_setn(cTrackList);
	AutoBuff_setn(cWeaponList);
	AutoBuff_setn(cAspectList);
	AutoBuff_setn(cSealList);
end

function AutoBuff_setn(tbl)
	bValue = 0;
	table.foreach(tbl, AutoBuff_setn_foreach);
	table.setn(tbl, bValue);
end

function AutoBuff_setn_foreach(index, value)
	bValue = bValue +1;
end

function AutoBuff_Print(text)
	if (text) then DEFAULT_CHAT_FRAME:AddMessage("|cff5e9ae4AutoBuff"..FONT_COLOR_CODE_CLOSE..": "..text); end
end

function AutoBuff_Seperator()
	DEFAULT_CHAT_FRAME:AddMessage("-");
end

function AutoBuff_WHEELU()	-- Hook for scrollwheel-up
	AutoBuff_Check(1);
	AutoBuff_WHEELUx();
end
function AutoBuff_WHEELD()	-- Hook for scrollwheel-down
	AutoBuff_Check(2);
	AutoBuff_WHEELDx();
end
function AutoBuff_TARGET()	-- Hook for target-switching
	AutoBuff_Check(3);
end

function AutoBuff_JMP()
	AutoBuff_Check(4);
	AutoBuff_JMPx();
end
function AutoBuff_MFS()							-- These are the hook functions for movement
	vSit = 0;
	AutoBuff_Check(1);
	AutoBuff_MFSx();
end
function AutoBuff_MBS()
	vSit = 0;
	AutoBuff_Check(1);
	AutoBuff_MBSx();
end
function AutoBuff_TLS()
	vSit = 0;
	AutoBuff_Check(3);
	AutoBuff_TLSx();
end
function AutoBuff_TRS()
	vSit = 0;
	AutoBuff_Check(3);
	AutoBuff_TRSx();
end
function AutoBuff_SLS()
	vSit = 0;
	AutoBuff_Check(2);
	AutoBuff_SLSx();
end
function AutoBuff_SRS()
	vSit = 0;
	AutoBuff_Check(2);
	AutoBuff_SRSx();
end
function AutoBuff_MFF()
	AutoBuff_Check(1);
	AutoBuff_MFFx();
end
function AutoBuff_MBF()
	AutoBuff_Check(1);
	AutoBuff_MBFx();
end
function AutoBuff_TLF()
	AutoBuff_Check(3);
	AutoBuff_TLFx();
end
function AutoBuff_TRF()
	AutoBuff_Check(3);
	AutoBuff_TRFx();
end
function AutoBuff_SLF()
	AutoBuff_Check(2);
	AutoBuff_SLFx();
end
function AutoBuff_SRF()
	AutoBuff_Check(2);
	AutoBuff_SRFx();
end
function AutoBuff_TAR()
	AutoBuff_Check(1);
	AutoBuff_TARx();
end
function AutoBuff_TAS(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
	AutoBuff_Check(6);
	AutoBuff_TASx(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
end
function AutoBuff_TAF(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
	AutoBuff_Check(6);
	AutoBuff_TAFx(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
end
function AutoBuff_CMS(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
	AutoBuff_Check(5);
	AutoBuff_CMSx(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
end
function AutoBuff_CMF(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
	AutoBuff_Check(5);
	AutoBuff_CMFx(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
end

function AutoBuff_Option(n, o, z, s)
	if (s == nil) then s = ""; end
	if (type(n) == "string") and (strlen(n) < 1) then n = nil; end
	local a,b,c = "|cffffa0a0nil","|cffa0ffa0nil","|cffa0a0ffnil";
	if (n) then a = "|cffffa0a0"..n; end
	if (o) then b = "|cffa0ffa0"..o; end
	if (z) then c = "|cffa0a0ff"..z; end
--	AutoBuff_Debug("Option -> "..a.." "..b.." "..c);
	if (not o) then return; end
	if (not n) then n = 'd'; end
	if (not vSpellList[n]) and (not vWeaponList[n]) and (not vTrackList[n]) and (not vAspectList[n]) and (not vSealList[n]) and (n ~= 'd') then return; end
	if (z == nil) then
		if (AutoBuff_Data[vC]['x'][n] ~= nil) then
				local r = AutoBuff_Data[vC]['x'][n][o];
				if (r ~= nil) then
					return r;
				end
			end
	else
		if (z == "default") then z = nil; end
		if (AutoBuff_Data[vC]['x'][n] == nil) then AutoBuff_Data[vC]['x'][n] = {}; end
		AutoBuff_Data[vC]['x'][n][o] = z;
		
		-- Output
		if (s == 1) then
			if (n == 'd') then n = "default"; end
			n = "'|cffffffa0"..n..FONT_COLOR_CODE_CLOSE.."'";
			if (z == nil) then z = "default"; end
			if (o == 'm') then s = "|cff5e9ae4mana";
			elseif (o == 'h') then s = "|cffffa0a0health";
			elseif (o == 'c') then s = "|cfff0802ecombat";
			elseif (o == 'r') then s = "|cffa0a0a0rebuff";
			elseif (o == 't') then s = "|cffc0c0c0trigger";
			elseif (o == 'k') then s = "|cffffa0ffrank";
			end
			if (s ~= 1) then
				s = s..FONT_COLOR_CODE_CLOSE;
				z = "|cffa0ffa0"..z..FONT_COLOR_CODE_CLOSE;
				AutoBuff_Print(string.format(AUTOBUFF_CHANGE,s,n,z));
			elseif (o == 'd') then
				if (z == 1) then o = "|cffffa0a0"..AUTOBUFF_DISABLED;
				else o = "|cffa0ffa0"..AUTOBUFF_ENABLED; end
				o = o..FONT_COLOR_CODE_CLOSE;
				AutoBuff_Print(n..", "..o);
			end
		end
	end
	if (n ~= 'd') and (AutoBuff_Data[vC]['x'][n] ~= nil) then
		local v,k,empty = nil,nil,1;
		for v, k in AutoBuff_Data[vC]['x'][n] do empty = nil; break; end
		if (empty) then AutoBuff_Data[vC]['x'][n] = nil; end
	end
end

function AutoBuff_TrackLoad(s)
	local x = AutoBuff_Data[vC]['t'];				-- Get stored tracking ability
	local d = AutoBuff_TableIndex(vTrackList,0);
	local z;
	if (d) then d = string.lower(d); end
	if (x) then
		x = string.lower(x);
		if (x == "off") then
			z = nil;			
		elseif (vTrackList[x]) and (AutoBuff_Ability(x)) then
			z = x;
		elseif (d) then
			x = d;
			z = d;
		end
	elseif (d) then
		x = d;
		z = d;
	else
		z = nil;
		x = "off";
	end
	AutoBuff_Data[vC]['t'] = x;
	vTrack = z;
	if (z) then
		z = "'|cffa0ffa0"..z..FONT_COLOR_CODE_CLOSE.."'";
	else
		z = "'|cffffa0a0".."off"..FONT_COLOR_CODE_CLOSE.."'";
	end
	if (s == "show") then AutoBuff_Print(AUTOBUFF_CHANGE_TRACK..", "..z); end
end

function AutoBuff_AspectLoad(s)
	local x = AutoBuff_Data[vC]['a'];				-- Get stored aspect ability
	local d = AutoBuff_TableIndex(vAspectList,0);
	local z;
	if (d) then d = string.lower(d); end
	if (x) then
		x = string.lower(x);
		if (x == "off") then
			z = nil;			
		elseif (vAspectList[x]) and (AutoBuff_Ability(x)) then
			z = x;
		elseif (d) then
			x = d;
			z = d;
		end
	elseif (d) then
		x = d;
		z = d;
	else
		z = nil;
		x = "off";
	end
	AutoBuff_Data[vC]['a'] = x;
	vAspect = z;
	if (z) then
		z = "'|cffa0ffa0"..z..FONT_COLOR_CODE_CLOSE.."'";
	else
		z = "'|cffffa0a0".."off"..FONT_COLOR_CODE_CLOSE.."'";
	end
	if (s == "show") then AutoBuff_Print(AUTOBUFF_CHANGE_ASPECT..", "..z); end
end

function AutoBuff_SealLoad(s)
	local x = AutoBuff_Data[vC]["seal"];				-- Get stored seal ability
	local d = AutoBuff_TableIndex(vSealList,0);
	local z;
	if (d) then d = string.lower(d); end
	if (x) then
		x = string.lower(x);
		if (x == "off") then
			z = nil;			
		elseif (vSealList[x]) and (AutoBuff_Ability(x)) then
			z = x;
		elseif (d) then
			x = d;
			z = d;
		end
	elseif (d) then
		x = d;
		z = d;
	else
		z = nil;
		x = "off";
	end
	AutoBuff_Data[vC]["seal"] = x;
	vSeal = z;
	if (z) then
		z = "'|cffa0ffa0"..z..FONT_COLOR_CODE_CLOSE.."'";
	else
		z = "'|cffffa0a0".."off"..FONT_COLOR_CODE_CLOSE.."'";
	end
	if (s == "show") then AutoBuff_Print(AUTOBUFF_CHANGE_SEAL..", "..z); end
end

function AutoBuff_WeaponLoad(s)
	local x = AutoBuff_Data[vC]['w'];				-- Get stored weapon ability
	local d = AutoBuff_TableIndex(vWeaponList,0);
	local z;
	if (d) then d = string.lower(d); end
	if (x) then
		x = string.lower(x);
		if (x == "off") then
			z = nil;
		elseif (vWeaponList[x]) and (AutoBuff_Ability(x)) then
			z = x;
		elseif (d) then
			z = d;
			x = d;
		end
	elseif (d) then
		z = d;
		x = d;
	else
		z = nil;
		x = "off";
	end
	AutoBuff_Data[vC]['w'] = x;
	vWeapon = z;
	if (z) then
		z = "'|cffa0ffa0"..z..FONT_COLOR_CODE_CLOSE.."'";
	else
		z = "'|cffffa0a0".."off"..FONT_COLOR_CODE_CLOSE.."'";
	end
	if (s == "show") then AutoBuff_Print(AUTOBUFF_CHANGE_WEAPON..", "..z); end
end

function AutoBuff_LoadDefaults()
	if (not AutoBuff_Data) then AutoBuff_Data = { }; end
	if (AutoBuff_Data[vC] == nil) then AutoBuff_Data[vC] = { }; end
	if (AutoBuff_Data[vC]['version']) then AutoBuff_Data = { [vC] = {} }; end
	table.foreach(cDefault, AutoBuff_CheckDefaults);
	if (AutoBuff_Data[vC]['x'] == nil) then AutoBuff_Data[vC]['x'] = {}; end
	if (AutoBuff_Data[vC]['x']['d'] == nil) then AutoBuff_Data[vC]['x']['d'] = {}; end
	table.foreach(cDefault['x']['d'], AutoBuff_CheckDefaults_Ability);
	if (AutoBuff_Data[vC]['v'] ~= cDefault['v']) then AutoBuff_Upgrade(AutoBuff_Data[vC]['v']); end
end

function AutoBuff_Upgrade(ver)
	local c = cDefault['v']
	--if (ver < 31) then
		--AutoBuff_Data[vC]['h'] = cDefault['h'];
	--end
	AutoBuff_Data[vC]['v'] = c;
end

function AutoBuff_CheckSpellList()
	local iName, xName;
	for iName, xName in AutoBuff_Data[vC]['x'] do
		if (iName ~= "d") and (not vSpellList[iName]) and (not vWeaponList[iName]) and (not vTrackList[iName]) and (not vAspectList[iName]) and (not vSealList[iName]) then AutoBuff_Data[vC]['x'][iName] = nil; end
	end
end

function AutoBuff_CheckDefaults(index, value)
	if (AutoBuff_Data[vC][index] == nil) then AutoBuff_Data[vC][index] = cDefault[index]; end
end

function AutoBuff_CheckDefaults_Ability(index, value)
	if (AutoBuff_Data[vC]['x']['d'][index] == nil) then AutoBuff_Data[vC]['x']['d'][index] = cDefault['x']['d'][index]; end
end

function AutoBuff_Reload()
	AutoBuffFrame_Close();
	vSpellList = { };
	vTrackList = { };
	vWeaponList = { };
	vAspectList = { };
	vSealList = { };
	vTrack = nil;
	vWeapon = nil;
	vAspect = nil;
	vSeal = nil;
	AutoBuff_Debug("Total spells available -> "..table.getn(cSpellList));
	local iName, xName;
	local powertype = UnitPowerType("player"); -- 0 mana, 1 rage, 2 focus, 3 energy
	for iName, xName in cSpellList do
		if AutoBuff_Ability(iName) and (xName.pwt == nil or xName.pwt == powertype or xName.pwt == 3) then
			AutoBuff_Debug("Adding Ability -> "..iName);
			vSpellList[string.lower(iName)] = xName;
			local rank = AutoBuff_GetHighestSpellRank(iName);
			if (rank) then vSpellList[string.lower(iName)]['k'] = rank; end
		end
	end
							-- Same for tracking abilities..
	AutoBuff_Debug("Total track available -> "..table.getn(cTrackList));
	for iName, xName in cTrackList do
		if (AutoBuff_Ability(iName)) then
			AutoBuff_Debug("Adding Track -> "..iName);
			vTrackList[string.lower(iName)] = xName;
		end
	end
							-- EMERALD: aspect buffs
	AutoBuff_Debug("Total aspect available -> "..table.getn(cAspectList));
	for iName, xName in cAspectList do
		if AutoBuff_Ability(iName) and powertype == 0 then
			AutoBuff_Debug("Adding Aspect -> "..iName);
			vAspectList[string.lower(iName)] = xName;
		end
	end
							-- EMERALD: seal buffs
	AutoBuff_Debug("Total seals available -> "..table.getn(cSealList));
	for iName, xName in cSealList do
		if AutoBuff_Ability(iName) and powertype == 0 then
			AutoBuff_Debug("Adding Seal -> "..iName);
			vSealList[string.lower(iName)] = xName;
			local rank = AutoBuff_GetHighestSpellRank(iName);
			if (rank) then vSealList[string.lower(iName)]['k'] = rank; end
		end
	end
							-- And weapon buffs...
	AutoBuff_Debug("Total weaponbuff available -> "..table.getn(cWeaponList));
	for iName, xName in cWeaponList do
		if (AutoBuff_Ability(iName)) then
			AutoBuff_Debug("Adding WeaponBuff -> "..iName);
			vWeaponList[string.lower(iName)] = xName;
			local rank = AutoBuff_GetHighestSpellRank(iName);
			if (rank) then vWeaponList[string.lower(iName)] = rank; end
		end
	end
	
	AutoBuff_setn(vSpellList);
	AutoBuff_setn(vWeaponList);
	AutoBuff_setn(vTrackList);
	AutoBuff_setn(vAspectList);
	AutoBuff_setn(vSealList);
							-- Some spells overwrite others, or are higher ranked
							-- versions of another spell but with a different name.
							-- So we make sure only the best version is in the table

	-- akpatch: removed class checks for multiclass play						
	if vSpellList[string.lower(AUTOBUFF_ABILITY_ICE_ARMOR)] then vSpellList[string.lower(AUTOBUFF_ABILITY_FROST_ARMOR)] = nil; end
	if vSpellList[string.lower(AUTOBUFF_ABILITY_DEMON_ARMOR)] then vSpellList[string.lower(AUTOBUFF_ABILITY_DEMON_SKIN)] = nil; end
	if vSpellList[string.lower(AUTOBUFF_ABILITY_DETECT_GINVIS)] then vSpellList[string.lower(AUTOBUFF_ABILITY_DETECT_INVIS)] = nil; vSpellList[string.lower(AUTOBUFF_ABILITY_DETECT_LINVIS)] = nil;
	elseif vSpellList[string.lower(AUTOBUFF_ABILITY_DETECT_INVIS)] then vSpellList[string.lower(AUTOBUFF_ABILITY_DETECT_LINVIS)] = nil;
	end

	AutoBuff_TrackLoad();				-- Checks for available Tracking Abilities
	AutoBuff_WeaponLoad();
	AutoBuff_AspectLoad();
	AutoBuff_SealLoad();
	--AutoBuff_CheckSpellList(); -- Checks the disabled, mana, and combat tables for spells that this character can't use.
	-- если не закомментировать, то будут теряться умения после переключений разных классов
end

--[[ Dialog control functions ]]
function AutoBuffFrame_OnShow()
	PlaySound("igMainMenuOpen");
	AutoBuffFrameCheckButton:SetChecked(AutoBuff_Data[vC]['e']);
	if (AutoBuff_Data[vC]['e']) then
		AutoBuffFrameAbility:Show();
		AutoBuff_Populate();
	else
		AutoBuffFrameAbility:Hide();
	end
end

function AutoBuffFrame_OnHide()
	PlaySound("igMainMenuClose");
end

function AutoBuffFrame_Toggle()
		vGUI = {};
		vGUI['m'] = { [1] = "default" }; -- EMERALD: Line 2205 bug (nil on field 'm')
    AutoBuffFrame:StopMovingOrSizing();
	if (not AutoBuffFrame:IsVisible()) then
		AutoBuffFrame_Open();
	else
		AutoBuffFrame_Close();
	end
end

function AutoBuffFrame_Open()
	ShowUIPanel(AutoBuffFrame);
end

function AutoBuffFrame_Close()
	AutoBuffFrame:StopMovingOrSizing();
	HideUIPanel(AutoBuffFrame);
	
	-- myAddOns window
	if(MYADDONS_ACTIVE_OPTIONSFRAME == AutoBuffFrame) then ShowUIPanel(myAddOnsFrame); end
end

function AutoBuff_Populate()
	local i,v,k,x,r,g,b = 1,nil,nil,nil,0.4,0.4,0.4;
	for x=1,AUTOBUFF_GUI_ABILITY_TOTALROWS do
		getglobal("AutoBuffName"..x):UnlockHighlight();
	end
	vGUI['m'] = { [1] = "default" };
	AutoBuff_PopulateInsert(1, AUTOBUFF_GUI_DEFAULTABILITY, 0.6, 0.6, 1)
	if (table.getn(vSpellList) > 0) then
	    --[[ akpatch: освобождаем строку
		i=i+1;
		AutoBuff_PopulateInsert(2, "- "..AUTOBUFF_GUI_SPELLS, 1, 1, 1);
		getglobal("AutoBuffName"..i):Disable(); ]]

		--for v, k in vSpellList do
		k = 1;
		while (k > -1) do
			v = AutoBuff_SpellList(k);
			if (not v) then break; end
			v = string.lower(v);
			if (vSpellList[v]) then
				i = i+1;
				if (AutoBuff_Option(v, 'd')) then r,g,b = 1, 0.6, 0.6; else r,g,b = 0.6, 1, 0.6; end
				AutoBuff_PopulateInsert(i, AutoBuff_CorrectName(v), r, g, b);
				vGUI['m'][i] = "spell";
			end
			k = k+1;
		end
	end
	if (table.getn(vWeaponList) > 0) then
		i = i+1;
		AutoBuff_PopulateInsert(i, "- "..AUTOBUFF_GUI_WEAPON, 1, 1, 1);
		getglobal("AutoBuffName"..i):Disable();
		for v, k in vWeaponList do
			i = i+1;
			if (v == vWeapon) then r,g,b = 0.6, 1, 0.6; else r,g,b = 1, 0.6, 0.6; end
			AutoBuff_PopulateInsert(i, AutoBuff_CorrectName(v), r, g, b);
			vGUI['m'][i] = "weapon";
		end
	end
	if (table.getn(vTrackList) > 0) then
		i = i+1;
		AutoBuff_PopulateInsert(i, "- "..AUTOBUFF_GUI_TRACK, 1, 1, 1);
		getglobal("AutoBuffName"..i):Disable();
		for v, k in vTrackList do
			i = i+1;
			if (v == vTrack) then r,g,b = 0.6, 1, 0.6; else r,g,b = 1, 0.6, 0.6; end
			AutoBuff_PopulateInsert(i, AutoBuff_CorrectName(v), r, g, b);
			vGUI['m'][i] = "track";
		end
	end
	if (table.getn(vAspectList) > 0) then
	    --[[ akpatch: освобождаем строку
		i = i+1;
		AutoBuff_PopulateInsert(i, "- "..AUTOBUFF_GUI_ASPECT, 1, 1, 1);
		getglobal("AutoBuffName"..i):Disable(); ]]

		for v, k in vAspectList do
			i = i+1;
			if (v == vAspect) then r,g,b = 0.6, 1, 0.6; else r,g,b = 1, 0.6, 0.6; end
			AutoBuff_PopulateInsert(i, AutoBuff_CorrectName(v), r, g, b);
			vGUI['m'][i] = "aspect";
		end
	end
	if (table.getn(vSealList) > 0) then
		i = i+1;
		AutoBuff_PopulateInsert(i, "- "..AUTOBUFF_GUI_SEAL, 1, 1, 1);
		getglobal("AutoBuffName"..i):Disable();
		for v, k in vSealList do
			i = i+1;
			if (v == vSeal) then r,g,b = 0.6, 1, 0.6; else r,g,b = 1, 0.6, 0.6; end
			AutoBuff_PopulateInsert(i, AutoBuff_CorrectName(v), r, g, b);
			vGUI['m'][i] = "seal";
		end
	end
	AutoBuffFrameAbility:SetHeight(AUTOBUFF_GUI_ABILITY_OVERHEAD + (AUTOBUFF_GUI_ABILITY_INTERVAL*i));
	AutoBuffFrameOptions:Hide();
end

function AutoBuff_PopulateInsert(n, t, r, g, b)
	local itemButton = getglobal("AutoBuffName"..n);
	local itemText = getglobal("AutoBuffName"..n.."_Text");
	if (t) and (n <= AUTOBUFF_GUI_ABILITY_TOTALROWS) then
		itemText:SetText(t);
		itemText:SetTextColor(r, g, b, 1);
		itemButton:Enable();
		itemButton:Show();
	end	
end

function AutoBuffFrameCloseButton_OnClick()
	AutoBuffFrame_Close();
end

function AutoBuffFrame_ResetAbility()
	vGUI['r'] = 1;
	local x,y;

	AutoBuffFrameOptionsDefaultAbility:Hide();

	AutoBuffFrameOptionsEnable_Text:Show();
	AutoBuffFrameOptionsEnableButton:Show();
	AutoBuffFrameOptionsEnableButton:SetChecked(0);

	AutoBuffFrameOptionsDefaultTrigger_Text:Hide();
	AutoBuffFrameOptionsTrigger_Text:Hide();
	AutoBuffFrameOptionsTriggerDefaultButton:Hide();
	AutoBuffFrameOptionsTriggerDefaultButton:SetChecked(0);
	AutoBuffFrameOptionsTriggerWheelUp_Text:Hide();
	AutoBuffFrameOptionsTriggerWheelUpButton:Hide();
	AutoBuffFrameOptionsTriggerWheelUpButton:SetChecked(0);
	AutoBuffFrameOptionsTriggerWheelDown_Text:Hide();
	AutoBuffFrameOptionsTriggerWheelDownButton:Hide();
	AutoBuffFrameOptionsTriggerWheelDownButton:SetChecked(0);
	AutoBuffFrameOptionsTriggerTarget_Text:Hide();
	AutoBuffFrameOptionsTriggerTargetButton:Hide();
	AutoBuffFrameOptionsTriggerTargetButton:SetChecked(0);
	
	
	AutoBuffFrameOptionsCombat_Text:ClearAllPoints();
	--AutoBuffFrameOptionsCombat_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsTrigger_Text", "BOTTOMLEFT", 0, -110)
	AutoBuffFrameOptionsCombat_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsTrigger_Text", "BOTTOMLEFT", 0, -55)
	AutoBuffFrameOptionsCombatDefaultButton:Hide();
	AutoBuffFrameOptionsCombatDefaultButton:SetChecked(0);
	AutoBuffFrameOptionsCombat_Text:Hide();
	AutoBuffFrameOptionsDefaultCombat_Text:Hide();
	AutoBuffFrameOptionsCombatIn_Text:Hide();
	AutoBuffFrameOptionsCombatInButton:Hide();
	AutoBuffFrameOptionsCombatInButton:SetChecked(0);
	AutoBuffFrameOptionsCombatOut_Text:Hide();
	AutoBuffFrameOptionsCombatOutButton:Hide();
	AutoBuffFrameOptionsCombatOutButton:SetChecked(0);
	AutoBuffFrameOptionsCombatAlways_Text:Hide();
	AutoBuffFrameOptionsCombatAlwaysButton:Hide();
	AutoBuffFrameOptionsCombatAlwaysButton:SetChecked(0);
	
	
	AutoBuffFrameOptionsParty_Text:ClearAllPoints();
	AutoBuffFrameOptionsParty_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsCombat_Text", "BOTTOMLEFT", 0, -25)
	AutoBuffFrameOptionsPartyDefaultButton:Hide();
	AutoBuffFrameOptionsPartyDefaultButton:SetChecked(0);
	AutoBuffFrameOptionsParty_Text:Hide();
	AutoBuffFrameOptionsDefaultParty_Text:Hide();
	AutoBuffFrameOptionsPartyIn_Text:Hide();
	AutoBuffFrameOptionsPartyInButton:Hide();
	AutoBuffFrameOptionsPartyInButton:SetChecked(0);
	AutoBuffFrameOptionsPartyOut_Text:Hide();
	AutoBuffFrameOptionsPartyOutButton:Hide();
	AutoBuffFrameOptionsPartyOutButton:SetChecked(0);
	AutoBuffFrameOptionsPartyAlways_Text:Hide();
	AutoBuffFrameOptionsPartyAlwaysButton:Hide();
	AutoBuffFrameOptionsPartyAlwaysButton:SetChecked(0);

	
	AutoBuffFrameOptionsHealth_Text:ClearAllPoints();
	AutoBuffFrameOptionsHealth_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsParty_Text", "BOTTOMLEFT", 0, -25)
	AutoBuffFrameOptionsHealthDefaultButton:Hide();
	AutoBuffFrameOptionsHealthDefaultButton:SetChecked(0);
	AutoBuffFrameOptionsHealth_Text:Hide();
	AutoBuffFrameOptionsDefaultHealth_Text:Hide();
	AutoBuffFrameOptionsHealth:Hide();
	x, y = AutoBuffFrameOptionsHealth:GetMinMaxValues();
	AutoBuffFrameOptionsHealth:SetValue(x);
	AutoBuffFrameOptionsHealth_ValueText:Hide();
	AutoBuffFrameOptionsHealth_ValueText:SetText("#");
	AutoBuffFrameOptionsHealthButton:Hide();
	AutoBuffFrameOptionsHealthButton:SetChecked(0);
	
	AutoBuffFrameOptionsManaDefaultButton:Hide();
	AutoBuffFrameOptionsManaDefaultButton:SetChecked(0);
	AutoBuffFrameOptionsMana_Text:Hide();
	AutoBuffFrameOptionsDefaultMana_Text:Hide();
	AutoBuffFrameOptionsMana:Hide();
	x, y = AutoBuffFrameOptionsMana:GetMinMaxValues();
	AutoBuffFrameOptionsMana_ValueText:Hide();
	AutoBuffFrameOptionsMana_ValueText:SetText("#");
	AutoBuffFrameOptionsManaButton:Hide();
	AutoBuffFrameOptionsManaButton:SetChecked(0);
	
	AutoBuffFrameOptionsRebuffDefaultButton:Hide();
	AutoBuffFrameOptionsRebuffDefaultButton:SetChecked(0);
	AutoBuffFrameOptionsRebuff:Hide();
	x, y = AutoBuffFrameOptionsRebuff:GetMinMaxValues();
	AutoBuffFrameOptionsRebuff:SetValue(x);
	AutoBuffFrameOptionsDefaultRebuff_Text:Hide();
	AutoBuffFrameOptionsRebuff_Text:Hide();
	AutoBuffFrameOptionsRebuff_ValueText:Hide();
	AutoBuffFrameOptionsRebuff_ValueText:SetText("#");
	
	AutoBuffFrameOptionsRankDefaultButton:Hide();
	AutoBuffFrameOptionsRankDefaultButton:SetChecked(0);
	AutoBuffFrameOptionsRank:Hide();
	x, y = AutoBuffFrameOptionsRank:GetMinMaxValues();
	AutoBuffFrameOptionsRank:SetValue(x);
	AutoBuffFrameOptionsDefaultRank_Text:Hide();
	AutoBuffFrameOptionsRank_Text:Hide();
	AutoBuffFrameOptionsRank_ValueText:Hide();
	AutoBuffFrameOptionsRank_ValueText:SetText("#");
	AutoBuffFrameOptionsRank_Text:ClearAllPoints();
	AutoBuffFrameOptionsRank_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsRebuff_Text", "BOTTOMLEFT", 0, -9)
	AutoBuffFrameOptions:Show();
	AutoBuffFrameOptions:SetHeight(40);
	vGUI['r'] = nil;
end

function AutoBuffNameButton_OnClick(s)
	if (vGUI['r']) then return; end
	local n = string.lower(getglobal("AutoBuffName"..s.."_Text"):GetText());
	local t,x;
	if (vGUI['s']) then getglobal("AutoBuffName"..vGUI['s']):UnlockHighlight(); end
	vGUI['s'] = s;
	getglobal("AutoBuffName"..s):LockHighlight();
	AutoBuffFrame_ResetAbility();
	if (s == 1) then n = nil; end
	vGUI['n'] = n;
	x = vGUI['m'][s];
	if (x == "default") then
		AutoBuffFrameOptionsEnable_Text:Hide();
		AutoBuffFrameOptionsEnableButton:Hide();
		AutoBuffFrameOptionsDefaultAbility:Show();
		AutoBuffFrameOptions:SetHeight(295); -- JURYRIG
		--AutoBuffFrameOptions:SetHeight(340);
		
		AutoBuffFrameOptionsTrigger_Text:Show();
		AutoBuffFrameOptionsTriggerWheelUp_Text:Show();
		AutoBuffFrameOptionsTriggerWheelUpButton:Show();
		AutoBuffFrameOptionsTriggerWheelDown_Text:Show();
		AutoBuffFrameOptionsTriggerWheelDownButton:Show();
		AutoBuffFrameOptionsTriggerTarget_Text:Show();
		AutoBuffFrameOptionsTriggerTargetButton:Show();
		
		AutoBuffFrameOptionsCombat_Text:Show();
		AutoBuffFrameOptionsCombatIn_Text:Show();
		AutoBuffFrameOptionsCombatInButton:Show();
		AutoBuffFrameOptionsCombatOut_Text:Show();
		AutoBuffFrameOptionsCombatOutButton:Show();
		AutoBuffFrameOptionsCombatAlways_Text:Show();
		AutoBuffFrameOptionsCombatAlwaysButton:Show();
		
		AutoBuffFrameOptionsParty_Text:Show();
		AutoBuffFrameOptionsPartyIn_Text:Show();
		AutoBuffFrameOptionsPartyInButton:Show();
		AutoBuffFrameOptionsPartyOut_Text:Show();
		AutoBuffFrameOptionsPartyOutButton:Show();
		AutoBuffFrameOptionsPartyAlways_Text:Show();
		AutoBuffFrameOptionsPartyAlwaysButton:Show();
		AutoBuffFrameOptionsHealth_Text:Show();
		AutoBuffFrameOptionsHealth:Show();
		AutoBuffFrameOptionsHealth_ValueText:Show();
		AutoBuffFrameOptionsHealthButton:Show();
		AutoBuffFrameOptionsMana_Text:Show();
		AutoBuffFrameOptionsMana:Show();
		AutoBuffFrameOptionsMana_ValueText:Show();
		AutoBuffFrameOptionsManaButton:Show();
		AutoBuffFrameOptionsRebuff:Show();
		AutoBuffFrameOptionsRebuff_Text:Show();
		AutoBuffFrameOptionsRebuff_ValueText:Show();
		
		local trigger = AutoBuff_Trigger('d');
		AutoBuffFrameOptionsTriggerWheelUpButton:SetChecked(trigger[1]);
		AutoBuffFrameOptionsTriggerWheelDownButton:SetChecked(trigger[2]);
		AutoBuffFrameOptionsTriggerTargetButton:SetChecked(trigger[3]);
		
		if (AutoBuff_Option(n, 'c') == 1) then AutoBuffFrameOptionsCombatInButton:SetChecked(1); end
		if (AutoBuff_Option(n, 'c') == 2) then AutoBuffFrameOptionsCombatOutButton:SetChecked(1); end
		if (AutoBuff_Option(n, 'c') == 3) then AutoBuffFrameOptionsCombatAlwaysButton:SetChecked(1); end
		
		if (AutoBuff_Option(n, 'p') == 1) then AutoBuffFrameOptionsPartyInButton:SetChecked(1); end
		if (AutoBuff_Option(n, 'p') == 2) then AutoBuffFrameOptionsPartyOutButton:SetChecked(1); end
		if (AutoBuff_Option(n, 'p') == 3) then AutoBuffFrameOptionsPartyAlwaysButton:SetChecked(1); end
		
		t = AutoBuff_Option(n, 'h');
		if (t > 0) then
			AutoBuffFrameOptionsHealthButton:SetChecked(0);
			AutoBuffFrameOptionsHealth_ValueText:SetText(">"..t.."%");
			AutoBuffFrameOptionsHealth:SetValue(t);
		else
			t = t*-1;
			AutoBuffFrameOptionsHealthButton:SetChecked(1);
			AutoBuffFrameOptionsHealth_ValueText:SetText("<"..t.."%");
			AutoBuffFrameOptionsHealth:SetValue(t);
		end
		
		t = AutoBuff_Option(n, 'm');
		if (t > 0) then
			AutoBuffFrameOptionsManaButton:SetChecked(0);
			AutoBuffFrameOptionsMana:SetValue(t);
			AutoBuffFrameOptionsMana_ValueText:SetText(">"..t.."%");
		else
			t = t*-1;
			AutoBuffFrameOptionsManaButton:SetChecked(1);
			AutoBuffFrameOptionsMana:SetValue(t);
			AutoBuffFrameOptionsMana_ValueText:SetText("<"..t.."%");
		end
		
		t = AutoBuff_Option(n, 'r');
		AutoBuffFrameOptionsRebuff:SetValue(t);
		AutoBuffFrameOptionsRebuff_ValueText:SetText(AutoBuffFrame_RebuffValueText(t));
		
		
	-- elseif (vGUI['m'][s] == "track") then
		-- if (vTrack == n) then AutoBuffFrameOptionsEnableButton:SetChecked(1); end
	-- elseif (vGUI['m'][s] == "aspect") then
		-- if (vAspect == n) then AutoBuffFrameOptionsEnableButton:SetChecked(1); end
	-- elseif (vGUI['m'][s] == "seal") then
		-- if (vSeal == n) then AutoBuffFrameOptionsEnableButton:SetChecked(1); end
	--elseif (x ~= "track" and x ~= "aspect" and x ~= "seal") then
	else
		--if ((x == "spell") and (not AutoBuff_Option(n, 'd'))) or ((x == "weapon") and (vWeapon == n)) then
		if ((x == "spell") and (not AutoBuff_Option(n, 'd'))) or ((x == "weapon") and (vWeapon == n)) or ((x == "track") and (vTrack == n)) or ((x == "aspect") and (vAspect == n)) or ((x == "seal") and (vSeal == n)) then
			AutoBuffFrameOptionsEnableButton:SetChecked(1);
			local height = 370;
			
			AutoBuffFrameOptionsCombatDefaultButton:Show();
			AutoBuffFrameOptionsCombat_Text:Show();
			AutoBuffFrameOptionsCombatIn_Text:Show();
			AutoBuffFrameOptionsCombatInButton:Show();
			AutoBuffFrameOptionsCombatOut_Text:Show();
			AutoBuffFrameOptionsCombatOutButton:Show();
			AutoBuffFrameOptionsCombatAlways_Text:Show();
			AutoBuffFrameOptionsCombatAlwaysButton:Show();
			
			AutoBuffFrameOptionsPartyDefaultButton:Show();
			AutoBuffFrameOptionsParty_Text:Show();
			AutoBuffFrameOptionsPartyIn_Text:Show();
			AutoBuffFrameOptionsPartyInButton:Show();
			AutoBuffFrameOptionsPartyOut_Text:Show();
			AutoBuffFrameOptionsPartyOutButton:Show();
			AutoBuffFrameOptionsPartyAlways_Text:Show();
			AutoBuffFrameOptionsPartyAlwaysButton:Show();
			
			AutoBuffFrameOptionsHealthDefaultButton:Show();
			AutoBuffFrameOptionsHealth_Text:Show();
			AutoBuffFrameOptionsHealth:Show();
			AutoBuffFrameOptionsHealth_ValueText:Show();
			AutoBuffFrameOptionsHealthButton:Show();
			AutoBuffFrameOptionsManaDefaultButton:Show();
			AutoBuffFrameOptionsMana_Text:Show();
			AutoBuffFrameOptionsMana:Show();
			AutoBuffFrameOptionsMana_ValueText:Show();
			AutoBuffFrameOptionsManaButton:Show();
			AutoBuffFrameOptionsRebuffDefaultButton:Show();
			AutoBuffFrameOptionsRebuff:Show();
			AutoBuffFrameOptionsRebuff_Text:Show();
			AutoBuffFrameOptionsRebuff_ValueText:Show();
			
			AutoBuffFrameOptionsRankDefaultButton:Show();
			AutoBuffFrameOptionsRank:Show();
			AutoBuffFrameOptionsRank_Text:Show();
			AutoBuffFrameOptionsRank_ValueText:Show();
			
			AutoBuffFrameOptionsTrigger_Text:Show();
			AutoBuffFrameOptionsTriggerDefaultButton:Show();
			AutoBuffFrameOptionsTriggerWheelUp_Text:Show();
			AutoBuffFrameOptionsTriggerWheelUpButton:Show();
			AutoBuffFrameOptionsTriggerWheelDown_Text:Show();
			AutoBuffFrameOptionsTriggerWheelDownButton:Show();
			AutoBuffFrameOptionsTriggerTarget_Text:Show();
			AutoBuffFrameOptionsTriggerTargetButton:Show();
			
			if (AutoBuff_Option(n, 't')) then
				AutoBuffFrameOptionsTriggerDefaultButton:SetChecked(1);
				local trigger = AutoBuff_Trigger(n);
				AutoBuffFrameOptionsTriggerWheelUpButton:SetChecked(trigger[1]);
				AutoBuffFrameOptionsTriggerWheelDownButton:SetChecked(trigger[2]);
				AutoBuffFrameOptionsTriggerTargetButton:SetChecked(trigger[3]);
				height = height - 55;
			else
				AutoBuffFrameOptionsDefaultTrigger_Text:Show();
				AutoBuffFrameOptionsTriggerWheelUp_Text:Hide();
				AutoBuffFrameOptionsTriggerWheelUpButton:Hide();
				AutoBuffFrameOptionsTriggerWheelDown_Text:Hide();
				AutoBuffFrameOptionsTriggerWheelDownButton:Hide();
				AutoBuffFrameOptionsTriggerTarget_Text:Hide();
				AutoBuffFrameOptionsTriggerTargetButton:Hide();
				AutoBuffFrameOptionsCombat_Text:ClearAllPoints();
				AutoBuffFrameOptionsCombat_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsTrigger_Text", "BOTTOMLEFT", 0, -9);
				height = height - 105;
			end
			
			if (AutoBuff_Option(n, 'c')) then
				AutoBuffFrameOptionsCombatDefaultButton:SetChecked(1);
				if (AutoBuff_Option(n, 'c') == 1) then AutoBuffFrameOptionsCombatInButton:SetChecked(1); end
				if (AutoBuff_Option(n, 'c') == 2) then AutoBuffFrameOptionsCombatOutButton:SetChecked(1); end
				if (AutoBuff_Option(n, 'c') == 3) then AutoBuffFrameOptionsCombatAlwaysButton:SetChecked(1); end
			else
				AutoBuffFrameOptionsCombatIn_Text:Hide();
				AutoBuffFrameOptionsCombatInButton:Hide();
				AutoBuffFrameOptionsCombatOut_Text:Hide();
				AutoBuffFrameOptionsCombatOutButton:Hide();
				AutoBuffFrameOptionsCombatAlways_Text:Hide();
				AutoBuffFrameOptionsCombatAlwaysButton:Hide();
				AutoBuffFrameOptionsDefaultCombat_Text:Show();
				AutoBuffFrameOptionsParty_Text:ClearAllPoints();
				AutoBuffFrameOptionsParty_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsCombat_Text", "BOTTOMLEFT", 0, -9)
				height = height - 15;
			end
			
			
			if (AutoBuff_Option(n, 'p')) then
				AutoBuffFrameOptionsPartyDefaultButton:SetChecked(1);
				if (AutoBuff_Option(n, 'p') == 1) then AutoBuffFrameOptionsPartyInButton:SetChecked(1); end
				if (AutoBuff_Option(n, 'p') == 2) then AutoBuffFrameOptionsPartyOutButton:SetChecked(1); end
				if (AutoBuff_Option(n, 'p') == 3) then AutoBuffFrameOptionsPartyAlwaysButton:SetChecked(1); end
			else
				AutoBuffFrameOptionsPartyIn_Text:Hide();
				AutoBuffFrameOptionsPartyInButton:Hide();
				AutoBuffFrameOptionsPartyOut_Text:Hide();
				AutoBuffFrameOptionsPartyOutButton:Hide();
				AutoBuffFrameOptionsPartyAlways_Text:Hide();
				AutoBuffFrameOptionsPartyAlwaysButton:Hide();
				AutoBuffFrameOptionsDefaultParty_Text:Show();
				AutoBuffFrameOptionsHealth_Text:ClearAllPoints();
				AutoBuffFrameOptionsHealth_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsParty_Text", "BOTTOMLEFT", 0, -9)
				height = height -15;
			end
			
			t = AutoBuff_Option(n, 'h');
			if (not t) then
				AutoBuffFrameOptionsHealth:Hide();
				AutoBuffFrameOptionsHealth_ValueText:Hide();
				AutoBuffFrameOptionsHealthButton:Hide();
				AutoBuffFrameOptionsDefaultHealth_Text:Show();
			else
				AutoBuffFrameOptionsHealthDefaultButton:SetChecked(1);
				if (t > 0) then
					AutoBuffFrameOptionsHealthButton:SetChecked(0);
					AutoBuffFrameOptionsHealth_ValueText:SetText(">"..t.."%");
					AutoBuffFrameOptionsHealth:SetValue(t);
				else
					t = t*-1;
					AutoBuffFrameOptionsHealthButton:SetChecked(1);
					AutoBuffFrameOptionsHealth_ValueText:SetText("<"..t.."%");
					AutoBuffFrameOptionsHealth:SetValue(t);
				end
			end
			
			t = AutoBuff_Option(n, 'm');
			if (not t) then
				AutoBuffFrameOptionsMana:Hide();
				AutoBuffFrameOptionsMana_ValueText:Hide();
				AutoBuffFrameOptionsManaButton:Hide();
				AutoBuffFrameOptionsDefaultMana_Text:Show();
			else
				AutoBuffFrameOptionsManaDefaultButton:SetChecked(1);
				if (t > 0) then
					AutoBuffFrameOptionsManaButton:SetChecked(0);
					AutoBuffFrameOptionsMana:SetValue(t);
					AutoBuffFrameOptionsMana_ValueText:SetText(">"..t.."%");
				else
					t = t*-1;
					AutoBuffFrameOptionsManaButton:SetChecked(1);
					AutoBuffFrameOptionsMana:SetValue(t);
					AutoBuffFrameOptionsMana_ValueText:SetText("<"..t.."%");
				end
			end
			--if (not AutoBuff_IsAura(n)) and (n ~= string.lower(AUTOBUFF_ABILITY_TRUESHOTAURA)) then
			if (not AutoBuff_IsAura(n)) then
				t = AutoBuff_Option(n, 'r');
				if (not t) then
					AutoBuffFrameOptionsRebuff:Hide();
					AutoBuffFrameOptionsRebuff_ValueText:Hide();
					AutoBuffFrameOptionsDefaultRebuff_Text:Show();
				else
					AutoBuffFrameOptionsRebuffDefaultButton:SetChecked(1);
					AutoBuffFrameOptionsRebuff:SetValue(t);
					AutoBuffFrameOptionsRebuff_ValueText:SetText(AutoBuffFrame_RebuffValueText(t));
				end
			else
				AutoBuffFrameOptionsRebuffDefaultButton:Hide();
				AutoBuffFrameOptionsRebuff:Hide();
				AutoBuffFrameOptionsRebuff_Text:Hide();
				AutoBuffFrameOptionsRebuff_ValueText:Hide();
				height = height - 28;
				AutoBuffFrameOptionsRank_Text:ClearAllPoints();
				AutoBuffFrameOptionsRank_Text:SetPoint("TOPLEFT", "AutoBuffFrameOptionsMana_Text", "BOTTOMLEFT", 0, -9)
			end
			local hr = 0;
			if (x == "weapon") then hr = vWeaponList[n]; end
			--if (x == "track") then hr = vTrackList[n]; end
			--if (x == "aspect") then hr = vAspectList[n]; end
			--if (x == "seal") then hr = vSealList[n]; end
			if (x == "spell") and (vSpellList[n]['k']) then hr = vSpellList[n]['k']; end
			--if (x == "track") and (vTrackList[n]['k']) then hr = vTrackList[n]['k']; end
			--if (x == "aspect") and (vAspectList[n]['k']) then hr = vAspectList[n]['k']; end
			if (x == "seal") and (vSealList[n]['k']) then hr = vSealList[n]['k']; end
			if (hr and hr > 1) then
				t = AutoBuff_Option(n, 'k');
				AutoBuffFrameOptionsRank:SetMinMaxValues(1, hr);
				if (not t) then
					AutoBuffFrameOptionsRank:Hide();
					AutoBuffFrameOptionsRank_ValueText:Hide();
					AutoBuffFrameOptionsDefaultRank_Text:Show();
				else
					AutoBuffFrameOptionsRankDefaultButton:SetChecked(1);
					AutoBuffFrameOptionsRank:SetValue(t);
					AutoBuffFrameOptionsRank_ValueText:SetText(t);
				end			
			else
				AutoBuffFrameOptionsRankDefaultButton:Hide();
				AutoBuffFrameOptionsRank:Hide();
				AutoBuffFrameOptionsRank_Text:Hide();
				AutoBuffFrameOptionsRank_ValueText:Hide();
				height = height - 28;
			end
			
			AutoBuffFrameOptions:SetHeight(height);
		end
	end
end

function AutoBuffFrame_OnClick()
	if (vGUI['r']) then return; end
	local s = vGUI['s'];
	local x = vGUI['m'][s];
	local frame, n = this:GetName(), vGUI['n']
		if (not frame) then return; end
		local c = this:GetChecked();
		if (frame == "AutoBuffFrameCheckButton") then
			if (not c or c==0) then AutoBuff_Off(); end -- EMERALD: Persistant on/off checkbox
			--else AutoBuff_On(); end
			if (not c or c==0) then
				AutoBuff_Off();
				AutoBuffFrameAbility:Hide();
			else
				AutoBuff_On();
				AutoBuffFrameAbility:Show();
				AutoBuff_Populate();
			end
		elseif (frame == "AutoBuffFrameOptionsEnableButton") then
			local t = vGUI['m'][(vGUI['s'])];
			if (t == "spell") then
				if (c == 1) then c = "default"; else c = 1; end
				AutoBuff_Option(n, 'd', c);
				if (AutoBuff_IsBlessing(n)) then AutoBuff_FixBlessing(n); end
				if (AutoBuff_IsAura(n)) then AutoBuff_FixAura(n); end
			elseif (t == "weapon") then
				if (c == 1) then AutoBuff_Data[vC]['w'] = vGUI['n'];
				else AutoBuff_Data[vC]['w'] = "off"; end
				AutoBuff_WeaponLoad();
			elseif (t == "track") then
				if (c == 1) then AutoBuff_Data[vC]['t'] = vGUI['n'];
				else AutoBuff_Data[vC]['t'] = "off"; end
				AutoBuff_TrackLoad();
			elseif (t == "aspect") then
				if (c == 1) then AutoBuff_Data[vC]['a'] = vGUI['n'];
				else AutoBuff_Data[vC]['a'] = "off"; end
				AutoBuff_AspectLoad();
			elseif (t == "seal") then
				if (c == 1) then AutoBuff_Data[vC]["seal"] = vGUI['n'];
				else AutoBuff_Data[vC]["seal"] = "off"; end
				AutoBuff_SealLoad();
			end
			AutoBuff_Populate();
			AutoBuffNameButton_OnClick(vGUI['s']);

		elseif (frame == "AutoBuffFrameOptionsHealthButton") then
			if (c == 1) then t = "<";
			else t = ">"; end
			AutoBuffFrameOptionsHealth_ValueText:SetText(t..AutoBuffFrameOptionsHealth:GetValue().."%");
			AutoBuff_Option(n, 'h', (AutoBuff_Option(n, 'h')*-1));
		elseif (frame == "AutoBuffFrameOptionsManaButton") then
			if (c == 1) then t = "<";
			else t = ">"; end
			AutoBuffFrameOptionsMana_ValueText:SetText(t..AutoBuffFrameOptionsMana:GetValue().."%");
			AutoBuff_Option(n, 'm', (AutoBuff_Option(n, 'm')*-1));
		elseif (frame == "AutoBuffFrameOptionsCombatInButton") then
			this:SetChecked(1);
			AutoBuffFrameOptionsCombatOutButton:SetChecked(0);
			AutoBuffFrameOptionsCombatAlwaysButton:SetChecked(0);
			AutoBuff_Option(n, 'c', 1);
		elseif (frame == "AutoBuffFrameOptionsCombatOutButton") then
			this:SetChecked(1);
			AutoBuffFrameOptionsCombatInButton:SetChecked(0);
			AutoBuffFrameOptionsCombatAlwaysButton:SetChecked(0);
			AutoBuff_Option(n, 'c', 2);
		elseif (frame == "AutoBuffFrameOptionsCombatAlwaysButton") then
			this:SetChecked(1);
			AutoBuffFrameOptionsCombatInButton:SetChecked(0);
			AutoBuffFrameOptionsCombatOutButton:SetChecked(0);
			AutoBuff_Option(n, 'c', 3);
		elseif (frame == "AutoBuffFrameOptionsCombatDefaultButton") then
			if (c == 1) then
				AutoBuff_Option(n, 'c', AutoBuff_Option('d', 'c'));
			else
				AutoBuff_Option(n, 'c', "default");
			end
			AutoBuffNameButton_OnClick(vGUI['s']);
			
		elseif (frame == "AutoBuffFrameOptionsPartyInButton") then
			this:SetChecked(1);
			AutoBuffFrameOptionsPartyOutButton:SetChecked(0);
			AutoBuffFrameOptionsPartyAlwaysButton:SetChecked(0);
			AutoBuff_Option(n, 'p', 1);
		elseif (frame == "AutoBuffFrameOptionsPartyOutButton") then
			this:SetChecked(1);
			AutoBuffFrameOptionsPartyInButton:SetChecked(0);
			AutoBuffFrameOptionsPartyAlwaysButton:SetChecked(0);
			AutoBuff_Option(n, 'p', 2);
		elseif (frame == "AutoBuffFrameOptionsPartyAlwaysButton") then
			this:SetChecked(1);
			AutoBuffFrameOptionsPartyInButton:SetChecked(0);
			AutoBuffFrameOptionsPartyOutButton:SetChecked(0);
			AutoBuff_Option(n, 'p', 3);
		elseif (frame == "AutoBuffFrameOptionsPartyDefaultButton") then
			if (c == 1) then
				AutoBuff_Option(n, 'p', AutoBuff_Option('d', 'p'));
			else
				AutoBuff_Option(n, 'p', "default");
			end
			AutoBuffNameButton_OnClick(vGUI['s']);
		
		
		elseif (frame == "AutoBuffFrameOptionsTriggerWheelUpButton") or
				(frame == "AutoBuffFrameOptionsTriggerWheelDownButton") or
				(frame == "AutoBuffFrameOptionsTriggerTargetButton") then
			local trigger = 0;
			if (AutoBuffFrameOptionsTriggerWheelUpButton:GetChecked() == 1) then trigger = trigger + 2^1; end
			if (AutoBuffFrameOptionsTriggerWheelDownButton:GetChecked() == 1) then trigger = trigger + 2^2; end
			if (AutoBuffFrameOptionsTriggerTargetButton:GetChecked() == 1) then trigger = trigger + 2^3; end
			AutoBuff_Option(n, 't', trigger);
		elseif (frame == "AutoBuffFrameOptionsTriggerDefaultButton") then
			if (c == 1) then
				AutoBuff_Option(n, 't', AutoBuff_Option('d', 't'));
			else
				AutoBuff_Option(n, 't', "default");
			end
			AutoBuffNameButton_OnClick(vGUI['s']);
		elseif (frame == "AutoBuffFrameOptionsHealthDefaultButton") then
			if (c == 1) then
				AutoBuff_Option(n, 'h', AutoBuff_Option('d', 'h'));
			else
				AutoBuff_Option(n, 'h', "default");
			end
			AutoBuffNameButton_OnClick(vGUI['s']);
		elseif (frame == "AutoBuffFrameOptionsManaDefaultButton") then
			if (c == 1) then
				AutoBuff_Option(n, 'm', AutoBuff_Option('d', 'm'));
			else
				AutoBuff_Option(n, 'm', "default");
			end
			AutoBuffNameButton_OnClick(vGUI['s']);
		elseif (frame == "AutoBuffFrameOptionsRebuffDefaultButton") then
			if (c == 1) then
				AutoBuff_Option(n, 'r', AutoBuff_Option('d', 'r'));
			else
				AutoBuff_Option(n, 'r', "default");
			end
			AutoBuffNameButton_OnClick(vGUI['s']);
		elseif (frame == "AutoBuffFrameOptionsRankDefaultButton") then
			if (c == 1) then
				local a, b = AutoBuffFrameOptionsRank:GetMinMaxValues();
				AutoBuff_Option(n, 'k', b);
			else
				AutoBuff_Option(n, 'k', "default");
			end
			AutoBuffNameButton_OnClick(vGUI['s']);
		end
end

function AutoBuffFrame_OnValueChanged()
	if (vGUI['r']) then return; end
	local frame = this:GetName();
	if (not frame) then return; end
	local c = this:GetValue();
	local t;
	if (frame == "AutoBuffFrameOptionsHealth") then
		if (AutoBuffFrameOptionsHealthButton:GetChecked() == 1) then t = "<"..c.."%"; c=c*-1;
		else t = ">"..c.."%"; end
		AutoBuffFrameOptionsHealth_ValueText:SetText(t);
		AutoBuff_Option(vGUI['n'],'h',c);
	elseif (frame == "AutoBuffFrameOptionsMana") then
		if (AutoBuffFrameOptionsManaButton:GetChecked() == 1) then t = "<"..c.."%"; c=c*-1;
		else t = ">"..c.."%"; end
		AutoBuffFrameOptionsMana_ValueText:SetText(t);
		AutoBuff_Option(vGUI['n'],'m',c);
	elseif (frame == "AutoBuffFrameOptionsRebuff") then
		AutoBuffFrameOptionsRebuff_ValueText:SetText(AutoBuffFrame_RebuffValueText(c));
		AutoBuff_Option(vGUI['n'], 'r', c);
	elseif (frame == "AutoBuffFrameOptionsRank") then
		AutoBuffFrameOptionsRank_ValueText:SetText(c);
		AutoBuff_Option(vGUI['n'], 'k', c);
	end
end

function AutoBuffFrame_RebuffValueText(c)
	c = tonumber(c);
	if (c == nil) then return; end
	local m = floor(c/60);
	local s = c - (m*60);
	local v = s.."s";
	if (m>0) and (s == 0) then v = m.."m";
	elseif (m>0) then v = m.."m"..v; end
	return v;
end


function AutoBuffFrame_Tooltip(arg1,arg2,arg3)
	if (not arg3) then arg3 = "ANCHOR_TOPLEFT"; end
	GameTooltip:SetOwner(this, arg3);
    GameTooltip:SetText(arg1);
    GameTooltip:AddLine(arg2, .75, .75, .75, 1);
    GameTooltip:Show();
end

function AutoBuffFrame_OnEnter()
	local frame = this:GetName();
	if (not frame) then return; end
	if (frame == "AutoBuffFrameCheckButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_ENABLE_TOOLTIP_TITLE, AUTOBUFF_GUI_ENABLE_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsEnableButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_ENABLEABILITY_TOOLTIP_TITLE, AUTOBUFF_GUI_ENABLEABILITY_TOOLTIP, "ANCHOR_BOTTOMRIGHT");
	elseif (frame == "AutoBuffFrameOptionsRebuff") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_REBUFF_TOOLTIP_TITLE, AUTOBUFF_GUI_REBUFF_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsHealth") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_HEALTH_TOOLTIP_TITLE, AUTOBUFF_GUI_HEALTH_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsMana") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_MANA_TOOLTIP_TITLE, AUTOBUFF_GUI_MANA_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsHealthButton") or (frame == "AutoBuffFrameOptionsManaButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_INVERT_TOOLTIP_TITLE, AUTOBUFF_GUI_INVERT_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsCombatInButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_COMBAT_IN_TOOLTIP_TITLE, AUTOBUFF_GUI_COMBAT_IN_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsCombatOutButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_COMBAT_OUT_TOOLTIP_TITLE, AUTOBUFF_GUI_COMBAT_OUT_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsCombatAlwaysButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_COMBAT_ALWAYS_TOOLTIP_TITLE, AUTOBUFF_GUI_COMBAT_ALWAYS_TOOLTIP);
		
	elseif (frame == "AutoBuffFrameOptionsPartyInButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_PARTY_IN_TOOLTIP_TITLE, AUTOBUFF_GUI_PARTY_IN_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsPartyOutButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_PARTY_OUT_TOOLTIP_TITLE, AUTOBUFF_GUI_PARTY_OUT_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsPartyAlwaysButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_PARTY_ALWAYS_TOOLTIP_TITLE, AUTOBUFF_GUI_PARTY_ALWAYS_TOOLTIP);
		
	elseif (frame == "AutoBuffFrameOptionsCombatDefaultButton") or (frame == "AutoBuffFrameOptionsHealthDefaultButton") or (frame == "AutoBuffFrameOptionsTriggerDefaultButton") or
		   (frame == "AutoBuffFrameOptionsManaDefaultButton") or (frame == "AutoBuffFrameOptionsRebuffDefaultButton") or (frame == "AutoBuffFrameOptionsPartyDefaultButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_DEFAULT_TOOLTIP_TITLE, AUTOBUFF_GUI_DEFAULT_TOOLTIP);
	elseif (frame == "AutoBuffFrameOptionsTriggerWheelUpButton") or (frame == "AutoBuffFrameOptionsTriggerWheelDownButton") or (frame == "AutoBuffFrameOptionsTriggerTargetButton") then
		AutoBuffFrame_Tooltip(AUTOBUFF_GUI_TRIGGER_TITLE, AUTOBUFF_GUI_TRIGGER_TOOLTIP);
	end
end

function AutoBuffFrame_OnMouseDown(arg1) if arg1=="LeftButton" then	AutoBuffFrame:StartMoving(); end end
function AutoBuffFrame_OnMouseUp(arg1) if arg1=="LeftButton" then AutoBuffFrame:StopMovingOrSizing(); end end


-- Had to make this function weird, as it was giving me an awful 'next' key is invalid error.
function AutoBuff_CorrectName(s)
	s = string.lower(s);
	local a,b,c,d;
	for a, b in cSpellList do
		c = string.lower(a);
		if (c == s) then d = a; break; end
	end
	if (not d) then
		for a, b in cWeaponList do
			c = string.lower(a);
			if (c == s) then d = a; break; end
		end
	end
	if (not d) then
		for a, b in cTrackList do
			c = string.lower(a);
			if (c == s) then d = a; break; end
		end
	end
	if (not d) then
		for a, b in cAspectList do
			c = string.lower(a);
			if (c == s) then d = a; break; end
		end
	end
	if (not d) then
		for a, b in cSealList do
			c = string.lower(a);
			if (c == s) then d = a; break; end
		end
	end
	return d;
end

function AutoBuff_SpellList(n)
	local a,b,r;
	for a,b in cSpellList do
		if (b['i'] == n) then r = a; break; end
	end
	return r;
end

-- ==================================================

function TitanPanelAutoBuffButton_OnLoad()
	this.registry = { 
		id = TITAN_AUTOBUFF_ID,
		menuText = TITAN_AUTOBUFF_MENU_TEXT,
		buttonTextFunction = nil,
		tooltipTitle = TITAN_AUTOBUFF_TOOLTIP,
		tooltipTextFunction = "TitanPanelAutoBuffButton_GetTooltipText",
		icon = TITAN_AUTOBUFF_ICON_ON,
		iconWidth = 16,
    frequency = 5,
	};
end

function TitanPanelAutoBuffButton_OnClick()
	if (arg1=="LeftButton") then
		AutoBuffOptionsButton_OnClick(arg1);
	end
end

function TitanPanelAutoBuffButton_GetTooltipText()

	--if (IsAddOnLoaded("Titan")) then TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Testing", u.ColorList[string.lower("red")]).."\t"..TitanUtils_GetColoredText("Testing", u.ColorList[string.lower("yellow")]).."\n"; end
	
	TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TitanUtils_GetColoredText(TITAN_AUTOBUFF_ENABLE, u.ColorList[string.lower("yellow")]).."\t";
	
	if (TitanAutoBuffStates.Enabled) then
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\n";
	else
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\n";
	end
	
	TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText(TITAN_AUTOBUFF_DEBUG, u.ColorList[string.lower("yellow")]).."\t";
	
	if (TitanAutoBuffStates.Debug) then
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\n";
	else
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\n";
	end

if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_SHAMAN)) then
	TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText(TITAN_AUTOBUFF_WATER, u.ColorList[string.lower("yellow")]).."\t";
	
	if (TitanAutoBuffStates.Water) then
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\n";
	else
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\n";
	end
end

if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
	TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText(TITAN_AUTOBUFF_TAP, u.ColorList[string.lower("yellow")]).."\t";
	
	if (TitanAutoBuffStates.Tap) then
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\n";
	else
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\n";
	end
end

if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) then
	TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText(TITAN_AUTOBUFF_SCALED, u.ColorList[string.lower("yellow")]).."\t";
	
	if (TitanAutoBuffStates.Scaled) then
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\n";
	else
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\n";
	end
end

if (vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
	TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText(TITAN_AUTOBUFF_INNER, u.ColorList[string.lower("yellow")]).."\t";
	
	if (TitanAutoBuffStates.Inner) then
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Enabled", u.ColorList[string.lower("green")]).."\n";
	else
		TITAN_AUTOBUFF_TOOLTIP_CONTENTS = TITAN_AUTOBUFF_TOOLTIP_CONTENTS..TitanUtils_GetColoredText("Disabled", u.ColorList[string.lower("red")]).."\n";
	end
end

	return TITAN_AUTOBUFF_TOOLTIP_CONTENTS;
	
end

function TitanPanelRightClickMenu_PrepareAutoBuffMenu()

	local info;
	TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_AUTOBUFF_ID].menuText);	
	
	info = {};
	info.text = TITAN_AUTOBUFF_ENABLE;
	info.func = AutoBuffToggle;
	info.checked = TitanAutoBuffStates.Enabled;
	UIDropDownMenu_AddButton(info); 
	
	TitanPanelRightClickMenu_AddSpacer();	
	
if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_SHAMAN)) then
	info = {};
	info.text = TITAN_AUTOBUFF_WATER;
	info.func = AutoBuffWaterToggle;
	info.checked = TitanAutoBuffStates.Water;
	UIDropDownMenu_AddButton(info); 
end
	
if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
	info = {};
	info.text = TITAN_AUTOBUFF_TAP;
	info.func = AutoBuffTapToggle;
	info.checked = TitanAutoBuffStates.Tap;
	UIDropDownMenu_AddButton(info); 
end
	
if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) then
	info = {};
	info.text = TITAN_AUTOBUFF_SCALED;
	info.func = AutoBuffScaledToggle;
	info.checked = TitanAutoBuffStates.Scaled;
	UIDropDownMenu_AddButton(info); 
end
	
if (vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
	info = {};
	info.text = TITAN_AUTOBUFF_INNER;
	info.func = AutoBuffInnerToggle;
	info.checked = TitanAutoBuffStates.Inner;
	UIDropDownMenu_AddButton(info); 
end

	TitanPanelRightClickMenu_AddSpacer();	
	
	info = {};
	info.text = TITAN_AUTOBUFF_BUTTONSHOW;
	info.func = AutoBuff_HideButton;
	info.checked = TitanAutoBuffStates.Button;
	UIDropDownMenu_AddButton(info);
	
	info = {};
	info.text = TITAN_AUTOBUFF_BUTTONRESET;
	info.func = AutoBuff_ResetButton;
	info.checked = nil;
	UIDropDownMenu_AddButton(info);	
	
	TitanPanelRightClickMenu_AddSpacer();	
	
	info = {};
	info.text = TITAN_AUTOBUFF_DEBUG;
	info.func = AutoBuffDebug;
	info.checked = TitanAutoBuffStates.Debug;
	UIDropDownMenu_AddButton(info);
	
	TitanPanelRightClickMenu_AddSpacer();
	TitanPanelRightClickMenu_AddCommand(TITAN_PANEL_MENU_HIDE, TITAN_AUTOBUFF_ID, TITAN_PANEL_MENU_FUNC_HIDE);
	
end

-- Fubar Functions
function FuBarAutoBuff_OnLoad()

	AutoBuffFu = AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceDB-2.0", "FuBarPlugin-2.0");
	local L = AceLibrary("AceLocale-2.0"):new("AutoBuffFu");
	local Dewdrop = AceLibrary("Dewdrop-2.0");
	local Tablet = AceLibrary("Tablet-2.0");

L:RegisterTranslations("enUS", function() return {
	["enable"] = TITAN_AUTOBUFF_ENABLE,
	["buttonshow"] = TITAN_AUTOBUFF_BUTTONSHOW,
	["buttonreset"] = TITAN_AUTOBUFF_BUTTONRESET,
	["debug"] = TITAN_AUTOBUFF_DEBUG,
	["water"] = TITAN_AUTOBUFF_WATER,
	["tap"] = TITAN_AUTOBUFF_TAP,
	["scaled"] = TITAN_AUTOBUFF_SCALED,
	["inner"] = TITAN_AUTOBUFF_INNER,
	["tablethint"] = "Left-Click for AutoBuff UI",
} end);

	AutoBuffFu:RegisterDB("AutoBuffFuDB");
	AutoBuffFu.hasNoText  = true;
	AutoBuffFu.hasIcon = true;
	AutoBuffFu.defaultPosition = "RIGHT";
	--AutoBuffFu.title = TITAN_AUTOBUFF_ID;
	AutoBuffFu.title = TITAN_AUTOBUFF_TOOLTIP; -- With Version number
	AutoBuffFu:SetIcon(TITAN_AUTOBUFF_ICON_ON..".tga");

	local optionsTable = {
		handler = AutoBuffFu,
		type = "Buffs",
		args = {};
	};

	AutoBuffFu.OnMenuRequest = optionsTable;

function AutoBuffFu:OnTooltipUpdate()

	-- Have been unable to get the tooltip to work, keeps erroring out with:
	-- Count: 5
	-- Error: ...rface\AddOns\AutoBuff\libs\Tablet-2.0\Tablet-2.0.lua:2265: attempt to index a nil value

	local cat = Tablet:AddCategory(
		'columns', 2
	);
	if (TitanAutoBuffStates.Enabled) then
	cat:AddLine(
		'text', L"enable",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Enabled",
		'text2R', 0,
		'text2G', 1,
		'text2B', 0
	);
	else
	cat:AddLine(
		'text', L"enable",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Disabled",
		'text2R', 1,
		'text2G', 0,
		'text2B', 0
	);
	end
	
	if (TitanAutoBuffStates.Debug) then
	cat:AddLine(
		'text', L"debug",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Enabled",
		'text2R', 0,
		'text2G', 1,
		'text2B', 0
	);
	else
	cat:AddLine(
		'text', L"debug",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Disabled",
		'text2R', 1,
		'text2G', 0,
		'text2B', 0
	);
	end

if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_SHAMAN)) then
	if (TitanAutoBuffStates.Water) then
	cat:AddLine(
		'text', L"water",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Enabled",
		'text2R', 0,
		'text2G', 1,
		'text2B', 0
	);
	else
	cat:AddLine(
		'text', L"water",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Disabled",
		'text2R', 1,
		'text2G', 0,
		'text2B', 0
	);
	end
end

if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
	if (TitanAutoBuffStates.Tap) then
	cat:AddLine(
		'text', L"tap",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Enabled",
		'text2R', 0,
		'text2G', 1,
		'text2B', 0
	);
	else
	cat:AddLine(
		'text', L"tap",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Disabled",
		'text2R', 1,
		'text2G', 0,
		'text2B', 0
	);
	end
end

if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) then
	if (TitanAutoBuffStates.Scaled) then
	cat:AddLine(
		'text', L"scaled",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Enabled",
		'text2R', 0,
		'text2G', 1,
		'text2B', 0
	);
	else
	cat:AddLine(
		'text', L"scaled",
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Disabled",
		'text2R', 1,
		'text2G', 0,
		'text2B', 0
	);
	end
end

if (vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
	if (TitanAutoBuffStates.Inner) then
	cat:AddLine(
		'text', TITAN_AUTOBUFF_INNER,
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Enabled",
		'text2R', 0,
		'text2G', 1,
		'text2B', 0
	);
	else
	cat:AddLine(
		'text', TITAN_AUTOBUFF_INNER,
		'textR', 1,
		'textG', 1,
		'textB', 0,
		'text2', "Disabled",
		'text2R', 1,
		'text2G', 0,
		'text2B', 0
	);
	end
end

	cat:AddLine("text", "");

	Tablet:SetHint(L"tablethint");
end

function AutoBuffFu:OnMenuRequest(value)
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_ENABLE,
			"arg1", self,
			"func", AutoBuffToggle,
			"checked", TitanAutoBuffStates.Enabled
		);
		Dewdrop:AddLine(
			"text", ""
		);
if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_SHAMAN)) then
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_WATER,
			"arg1", self,
			"func", AutoBuffWaterToggle,
			"checked", TitanAutoBuffStates.Water
		);
end
if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK) or vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_TAP,
			"arg1", self,
			"func", AutoBuffTapToggle,
			"checked", TitanAutoBuffStates.Tap
		);
end
if (vClass == string.lower(AUTOBUFF_CLASS_WARLOCK)) then
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_SCALED,
			"arg1", self,
			"func", AutoBuffScaledToggle,
			"checked", TitanAutoBuffStates.Scaled
		);
end
if (vClass == string.lower(AUTOBUFF_CLASS_PRIEST)) then
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_INNER,
			"arg1", self,
			"func", AutoBuffInnerToggle,
			"checked", TitanAutoBuffStates.Inner
		);
end
		Dewdrop:AddLine(
			"text", ""
		);
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_BUTTONSHOW,
			"arg1", self,
			"func", AutoBuff_HideButton,
			"checked", TitanAutoBuffStates.Button
		);
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_BUTTONRESET,
			"arg1", self,
			"func", AutoBuff_ResetButton,
			"checked", nil
		);
		Dewdrop:AddLine(
			"text", ""
		);
		Dewdrop:AddLine(
			"text", TITAN_AUTOBUFF_DEBUG,
			"arg1", self,
			"func", AutoBuffDebug,
			"checked", TitanAutoBuffStates.Debug
		);

	Dewdrop:AddLine("text", "");
end

function AutoBuffFu:OnClick() -- Only reacts on "LeftButton"
	AutoBuffOptionsButton_OnClick("LeftButton");
end

end -- End prevention code wrap

-- Class declarations
-- Utility class provides print (to the chat box) and echo (displays over your character's head).
-- Instantiate it and use the colon syntax.
-- Color is an optional argument.  You can either use one of 7 named colors
-- "red", "green", "blue", "yellow", "cyan", "magenta", "white" or
-- a table with the r, g, b values.
-- IE foo:Print("some text", {r = 1.0, g=1.0, b=.5})

-- if there is an existing Utility Class version of equal or greater version, don't declare.
if not Utility_Class or (not Utility_Class.version) or (Utility_Class.version < 1.01) then
	Utility_Class = {};
	Utility_Class.version = 1.01
	function Utility_Class:New ()
		local o = {}   -- create object
		setmetatable(o, self)
		self.__index = self
		return o
	end
	
	function Utility_Class:Print(msg, color)
	local text;
	local r, g, b;
		if msg == nil then return; end
		if color == nil then color = "white"; end
		r, g, b = self.GetColor(color);
		
		if( DEFAULT_CHAT_FRAME ) then
			DEFAULT_CHAT_FRAME:AddMessage(msg,r,g,b);
		end
		
	end
	
	function Utility_Class:Echo(msg, color)
	local text;
	local r, g, b;
		if msg == nil then return; end
		if color == nil then color = "white"; end
		r, g, b = self.GetColor(color);
		
		UIErrorsFrame:AddMessage(msg, r, g, b, 1.0, UIERRORS_HOLD_TIME);
		
	end
	
	function Utility_Class:GetColor(color)
		if color == nil then color = self; end
		if color == nil then return 0, 0, 0 end
	
		if type(color) == "string" then 
			color = Utility_Class.ColorList[string.lower(color)];
		end
		
		if type(color) == "table" then
			if color.r == nil then color.r = 0.0 end
			if color.g == nil then color.g = 0.0 end
			if color.b == nil then color.g = 0.0 end
		else
			return 0, 0, 0 
		end
	
		if color.r < 0 then color.r = 0.0 end
		if color.g < 0 then color.g = 0.0 end
		if color.b < 0 then color.g = 0.0 end
	
		if color.r > 1 then color.r = 1.0 end
		if color.g > 1 then color.g = 1.0 end
		if color.b > 1 then color.g = 1.0 end
		
		return color.r, color.g, color.b
		
	end
	
	Utility_Class.ColorList = {}
	Utility_Class.ColorList["red"] = { r = 1.0, g = 0.0, b = 0.0 }
	Utility_Class.ColorList["green"] = { r = 0.0, g = 1.0, b = 0.0 }
	Utility_Class.ColorList["blue"] = { r = 0.0, g = 0.0, b = 1.0 }
	Utility_Class.ColorList["white"] = { r = 1.0, g = 1.0, b = 1.0 }
	Utility_Class.ColorList["magenta"] = { r = 1.0, g = 0.0, b = 1.0 }
	Utility_Class.ColorList["yellow"] = { r = 1.0, g = 1.0, b = 0.0 }
	Utility_Class.ColorList["cyan"] = { r = 0.0, g = 1.0, b = 1.0 }
	Utility_Class.ColorList["orange"] = { r = 1.0, g = 0.6, b = 0.0 }
end
