-- PowaAura Classes
-- class.lua
-- Compatible with Lua 5.1 (not 5.0).
function PowaClass(base,ctor)
	local c = {}     -- a new class instance
	if not ctor and type(base) == 'function' then
      ctor = base;
      base = nil;
	elseif type(base) == 'table' then
   -- our new class is a shallow copy of the base class!
      for i,v in pairs(base) do
          c[i] = v;
      end
	  if (type(ctor)=="table") then
		for i,v in pairs(ctor) do
			c[i] = v;
		end
		ctor = nil;
	  end
      c._base = base;
	end
	-- the class will be the metatable for all its objects,
	-- and they will look up their methods in it.
	c.__index = c

	-- expose a ctor which can be called by <classname>(<args>)
	local mt = {}
	mt.__call = function(class_tbl,...)
		local obj = {}
		setmetatable(obj,c)
		if ctor then
			--PowaAuras:ShowText("Call constructor "..tostring(ctor));
			ctor(obj,...)
		end 
		return obj
	end
    
    if ctor then
		c.init = ctor;
    else 
 		if base and base.init then
			c.init = base.init;
			ctor = base.init;
		end
    end
 
	c.is_a = function(self,klass)
      local m = getmetatable(self)
      while m do 
         if m == klass then return true end
         m = m._base
      end
      return false
    end
  setmetatable(c,mt)
  return c
end

cPowaStacks = PowaClass(function(stacker, aura, base)
	stacker.enabled = false;
	stacker.x = 0;
	stacker.y = 0;
	stacker.a = 1.0;
	stacker.h = 1.0;
	stacker.Transparent = false;
	stacker.HideLeadingZeros = false;
	stacker.Texture = "Default";
	--PowaAuras:ShowText("cPowaTimer");
	if (base) then
		for k, v in pairs (stacker) do
			--PowaAuras:ShowText("  base."..tostring(k).."="..tostring(base[k]));
			local varType = type(v);
			if (varType == "string" or varType == "boolean" or varType == "number") then
				if (base[k] ~= nil) then
					stacker[k] = base[k];
				end
			end
		end
	end
	stacker.Showing = false;
	stacker.id = aura.id;
end);

function cPowaStacks:GetTexture()
	local texture = PowaMisc.DefaultStacksTexture;
	if (self.Texture ~= "Default") then
		texture = self.Texture;
	end
	local postfix = "";
	if (self.Transparent) then
		postfix = "Transparent";
	end
	return "Interface\\Addons\\PowerAuras\\TimerTextures\\"..texture.."\\Timers"..postfix..".tga";
end

function cPowaStacks:Update()
	PowaAuras:UnitTestInfo("Stacks.Update ",self.id);
	local aura = PowaAuras.Auras[self.id];
	if (aura == nil) then
		PowaAuras:UnitTestInfo("Stacks aura missing");
		return;
	end
	if (self.enabled==false) then 
		PowaAuras:UnitTestInfo("Stacks disabled");
		return;
	end
	local newvalue = 0;
	if (PowaAuras.ModTest) then
		newvalue = random(1,12);
	else
		newvalue = aura.StackCount;
	end
	if (not newvalue or newvalue==0) then
		local frame = PowaAuras.StacksFrames[self.id];
		if (frame and frame:IsVisible()) then
			frame:Hide();
		end
		self.Showing = false;
		return;
	end
	PowaAuras:CreateStacksFrameIfMissing(self.id);
	self:ShowValue(aura, newvalue);
	self.Showing = true;
end


function cPowaStacks:ShowValue(aura, newvalue)
	local frame = PowaAuras.StacksFrames[self.id];
	if (aura.texmode == 1) then
		frame.texture:SetBlendMode("ADD");
	else
		frame.texture:SetBlendMode("DISABLE");
	end
	local auraTexture = PowaAuras.Textures[self.id];
	if (auraTexture) then
		if auraTexture:GetObjectType() == "Texture" then
			frame.texture:SetVertexColor(auraTexture:GetVertexColor());
		elseif auraTexture:GetObjectType() == "FontString" then
			frame.texture:SetVertexColor(auraTexture:GetTextColor());
		end
	else
		timerFrame.texture:SetVertexColor(aura.r,aura.g,aura.b);
	end

	--PowaAuras:ShowText("newvalue=", newvalue);
	
	local deci = math.floor(newvalue / 10);
	local uni  = math.floor(newvalue - (deci*10));
	--PowaAuras:ShowText("Show stacks: ",deci, " ", uni);
	local tStep = PowaAuras.Tstep;
	if (deci==0) then
		frame.texture:SetTexCoord(tStep , tStep * 1.5, tStep * uni, tStep * (uni+1));
	else
		frame.texture:SetTexCoord(tStep * uni, tStep * (uni+1), tStep * deci, tStep * (deci+1));
	end
	if (not frame:IsVisible()) then
		--PowaAuras:Message("Show Stacks Frame for ", self.id);
		frame:Show(); 
	end
end

function cPowaStacks:Hide()
	--PowaAuras:Message("Hide Stacks Frame for ", self.id, " ", self.Showing, " ", PowaAuras.StacksFrames[self.id]);
	if (not self.Showing) then return; end
	if (PowaAuras.StacksFrames[self.id]) then
		PowaAuras.StacksFrames[self.id]:Hide();
	end
	self.Showing = false;
end

function cPowaStacks:Delete()
	self:Hide();
	if PowaAuras.StacksFrames[self.id] then
		PowaAuras.StacksFrames[self.id] = nil;
	end
end

------- Timer -------

cPowaTimer = PowaClass(function(timer, aura, base)
	timer.enabled = false;
	timer.x = 0;
	timer.y = 0;
	timer.a = 1.0;
	timer.h = 1.0;
	timer.cents = true;
	timer.dual = false;
	timer.Transparent = false;
	timer.HideLeadingZeros = false;
	timer.Texture = "Default";
	--PowaAuras:Message("cPowaTimer");
	if (base) then
		for k, v in pairs (timer) do
			--PowaAuras:Message("  base."..tostring(k).."="..tostring(base[k]));
			local varType = type(v);
			if (varType == "string" or varType == "boolean" or varType == "number") then
				if (base[k] ~= nil) then
					timer[k] = base[k];
				end
			end
		end
	end
	timer.Showing = false;
	--PowaAuras:Message("CTR Timer id=", aura.id);
	--PowaAuras:Message("CooldownAura=", aura.CooldownAura);
	--PowaAuras:Message("inverse=", aura.inverse);
	--PowaAuras:Message("CanHaveTimer=", aura.CanHaveTimer);
	--PowaAuras:Message("CanHaveTimerOnInverse=", aura.CanHaveTimerOnInverse);
	timer.ShowOnAuraHide = ((aura.CooldownAura and (not aura.inverse and aura.CanHaveTimer)) or (not aura.CooldownAura and (aura.inverse and aura.CanHaveTimerOnInverse)));
	--PowaAuras:Message("ShowOnAuraHide=", timer.ShowOnAuraHide);
 
	timer.id = aura.id;
	--for k,v in pairs (timer) do
	--	PowaAuras:Message("  "..tostring(k).."="..tostring(v));
	--end
end);

function cPowaTimer:GetTexture()
	local texture = PowaMisc.DefaultTimerTexture;
	if (self.Texture ~= "Default") then
		texture = self.Texture;
	end
	local postfix = "";
	if (self.Transparent) then
		postfix = "Transparent";
	end
	return "Interface\\Addons\\PowerAuras\\TimerTextures\\"..texture.."\\Timers"..postfix..".tga";
end
--- ------------------------------------------------------------------------------------------------- TIMERS
function cPowaTimer:Update(elapsed)
	PowaAuras:UnitTestInfo("Timer.Update ",self.id);
	--PowaAuras:Message("Timer.Update ",self.id);
	local aura = PowaAuras.Auras[self.id];
	if (aura == nil) then
		PowaAuras:UnitTestInfo("Timer aura missing");
		--PowaAuras:Message("Timer aura missing");
		return;
	end
	if (self.enabled==false) then
		PowaAuras:UnitTestInfo("Timer disabled");
		--PowaAuras:Message("Timer disabled");
		return;
	end

	local newvalue;
	--- Determine the value to display in the timer
	if (PowaAuras.ModTest) then
		newvalue = random(0,99) + (random(0, 99) / 100);
	
	elseif (aura.timerduration > 0) then--- if a user defined timer is active for the aura override the rest
		if (aura.target or aura.targetfriend) and (PowaAuras.ResetTargetTimers == true) then
			self.CustomDuration = aura.timerduration;
		else
			self.CustomDuration = math.max(self.CustomDuration - elapsed, 0);
		end	
		newvalue = self.CustomDuration;
	else
		newvalue = aura:GetDuration(self.DurationInfo);
	end

	if (PowaAuras.DebugCycle) then
		PowaAuras:Message("newvalue=",newvalue); --OK
	end

	PowaAuras:UnitTestInfo("Timer newvalue", newvalue);
	--PowaAuras:ShowText("Timer newvalue=", newvalue);

	if (newvalue and newvalue > 0) then --- Time has value to display

		PowaAuras:CreateTimerFrameIfMissing(self.id);
	
		local large = newvalue;
		if (newvalue > 60.00) then 
			large = newvalue / 60;		
		end
		large = math.min (99.00, large);

		if (PowaAuras.DebugCycle) then
			PowaAuras:Message("large=",large); --OK
		end
		self:ShowValue(aura, 1, large);

		if (PowaAuras.DebugCycle) then
			PowaAuras:Message("cents=",self.cents); --OK
		end
		if (self.cents) then
			local small;
			if (newvalue > 60.00) then 
				small = math.fmod(newvalue,60); 
			else
				small = (newvalue - math.floor(newvalue)) * 100;
			end

			if (PowaAuras.DebugCycle) then
				PowaAuras:Message("small=",small); --OK
			end
			self:ShowValue(aura, 2, small);
		end	
		self.Showing = true;		

	elseif (self.Showing) then
		if (PowaAuras.DebugCycle) then
			PowaAuras:Message("HideTimerFrames"); --OK
		end
		self:Hide();
		PowaAuras:TestThisEffect(self.id);
	end			
	
end

function cPowaTimer:ShowValue(aura, frameIndex, newvalue)
	local timerFrame = PowaAuras.TimerFrame[self.id][frameIndex];
	if (aura.texmode == 1) then
		timerFrame.texture:SetBlendMode("ADD");
	else
		timerFrame.texture:SetBlendMode("DISABLE");
	end
	local auraTexture = PowaAuras.Textures[self.id];
	if (auraTexture) then
		if auraTexture:GetObjectType() == "Texture" then
			timerFrame.texture:SetVertexColor(auraTexture:GetVertexColor());
		elseif auraTexture:GetObjectType() == "FontString" then
			timerFrame.texture:SetVertexColor(auraTexture:GetTextColor());
		end
	else
		timerFrame.texture:SetVertexColor(aura.r,aura.g,aura.b);
	end
	
	--PowaAuras:ShowText("newvalue=", newvalue);
	
	local deci = math.floor(newvalue / 10);
	local uni  = math.floor(newvalue - (deci*10));
	--PowaAuras:ShowText("Show timer: ",deci, " ", uni, " ", PowaAuras.Auras[k].Timer.HideLeadingZeros);
	local tStep = PowaAuras.Tstep;
	if (deci==0 and self.HideLeadingZeros) then
		timerFrame.texture:SetTexCoord(tStep , tStep * 1.5, tStep * uni, tStep * (uni+1));
	else
		timerFrame.texture:SetTexCoord(tStep * uni, tStep * (uni+1), tStep * deci, tStep * (deci+1));
	end
	if (not timerFrame:IsVisible()) then
		--PowaAuras:ShowText("Show timer frame id=",self.id, " index=", frameIndex);
		timerFrame:Show(); -- Timer Frame
	end
	--PowaAuras:ShowText("Show #3 ", k, " ", i, " ", j, " ", seconds);
	
	--PowaAuras:ShowText("deci=", deci, " uni=", uni);
end


function cPowaTimer:HideFrame(i)
	if (PowaAuras.TimerFrame[self.id] and PowaAuras.TimerFrame[self.id][i]) then
		--PowaAuras:ShowText("Hide Timer Frame ", i," for ", self.id);
		PowaAuras.TimerFrame[self.id][i]:Hide();
	end
end

function cPowaTimer:Hide()
	if (not self.Showing) then return; end
	if PowaAuras.TimerFrame[self.id] then
		self:HideFrame(1);
		self:HideFrame(2);
	end
	self.Showing = false;
	--PowaAuras:Message("Hide timer frame");
end

function cPowaTimer:Delete()
	self:Hide();
	if PowaAuras.TimerFrame[self.id] then
		PowaAuras.TimerFrame[self.id][1] = nil;
		PowaAuras.TimerFrame[self.id][2] = nil;
		PowaAuras.TimerFrame[self.id] = nil;
	end
end

------------cPowaAura----------------
--   cPowaAura is the base class and is not instanced directly, the other classes inherit properties and methods from it
--===========================

cPowaAura = PowaClass(function(aura, id, base)
	--PowaAuras:Message("cPowaAura constructor " .. tostring(id));
	aura.off = false;
	
	aura.bufftype = PowaAuras.BuffTypes.Buff;
	aura.buffname = "";
	
	aura.texmode = 1;
	aura.wowtex = false;
	aura.customtex = false;
	aura.textaura = false;
	aura.owntex = false;
	aura.realaura = 1;
	aura.texture = 1;
	aura.customname = "";
	aura.aurastext = "";
	aura.aurastextfont = 1;
	aura.icon = "";

	aura.timerduration = 0;
	
	-- Sound Settings
	aura.sound = 0;
	aura.soundfile = "";
	aura.customsound = "";	
	
	-- Animation Settings
	aura.begin = 0;
	aura.anim1 = 1;
	aura.anim2 = 0;
	aura.speed = 1.00;
	aura.finish = 1;
	aura.duration = 0;
	aura.isSecondary = false;
	
	-- Appearance Settings
	aura.alpha = 0.75;
	aura.size = 0.75;
	aura.torsion = 1;
	aura.symetrie = 0;
	aura.x = 0;
	aura.y = -30;
	aura.randomcolor = false;
	aura.r = 1.0;
	aura.g = 1.0;
	aura.b = 1.0;
	
	aura.inverse = false;
	aura.ignoremaj = true;
	aura.exact = false;

	aura.stacks = 0;
	aura.stacksLower = 0;
	aura.stacksOperator = PowaAuras.DefaultOperator;

	aura.threshold = 50;
	aura.thresholdinvert = false;

	aura.mine = false;

	aura.focus = false;
	aura.target = false;
	aura.targetfriend = false;
	aura.raid = false;
	aura.groupOrSelf = false;
	aura.party = false;

	aura.groupany = true;
	aura.optunitn = false;
	aura.unitn = "";

	aura.isinraid = false;
	aura.ismounted = false;
	aura.ignoreResting = true;
	aura.inVehicle = false;
	
	aura.combat = 0;
	aura.spec1 = true;
	aura.spec2 = true;
	aura.gcd = false;
	aura.stance = 10;
	aura.multiids = "";
	aura.tooltipCheck = "";

	if (base) then
		for k, v in pairs (aura) do
			local varType = type(v);
			if (varType == "string" or varType == "boolean" or varType == "number" or k=="ShowOptions" or k=="CheckBoxes" or k=="OptionText") then
				if (base[k] ~= nil) then
					aura[k] = base[k];
				end
			end
		end
	end

	aura.Showing = false;
	aura.Active = false;
	aura.HideRequest = false;
	aura.id = id;
	
	if (base) then
		if (base.Timer and not aura.isSecondary) then
		--if ((base.CanHaveTimerOnInverse or base.CanHaveTimer) and base.Timer) then
			aura.Timer = cPowaTimer(aura, base.Timer);
		end				
		
		if (base.Stacks and not base.isSecondary) then
			aura.Stacks = cPowaStacks(aura, base.Stacks);
		end				
	end
	
	if (not aura.Timer and not aura.isSecondary) then
	--if ((base.CanHaveTimerOnInverse or base.CanHaveTimer) and not aura.Timer) then
		aura.Timer = cPowaTimer(aura);
	end
	
	if (aura.CanHaveStacks and not aura.Stacks and not aura.isSecondary) then
		aura.Stacks = cPowaStacks(aura);
	end
	
end);


function cPowaAura:TimerShowing()
	if (not self.Timer) then return false; end
	return self.Timer.Showing;
end

function cPowaAura:StacksShowing()
	if (not self.Stacks) then return false; end
	return self.Stacks.Showing;
end

function cPowaAura:HideShowTabs()
	if ((self.CanHaveTimer and not self.inverse) or (self.CanHaveTimerOnInverse and self.inverse)) then 
		PowaEditorTab3:Show();
		if (not self.Timer) then
			self.Timer = cPowaTimer(self);
		end
	else
		PowaEditorTab3:Hide();
		if (self.Timer) then
			self.Timer.enabled = false;
		end
	end
	if (self.CanHaveStacks and not self.inverse) then 
		PowaEditorTab5:Show();
		if (not self.Stacks) then
			self.Stacks = cPowaStacks(self);
		end
	else
		PowaEditorTab5:Hide();
		if (self.Stacks) then
			self.Stacks.enabled = false;
		end
	end
end
function cPowaAura:GetDuration(durationInfo)
	--PowaAuras:Message("GetDuration=", durationInfo);
	if (durationInfo and durationInfo > 0) then
		return math.max(durationInfo - GetTime(), 0);
	end
	return 0;
end

function cPowaAura:CreateFrames()
	local frame = self:GetFrame();
	if (frame==nil) then
		PowaAuras:UnitTestInfo("New Frames", self.id);
		--PowaAuras:UnitTestDebug("Creating frame for aura ", self.id);
		--- Frame --- 
		frame = CreateFrame("Frame","Frame"..self.id, UIParent);
		self:SetFrame(frame);
		
		frame:SetFrameStrata("LOW");
		frame:Hide();  
		
		frame.baseL = 256;
		frame.baseH = 256;
	end
	
	local texture = self:GetTexture();
	if (texture==nil) then
		PowaAuras:UnitTestInfo("New Texture", self.id);
		if self.textaura then
			--PowaAuras:UnitTestDebug("Creating new textstring texture for aura ", self.id);
			texture = frame:CreateFontString(nil, "OVERLAY");
			texture:ClearAllPoints();
			texture:SetPoint("CENTER",frame);
			texture:SetFont(STANDARD_TEXT_FONT, 20);
			texture:SetTextColor(self.r,self.g,self.b);
			texture:SetJustifyH("CENTER");
		else
			texture = frame:CreateTexture(nil,"BACKGROUND");
			texture:SetBlendMode("ADD");
			texture:SetAllPoints(frame); --- attache la texture a la frame
			frame.texture = texture;
		end
		self:SetTexture(texture);
	else
		if self.textaura then
			--PowaAuras:UnitTestDebug("textaura ", texture:GetObjectType());
			if texture:GetObjectType() == "Texture" then
				PowaAuras:UnitTestInfo("Converting to textstring texture for aura ", self.id);
				--PowaAuras:UnitTestDebug("Converting to textstring texture for aura ", self.id);
				texture:SetTexture(nil);
				texture = frame:CreateFontString(nil, "OVERLAY");
				texture:ClearAllPoints();
				texture:SetPoint("CENTER",frame);
				texture:SetFont(STANDARD_TEXT_FONT, 20);
				texture:SetTextColor(self.r,self.g,self.b);
				texture:SetJustifyH("CENTER");
				self:SetTexture(texture);
			end
		else
			if texture:GetObjectType() == "FontString" then
				PowaAuras:UnitTestInfo("Converting from textstring texture for aura ", self.id);
				texture:SetText("");
				texture = frame:CreateTexture(nil,"BACKGROUND");
				texture:SetBlendMode("ADD");	
				texture:SetAllPoints(frame); --- attache la texture a la frame
				frame.texture = texture;
				self:SetTexture(texture);
			end
		end
	end	
	return frame, texture;
end


function cPowaAura:Hide()
	
	PowaAuras:UnitTestInfo("Aura.Hide ", self.id);

	local frame = self:GetFrame();
	if (frame) then
		frame:Hide();
	end
	
	if (not self.isSecondary) then
		if (self.Timer and (PowaAuras.ModTest or self.off)) then self.Timer:Hide(); end
		if (self.Stacks) then self.Stacks:Hide(); end
		local frame = PowaAuras.Frames[self.id];
		if (frame) then
			frame:Hide();
		end
		local secondaryAura = PowaAuras.SecondaryAuras[self.id];
		if (secondaryAura) then
			secondaryAura:Hide();
		end
	end

	self.Showing = false;
end

function cPowaAura:AddEffect(i)
	table.insert(PowaAuras.AurasByType[self.AuraType], i);
end

function cPowaAura:IsPlayerAura()
	return 	(not self.target) 
		and (not self.targetfriend)
		and (not self.party)
		and (not self.raid) 
		and (not (self.groupOrSelf and (GetNumPartyMembers()>0 or GetNumRaidMembers()>0))) 
		and (not self.focus)
		and (not self.optunitn);
end

function cPowaAura:ShowTimerDurationSlider()
	return false;
end

function cPowaAura:CheckState(giveReason)
	
	--- player aura but player is dead
	if (self:IsPlayerAura() and not PowaAuras.WeAreAlive) then
		if (not giveReason) then return false; end
		return false, "Player is DEAD";
	end
	
	--- n'affiche pas si la cible est inexistante ou morte
	if ((self.target or self.targetfriend) and (UnitName("target") == nil or UnitIsDead("target") or UnitName("target") == UnitName("player")) ) then
		if (not giveReason) then return false; end
		if (UnitName("target") == nil) then
			return false, "no Target";
		end
		if (UnitName("target") == UnitName("player")) then
			return false, "Target is you";
		end		
		return false, "Target DEAD";
	end
	    		
	--- regarde si la cible est ennemie
	if (self.target and self.targetfriend == false and UnitIsFriend("player","target")) then --- cible amie alors que faut pas
		if (not giveReason) then return false; end
		return false, "Target is fiendly";
	end
		
	--- party
	if (self.party and not ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0))) then --- partycheck yes, but not in party
		if (not giveReason) then return false; end
		return false, "Not in Party";
	end
        
    --- focus
	if (self.focus and (UnitName("focus") == nil or UnitIsDead("focus") or UnitName("focus") == UnitName("player"))) then --- focuscheck
		if (not giveReason) then return false; end
		return false, "No focus";
	end
        
    --- unit
	if (self.optunitn and not ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0) or UnitExists("pet"))) then --- Unitn yes, but not in party/raid or with pet
		if (not giveReason) then return false; end
		return false, "Can't find custom unit not in party, raid or with pet unit="..tostring(self.unitn);
	end
        
    --- raid
	if (self.raid and numrm == 0) then --- raidcheck yes, but not in raid
		if (not giveReason) then return false; end
		return false, "Not in raid";
	end
		
	--- regarde si la cible est amie
	if (self.target == false and self.targetfriend and not UnitIsFriend("player","target")) then --- cible ennemie
		if (not giveReason) then return false; end
		return false, "Target not friend";
	end

	--- dual spec check
	if ((not self.spec2 and PowaAuras.ActiveTalentGroup == 2) or (not self.spec1 and PowaAuras.ActiveTalentGroup == 1)) then
		if (not giveReason) then return false; end
		return false, "Aura not active for this talent spec";
    end
	
	--- mode combat, cache si besoin
	if ((PowaAuras.WeAreInCombat == true and self.combat == 2) or (PowaAuras.WeAreInCombat == false and self.combat == 1)) then
		if (not giveReason) then return false; end
		return false, "Not in combat";
	end
		
	if (PowaAuras.WeAreInRaid == false and self.isinraid == true) then
		if (not giveReason) then return false; end
		return false, "Not in raid";
	end
		
	if (PowaAuras.WeAreMounted ~= self.ismounted) then
		if (not giveReason) then return false; end
		if (PowaAuras.WeAreMounted) then
			return false, "Mounted";
		else
			return false, "Not Mounted";
		end
	end	
		
	if (PowaAuras.WeAreInVehicle ~= self.inVehicle) then	
		if (not giveReason) then return false; end
		return false, "Not In Vehicle";
	end	
	
	-- It's not dead it's restin'
	if (self.ignoreResting and (IsResting()==1) and (not PowaAuras.WeAreInCombat)) then	
		if (not giveReason) then return false; end
		return false, "Resting";
	end	
	
	if (not giveReason) then return true; end
	return true, "State OK";
end

function cPowaAura:ShouldShow(giveReason, reverse)
	PowaAuras:UnitTestInfo("ShouldShow", self.id);
	if (PowaMisc.Disabled) then
		return false, "Power Auras "..ADDON_DISABLED;
	end
	local stateResult, reason = self:CheckState(giveReason);	
	if (not stateResult) then
		self.InactiveDueToState = true;
		return stateResult, reason;
	end
	self.InactiveDueToState = false;
	local result, reason = self:CheckIfShouldShow(giveReason);
	if (result~=nil and (self.inverse or reverse) and not (self.inverse and reverse)) then
		result = not result;
		if (giveReason) then
			reason = reason .." (inverted)";
		end
	end
	return result, reason;
end

function cPowaAura:Display()
	PowaAuras:Message("Aura Display id=", self.id); --OK
	for k,v in pairs (self) do
		PowaAuras:Message("  "..tostring(k).." = "..tostring(v)); --OK
	end
end

function cPowaAura:GetFrame()
	if (self.isSecondary) then
		return PowaAuras.SecondaryFrames[self.id];
	end
	return PowaAuras.Frames[self.id];
end

function cPowaAura:GetTexture()
	if (self.isSecondary) then
		return PowaAuras.SecondaryTextures[self.id];
	end
	return PowaAuras.Textures[self.id];
end

function cPowaAura:SetFrame(frame)
	if (self.isSecondary) then
		PowaAuras.SecondaryFrames[self.id] = frame;
		return;
	end
	PowaAuras.Frames[self.id] = frame;
end

function cPowaAura:SetTexture(texture)
	if (self.isSecondary) then
		PowaAuras.SecondaryTextures[self.id] = texture;
		return;
	end
	PowaAuras.Textures[self.id] = texture;
end

function cPowaAura:GetSpellNameFromMatch(spellMatch)
	local _, _,spellId = string.find(spellMatch, "%[(%d+)%]")
	if (spellId) then		
		local spellName, rank, spellIcon = GetSpellInfo(tonumber(spellId));
		return spellName, spellIcon;
	end
	return spellMatch;
end

function cPowaAura:SetStacks(text)
	local _, _,curStacksLower, curOperator, curStacks = string.find(text, "(%d*)(%D+)(%d*)")

	if (curStacks == nil or curStacks == "") then curStacks = "0"; end
	local stacks = tonumber(curStacks);
	--PowaAuras:Debug(stacks);
		
	if (stacks ~= self.stacks) then
		if (stacks > 100) or (stacks < 0) then stacks = 0; end
		self.stacks = stacks or 0;
	end
	
	if (curStacksLower == nil or curStacksLower == "") then curStacksLower = "0"; end
	local stacksLower = tonumber(curStacksLower);
	--PowaAuras:Debug(stacksLower);
	
	if (stacksLower ~= self.stacksLower) then
		if (stacksLower > 100) or (stacksLower < 0) or (stacksLower > stacks) then stacksLower = 0; end
		self.stacksLower = stacksLower or 0;
	end
	
	if (curOperator ~= self.stacksOperator) then
		if (not PowaAuras.allowedOperators[curOperator]) then
			curOperator = PowaAuras.DefaultOperator;
		end	
		self.stacksOperator = curOperator;
	end	
end

function cPowaAura:Trim(s)
    return (string.gsub(s, "^%s*(.-)%s*$", "%1"));
end

function cPowaAura:MatchSpell(spellName, spellTexture, textToFind)
	if (spellName==nil or textToFind==nil) then
		return false;
	end
	if (textToFind=="*") then
		return true;
	end
	--PowaAuras:Debug("  MatchSpell spellName   =",spellName);
	--PowaAuras:Debug("             spellTexture=",spellTexture);
	--PowaAuras:Debug("             textToFind  =",textToFind);
	for pword in string.gmatch(textToFind, "[^/]+") do
		pword = self:Trim(pword);
		if (string.len(pword)>0) then
			local textToSearch;
			local textureMatch;
			if string.find(pword, "_") then
				 _, _,textToSearch = string.find(spellTexture, "([%w_]*)$")
			else
				textToSearch = spellName;
				pword, textureMatch = self:GetSpellNameFromMatch(pword);
			end
			--PowaAuras:Debug("textureMatch=", textureMatch);
			if (not textureMatch or textureMatch==spellTexture) then
				if (textToSearch) then
					if (self.ignoremaj) then
						textToSearch = string.upper(textToSearch)
						pword = string.upper(pword);
					end
					--PowaAuras:Debug("pword=", pword);
					--PowaAuras:Debug("search=", textToSearch);
					if (self.exact) then
						--PowaAuras:Debug("exact=", (textToSearch == pword));
						if (textToSearch == pword) then
							return true;
						end
					else
						--PowaAuras:Debug("find=", string.find(textToSearch, pword, 1, true));
						if (string.find(textToSearch, pword, 1, true)) then
							return true;
						end
					end
				end
			end
		end
	end

	return nil;
end

function cPowaAura:MatchText(textToSearch, textToFind)
	if (textToSearch==nil or textToFind==nil) then
		return false;
	end
	if (textToFind=="*") then
		return true;
	end
	--PowaAuras:Debug("MatchText textToSearch=",textToSearch," textToFind=",textToFind);
	if (self.ignoremaj) then
		textToFind = string.upper(textToFind);
		textToSearch = string.upper(textToSearch);
	end
	--PowaAuras:Debug("MatchText textToSearch=",textToSearch," textToFind=",textToFind, " ignoremaj=", self.ignoremaj, " exact=", self.exact);
	if (self.exact) then
		return (textToSearch == textToFind);
	end
	for pword in string.gmatch(textToFind, "[^/]+") do	
		--PowaAuras:Debug("pword=", pword," find=",string.find(textToSearch, pword, 1, true));
		if (string.find(textToSearch, pword, 1, true)) then
			return true;
		end
	end
	return nil;
end

function cPowaAura:CreateAuraString()
	local tempstr, varpref= "", "";
	for k, v in pairs (self) do
		--- multi condition checks not supported for export.
		if k == "multiids" then
			v = "";
		end
		local varType = type(v);
		if (varType == "string" or varType == "boolean" or varType == "number") then
			tempstr = tempstr..k..":"..string.sub(varType,1,2)
			if (varType == "string") then
				tempstr = tempstr..v;
			else
				tempstr = tempstr..tostring(v);
			end
			tempstr = tempstr.."; ";
		end
	end
	if (self.Timer) then
		for k, v in pairs (self.Timer) do
			local varType = type(v);
			if (varType == "string" or varType == "boolean" or varType == "number") then
				tempstr = tempstr.."timer."..k..":"..string.sub(varType,1,2);
				if (varType == "string") then
					tempstr = tempstr..v;
				else
					tempstr = tempstr..tostring(v);
				end
				tempstr = tempstr.."; ";
			end
		end
	end

	if tempstr and tempstr ~= "" then
		tempstr = strtrim(tempstr);
		tempstr = string.sub(tempstr, 1, string.len(tempstr)-1);
	end
	--PowaAuras:Debug("Aura-string length: "..tostring(string.len(tempstr)));
	return tempstr;
end

function cPowaAura:GetUnit()
	if (self.target or self.targetfriend) then
		return "target";
	elseif (self.focus) then
		return "focus";
	elseif (self.party) then
		return "party";
	elseif (self.raid) then
		return "raid";
	elseif (self.groupOrSelf) then
		return "groupOrSelf";
	elseif (self.optunitn) then
		return self.unitn;
	else 
		return "player";
	end	
	return nil;
end

function cPowaAura:CheckAllUnits(giveReason)
	local unit = self:GetUnit();		
	--PowaAuras:Debug("on unit "..unit);
	local numpm = GetNumPartyMembers();
	local numrm = GetNumRaidMembers();

	if unit == "party" then
		for pm = 1, numpm do
			unit = "party"..pm;
			if self:CheckUnit(unit) then
				if (not giveReason) then return true; end
				return true, unit.." "..self.MatchReason;
			end
		end
	elseif unit == "raid" then
		for rm = 1, numrm do
			unit = "raid"..rm;
			if self:CheckUnit(unit) then
				if (not giveReason) then return true; end
				return true, unit.." "..self.MatchReason;
			end
		end
	elseif  unit == "groupOrSelf" then
		if (numrm>0) then
			for rm = 1, numrm do
				unit = "raid"..rm;
				if self:CheckUnit(unit) then
					if (not giveReason) then return true; end
					return true, unit.." "..self.MatchReason;
				end
			end
		elseif (numpm>0) then
			for pm = 1, numpm do
				unit = "party"..pm;
				if self:CheckUnit(unit) then
					if (not giveReason) then return true; end
					return true, unit.." "..self.MatchReason;
				end
			end
			if self:CheckUnit("player") then
				if (not giveReason) then return true; end
				return true, unit.." "..self.MatchReason;
			end
		end
	else
		if self:CheckUnit(unit) then
			if (not giveReason) then return true; end
			return true, unit.." "..self.MatchReason;
		end
	end
	if (not giveReason) then return false; end
	return false, unit.." "..self.NoMatchReason;
end

function cPowaAura:CheckStacks(count)
	local operator = self.stacksOperator or PowaAuras.DefaultOperator;
	local stacks = self.stacks or 0;
	local stacksLower = self.stacksLower or 0;
	--PowaAuras:Debug("Stack op=",operator," stacks=",stacks,"Stack Count=",count);
	return    ((operator == "="  and stacks == 0)
			or (operator == ">=" and count >= stacks)
			or (operator == "<=" and count <= stacks)
			or (operator == ">"  and count > stacks)
			or (operator == "<"  and count < stacks)
			or (operator == "="  and count == stacks)
			or (operator == "-"  and count >= stacksLower and count <= stacks)
			or (operator == "!"  and count ~= stacks));
end

cPowaBuffBase = PowaClass(cPowaAura, {CanHaveTimer=true, CanHaveStacks=true});

function cPowaBuffBase:AddEffect(i)

	if not self.target 
   and not self.targetfriend 
   and not self.party
   and not self.raid 
   and not self.groupOrSelf
   and not self.focus
   and not self.optunitn then --- self-buff
		table.insert(PowaAuras.AurasByType.Buffs, i);
	end
	if self.party then --- partybuff cible
		table.insert(PowaAuras.AurasByType.PartyBuffs, i);
	end
	if self.focus then --- focus buffs
		table.insert(PowaAuras.AurasByType.FocusBuffs, i);
	end
	if self.raid then --- raid buffs
		table.insert(PowaAuras.AurasByType.RaidBuffs, i);
	end
	if self.groupOrSelf then --- groupOrSelf buffs
		table.insert(PowaAuras.AurasByType.GroupOrSelfBuffs, i);
	end
	if self.optunitn then --- unit buffs
		table.insert(PowaAuras.AurasByType.UnitBuffs, i);
	end
	if (self.target or self.targetfriend) then --- target buff
		table.insert(PowaAuras.AurasByType.TargetBuffs, i);
	end			
end

function cPowaBuffBase:IsPresent(unittarget, s)

	--PowaAuras:Debug("IsPresent on ",unittarget,"  buffid ",s," type", self.buffAuraType);

	local auraName, _, auraTexture, count, _, _, expirationTime, caster = UnitAura(unittarget, s, self.buffAuraType);
	
	if (auraName == nil) then return nil; end

	--PowaAuras:Debug("Aura=",auraName," count=",count," expirationTime=", expirationTime," caster=",caster);

	if (not self:CompareAura(unittarget, s, auraName, auraTexture)) then
		--PowaAuras:Debug("CompareAura not found");
		return false;
	end
	
	local isMine = (caster~=nil) and UnitExists(caster) and UnitIsUnit("player", caster);
	local bemine = self.mine;
	--PowaAuras:ShowText("Bemine=",bemine," isMine=",isMine);
	if (bemine and isMine) or (not bemine) then
		if (self:CheckStacks(count)) then
			--PowaAuras:ShowText("Present!");
			if (self.Timer) then
				self.Timer.DurationInfo = expirationTime;
			end
			if (self.Stacks) then
				self.StackCount = count;
			end			
			return true;
		end
	end
	
	return false;
end	

function cPowaBuffBase:CheckTooltip(text, target, index)
	if (text==nil or string.len(text) == 0) then
		return true;
	end

	--PowaAuras:Debug("Search in tooltip for ",text);

	PowaAuras_Tooltip:SetOwner(UIParent, "ANCHOR_NONE");
	PowaAuras_Tooltip:SetUnitAura(target, index, self.buffAuraType);
	
	for z = 1, PowaAuras_Tooltip:NumLines() do
		--PowaAuras:UnitTestDebug("Check tooltip line ",z);
		local textlinel = getglobal("PowaAuras_TooltipTextLeft"..z);
		local textl = textlinel:GetText();
		local tooltipText = "";
		if textl then
			tooltipText = tooltipText..textl;
		end
		local textliner = getglobal("PowaAuras_TooltipTextRight"..z);
		local textr = textliner:GetText();
		if textr then
			tooltipText = tooltipText..textr;
		end
		if (tooltipText ~= "") then
			--PowaAuras:UnitTestDebug("| "..text.." |");		
			if (string.find(tooltipText, text, 1, true)) then
				PowaAuras_Tooltip:Hide();
				return true;
			end
		end
	end	
	PowaAuras_Tooltip:Hide();
	return false;
end

function cPowaBuffBase:CompareAura(target, z, auraName, auraTexture, giveReason)
	
	--PowaAuras:Debug("CompareAura",z," ",auraName, auraTexture);
	
	if self:MatchSpell(auraName, auraTexture, self.buffname) then
		--PowaAuras:UnitTestDebug("Aura match found! ", self.id);
		if (not self:CheckTooltip(self.tooltipCheck, target, z)) then
			--PowaAuras:UnitTestDebug("Tooltip no match found!");
			if (not giveReason) then return false; end
			return false, target.." has "..self.auraType.." "..auraName.." but tooltip does not match";
		end
		local tempicon;
		if (self.owntex == true) then
			getglobal("PowaIconTexture"):SetTexture(auraTexture);
			tempicon = getglobal("PowaIconTexture"):GetTexture();
			if (self.icon ~= tempicon) then
				self.icon = tempicon;
			end
		end
		if (self.icon == "") then
			getglobal("PowaIconTexture"):SetTexture(auraTexture);
			self.icon = getglobal("PowaIconTexture"):GetTexture();
		end
		if (not giveReason) then return true; end
		return true, target.." has "..self.auraType.." "..auraName;	
	end
	if (not giveReason) then return false; end
	return false, target.." does not have "..self.auraType.." "..self.buffname;
end

function cPowaBuffBase:CheckAllAuraSlots(target, giveReason)
	--PowaAuras:UnitTestDebug("-------------");
	--PowaAuras:UnitTestDebug("CheckAllAuraSlots for ", target);
	for i = 1, 40 do
		local present = self:IsPresent(target, i);
		if (present==nil) then
			if (not giveReason) then return false; end
			return false, target.." doesn't have "..self.auraType.." "..self.buffname; 
		end
		if (present) then
			--PowaAuras:UnitTestDebug("CheckAllAuraSlots Present!");
			if (not giveReason) then return true; end
			return true, target .." has "..self.auraType.." "..self.buffname;
		end	
	end
	if (not giveReason) then return false; end
	return false, target.." doesn't have "..self.auraType.." "..self.buffname;
end

function cPowaBuffBase:CheckGroup(group, count, giveReason)
	for groupId = 1, count do
		local present = self:CheckAllAuraSlots(group..groupId, false);
		if (present) then
			if (self.groupany == true) then
				--PowaAuras:UnitTestDebug("CheckGroup("..group..") Present!");
				if (not giveReason) then return true; end
				return true, group..groupId .." has "..self.auraType.." "..self.buffname;
			end
		elseif (self.groupany==false) then
			if (not giveReason) then return false; end
			return false, "Not all in "..group.." has "..self.auraType.." "..self.buffname;
		end
	end
	if (self.groupany==false) then
		--PowaAuras:UnitTestDebug("CheckGroup("..group..") All Present!");
		if (not giveReason) then return true; end
		return true, "All in "..group.." has "..self.auraType.." "..self.buffname;
	end
	if (not giveReason) then return false; end
	return false, "No one in "..group.." has "..self.auraType.." "..self.buffname;
end

function cPowaBuffBase:CheckIfShouldShow(giveReason)
	PowaAuras:UnitTestInfo("CheckIfShouldShow ",self.buffAuraType," aura");
	--PowaAuras:Debug("Check " .. self.buffAuraType .. " aura");
	local numpm = GetNumPartyMembers();
	local numrm = GetNumRaidMembers();
	--- targets
	if (self.target or self.targetfriend) then
		--PowaAuras:UnitTestDebug("on target or friendlytarget");
		return self:CheckAllAuraSlots("target", giveReason);
	end	
	--- focus buff    
	if self.focus then
		--PowaAuras:UnitTestDebug("on focus");
		return self:CheckAllAuraSlots("focus", giveReason);
	end		
	--- unit buff    
	if self.optunitn then
		--PowaAuras:UnitTestDebug("on unit "..self.unitn);
		return self:CheckAllAuraSlots(self.unitn, giveReason);
	end		
	--- raid buff
	if self.raid then
		--PowaAuras:UnitTestDebug("on raid size=", numrm);
		return self:CheckGroup("raid", numrm, giveReason);
	end			
	--- partybuff    
	if self.party then
		--PowaAuras:UnitTestDebug("on party size=", numpm);
		return self:CheckGroup("party", numpm, giveReason);
	end
	
	if (self.groupOrSelf) then --- Group or Self Buff
		--PowaAuras:UnitTestDebug("on Group or Self");
		if (numrm>0) then
			--PowaAuras:UnitTestDebug("GoS on raidunit");
			return self:CheckGroup("raid", numrm, giveReason); -- includes player
		end
		if (numpm>0) then
			--PowaAuras:UnitTestDebug("GoS on partyunit or self");
			local presentOnSelf, reason = self:CheckAllAuraSlots("player", giveReason);
			if (presentOnSelf and self.groupany) then
				if (not giveReason) then return true; end
				return true, reason;
			end
			if (not presentOnSelf and not self.groupany) then
				if (not giveReason) then return false; end
				return false, reason;
			end
			return self:CheckGroup("party", numpm, giveReason);
		end
		--PowaAuras:UnitTestDebug("GoS on player");
		return self:CheckAllAuraSlots("player", giveReason);
	end
			
	--- player buff    

	--PowaAuras:Debug("on player");
	return self:CheckAllAuraSlots("player", giveReason);
end
function cPowaBuffBase:ShowTimerDurationSlider()
	return (self.target
		 or self.targetfriend
		 or self.party
		 or self.focus
		 or self.raid
		 or self.optunitn);
end

cPowaBuffBase.ShowOptions = {["PowaBarBuffStacks"]=1,
							 ["PowaGroupAnyButton"]=1,
							 ["PowaBarTooltipCheck"]=1};
cPowaBuffBase.CheckBoxes = {["PowaTargetButton"]=1,
							["PowaTargetFriendButton"]=1,
							["PowaPartyButton"]=1,
							["PowaFocusButton"]=1,
							["PowaRaidButton"]=1,
							["PowaGroupOrSelfButton"]=1,
							["PowaGroupAnyButton"]=1,
							["PowaOptunitnButton"]=1,
							["PowaInverseButton"]=1,
							["PowaIgnoreMajButton"]=1,
							["PowaIsInRaidButton"]=1,
							["PowaRestingButton"]=1,
							["PowaIsMountedButton"]=1,
							["PowaOwntexButton"]=1};						  

cPowaBuff = PowaClass(cPowaBuffBase, {buffAuraType="HELPFUL", auraType="buff"});
cPowaBuff.OptionText={buffNameTooltip=PowaAuras.Text.aideBuff, 
					  exactTooltip=PowaAuras.Text.aideExact,
					  typeText=PowaAuras.Text.nomCheckBuff, 
					  mineText=PowaAuras.Text.nomMine};
									  
cPowaDebuff = PowaClass(cPowaBuffBase, {buffAuraType = "HARMFUL", auraType="debuff"});
cPowaDebuff.OptionText={buffNameTooltip=PowaAuras.Text.aideBuff2,
						 exactTooltip=PowaAuras.Text.aideExact2,
						 typeText=PowaAuras.Text.nomCheckDebuff,
						 mineText=PowaAuras.Text.nomMine};

cPowaTypeDebuff = PowaClass(cPowaBuffBase, {buffAuraType = "HARMFUL", auraType="debuff type"});
cPowaTypeDebuff.OptionText={buffNameTooltip=PowaAuras.Text.aideBuff3, exactTooltip=PowaAuras.Text.aideExact3, typeText=PowaAuras.Text.nomCheckDebuffType, mineText=PowaAuras.Text.nomDispellable};
cPowaTypeDebuff.ShowOptions = {["PowaGroupAnyButton"]=1,
							   ["PowaBarTooltipCheck"]=1};						 
cPowaTypeDebuff.CheckBoxes = {["PowaTargetButton"]=1,
							  ["PowaTargetFriendButton"]=1,
							  ["PowaPartyButton"]=1,
							  ["PowaFocusButton"]=1,
							  ["PowaRaidButton"]=1,
							  ["PowaGroupOrSelfButton"]=1,
							  ["PowaGroupAnyButton"]=1,
							  ["PowaOptunitnButton"]=1,
							  ["PowaInverseButton"]=1,
							  ["PowaIgnoreMajButton"]=1,
							  ["PowaIsInRaidButton"]=1,
							  ["PowaRestingButton"]=1,
							  ["PowaIsMountedButton"]=1};

function cPowaTypeDebuff:IsPresent(target, z)
	local removeable;
	if (self.mine) then
		removeable = 1;
	end
	local name, _, texture, count, typeDebuff, _, expirationTime = UnitDebuff(target, z, removeable);
	if (not name) then
		return false;
	end
	--PowaAuras:Debug("TypeDebuff IsPresent on ",target,"  buffid ",z,"  removeable ",removeable);
	if (self.mine and typeDebuff==nil) then
		return false;
	end

	--PowaAuras:UnitTestDebug("Debuff ",name," type ",typeDebuff);
		
	local typeDebuffName;
	if (typeDebuff ~= nil) then
		typeDebuffName = PowaAuras.Text.DebuffType[typeDebuff];
	end
	local typeDebuffCatName = PowaAuras.Text.DebuffCatType[PowaAuras.DebuffCatSpells[name]];
	if (typeDebuffName == nil and typeDebuffCatName==nil) then
		typeDebuffName = PowaAuras.Text.aucun;
	end

	--PowaAuras:UnitTestDebug("typeDebuffName ",typeDebuffName);
	--PowaAuras:UnitTestDebug("typeDebuffCatName ",typeDebuffCatName);
	--PowaAuras:UnitTestDebug("self.buffname ",self.buffname);
	
	if self:MatchText(typeDebuffName, self.buffname)
	or self:MatchText(typeDebuffCatName, self.buffname) then
		if (self.Timer) then
			self.Timer.DurationInfo = expirationTime;
		end
		if (self.Stacks) then
			self.StackCount = count;
		end			
		if (self.icon == "") then
			getglobal("PowaIconTexture"):SetTexture(texture);
			self.icon = getglobal("PowaIconTexture"):GetTexture();
		end
		return true;
	end

	return false;
end


-- This is not really AoE it is periodic damage, could be a DoT or a ground effect damage
cPowaAoE = PowaClass(cPowaAura, {AuraType = "Aoe"});
cPowaAoE.OptionText={buffNameTooltip=PowaAuras.Text.aideBuff4, exactTooltip=PowaAuras.Text.aideExact4, typeText=PowaAuras.Text.nomCheckAoeDebuff};
cPowaAoE.ShowOptions={["PowaBarTooltipCheck"]=1};				 
cPowaAoE.CheckBoxes={["PowaIgnoreMajButton"]=1,
					 ["PowaIsInRaidButton"]=1,
					 ["PowaRestingButton"]=1,
					 ["PowaIgnoreMajButton"]=1,
					 ["PowaIsMountedButton"]=1};
function cPowaAoE:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check AoE");

	if (PowaAuras.DoResetAoe == true) then --- probablement mort, on reset l'effet
		if (not giveReason) then return false; end
		return false, "AoE reset";
	elseif (PowaAuras.AoeAuraAdded ~= "") then --- debuff ajoute
		if self:MatchSpell(PowaAuras.AoeAuraAdded, PowaAuras.AoeAuraTexture, self.buffname) then
			if (self.icon == "") then
				getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Spell_fire_meteorstorm");
				self.icon = getglobal("PowaIconTexture"):GetTexture();
			end
			if (not giveReason) then return true; end
			return true, "AoE Added "..self.buffname;
		end
	elseif (PowaAuras.AoeAuraFaded ~= "") then 
		if self:MatchSpell(PowaAuras.AoeAuraFaded, PowaAuras.AoeAuraTexture, self.buffname) then
			if (self.icon == "") then
			  getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Spell_fire_meteorstorm");
			  self.icon = getglobal("PowaIconTexture"):GetTexture();
			end
			if (not giveReason) then return true; end
			return true, "AoE Faded "..self.buffname;
		end
	end
	
	if (not self.Active) then
		if (not giveReason) then return false; end
		return false, "AoE expired";
	else
		if (not giveReason) then return true; end
		return true, "AoE active";
	end
end

cPowaEnchant = PowaClass(cPowaAura, {AuraType = "Enchants", CanHaveTimer=true, CanHaveTimerOnInverse=true, CanHaveStacks=true});
cPowaEnchant.OptionText = {buffNameTooltip=PowaAuras.Text.aideBuff5, exactTooltip=PowaAuras.Text.aideExact5, typeText=PowaAuras.Text.nomCheckEnchant};
cPowaEnchant.ShowOptions={["PowaBarBuffStacks"]=1};
cPowaEnchant.CheckBoxes={["PowaIgnoreMajButton"]=1,
						 ["PowaInverseButton"]=1,
						 ["PowaIsInRaidButton"]=1,
						 ["PowaRestingButton"]=1,
						 ["PowaIsMountedButton"]=1,
						 ["PowaOwntexButton"]=1};
function cPowaEnchant:GetDuration(durationInfo)
	if (durationInfo and durationInfo > 0) then
		return durationInfo / 1000;
	end
	return 0;
end
function cPowaEnchant:CheckforEnchant(slot, enchantText, textToFind)
	--PowaAuras:Debug("Check enchant ("..enchantText..") active in slot",slot);
	--PowaAuras:ShowText("Check enchant ("..enchantText..") active in slot",slot);
	PowaAuras_Tooltip:SetOwner(UIParent, "ANCHOR_NONE");
	PowaAuras_Tooltip:SetInventoryItem("player", slot);
	--PowaAuras:UnitTestDebug("search in tooltip for ", textToFind);			
	--PowaAuras:ShowText("search in tooltip for ", textToFind);			
	for z = 1, PowaAuras_Tooltip:NumLines() do
		--PowaAuras:UnitTestDebug("Check tooltip line ",z);
		--PowaAuras:ShowText("Check tooltip line ",z);
		local textlinel = getglobal("PowaAuras_TooltipTextLeft"..z);
		local textl = textlinel:GetText();
		local text = "";
		if textl then
			text = text..textl;
		end
		local textliner = getglobal("PowaAuras_TooltipTextRight"..z);
		local textr = textliner:GetText();
		if textr then
			text = text..textr;
		end
		if (text ~= "") then
			--PowaAuras:UnitTestDebug("| "..text.." |");
			--PowaAuras:ShowText("| "..text.." |");
			if (self:MatchText(text, textToFind)) then
				PowaAuras_Tooltip:Hide();
				return true;
			end
		end
	end	
	PowaAuras_Tooltip:Hide();
	return false;		
end
				
function cPowaEnchant:SetForEnchant(loc, slot, charges, index)
	--PowaAuras:Debug(loc,":found ",self.buffname," in the tooltip!");
	if (self:CheckStacks(charges)) then
		if (self.icon == "") then
			getglobal("PowaIconTexture"):SetTexture( GetInventoryItemTexture("player", slot) );
			self.icon = getglobal("PowaIconTexture"):GetTexture();
		end 
		if (self.Stacks) then
			self.StackCount = count;
		end			
		return true;
	end
	return false;
end
		
function cPowaEnchant:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check weapon enchant");
	local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo();

	local checkMain = true;
	local checkOff = true;
	for pword in string.gmatch(self.buffname, "[^/]+") do
		if (pword==PowaAuras.Text.mainHand) then
			checkMain = true;
			checkOff = false;
		elseif (pword==PowaAuras.Text.offHand) then
			checkOff = true;
			checkMain = false;
		else
			if (hasMainHandEnchant and checkMain) then		
				if (self:CheckforEnchant(16, PowaAuras.Text.mainHand, pword)) then
					if (self:SetForEnchant("MH", 16, mainHandCharges, 1)) then
						if (self.Timer) then
							self.Timer.DurationInfo = mainHandExpiration;
						end
						if (self.Stacks) then
							self.StackCount = mainHandCharges;
						end			
						if (not giveReason) then return true; end
						return true, "Main Hand "..self.buffname.." enchant found";
					end
				end			
			end
			if (hasOffHandEnchant and checkOff) then
				if (self:CheckforEnchant(17, PowaAuras.Text.offHand, pword)) then
					if (self:SetForEnchant("OH", 17, offHandCharges, 2)) then
						if (self.Timer) then
							self.Timer.DurationInfo = offHandExpiration;
						end		
						if (self.Stacks) then
							self.StackCount = offHandCharges;
						end			
						if (not giveReason) then return true; end
						return true, "Off Hand "..self.buffname.." enchant found";
					end
				end	
			end
		end
	end
	if (not giveReason) then return false; end
	return false, "No enchant found on weapons";
end

cPowaCombo = PowaClass(cPowaAura, {AuraType = "Combo", CanHaveStacks=true});
cPowaCombo.OptionText={buffNameTooltip=PowaAuras.Text.aideBuff6, exactTooltip=PowaAuras.Text.aideExact6, typeText=PowaAuras.Text.nomCheckCombo};
cPowaCombo.CheckBoxes={["PowaIgnoreMajButton"]=1,
					   ["PowaIsInRaidButton"]=1,
					   ["PowaRestingButton"]=1,
					   ["PowaIsMountedButton"]=1};
							  					 
function cPowaCombo:CheckIfShouldShow(giveReason)
	if (not(PowaAuras.playerclass == "ROGUE" or (PowaAuras.playerclass=="DRUID" and GetShapeshiftForm()==3))) then
		return nil, "You do not use combo points";
	end
	--PowaAuras:Debug("Check Combos");
	local nCombo = tostring(GetComboPoints("player"));
	--PowaAuras:UnitTestDebug("nCombo=", nCombo, " self.buffname=", self.buffname);
	if self:MatchText(nCombo, self.buffname) then
		if (self.icon == "") then
			getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\inv_sword_48");
			self.icon = getglobal("PowaIconTexture"):GetTexture();
		end
		if (self.Stacks) then
			self.StackCount = nCombo;
		end			
		if (not giveReason) then return true; end
		return true, "Combo points "..nCombo.." match "..self.buffname;
	end
	if (not giveReason) then return false; end
	return false, "Combo points "..nCombo.." no match with "..self.buffname;
end

cPowaActionReady = PowaClass(cPowaAura, {AuraType = "Actions", CanHaveTimer=true, CanHaveTimerOnInverse=true, CooldownAura=true});
cPowaActionReady.OptionText={buffNameTooltip=PowaAuras.Text.aideBuff7, exactTooltip=PowaAuras.Text.aideExact7, typeText=PowaAuras.Text.nomCheckSkill};
cPowaActionReady.CheckBoxes={["PowaIgnoreMajButton"]=1,
							 ["PowaInverseButton"]=1,
							 ["PowaIsInRaidButton"]=1,
							 ["PowaRestingButton"]=1,
							 ["PowaIsMountedButton"]=1,
							 ["PowaOwntexButton"]=1,
							 ["PowaGCDButton"]=1};
function cPowaActionReady:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check Action / Button:", self.slot);
	if (not self.slot or self.slot == 0) then 
		if (not giveReason) then return false; end
		return false, "Action not set"; 
	end 

	local isUsable = IsUsableAction(self.slot);
	local cdstart, cdduration, enable = GetActionCooldown(self.slot);
	--PowaAuras:UnitTestDebug("cdstart= ",cdstart," duration= ",cdduration);
	if (cdduration > 0.2 and cdduration < 1.7 and self.gcd == false) then
		if (isUsable == 1) then --- utilisable, pas de cooldown
			if (not giveReason) then return true; end
			return true, "Action Ready";
		end
	else
		if (isUsable == 1 and cdstart == 0) then
			if (not giveReason) then return true; end
			return true, "Action Ready";
		end
	end
	if (self.Timer) then
		if (enable>0) then
			self.Timer.DurationInfo = cdstart + cdduration;
		else
			self.Timer.DurationInfo = 0;
		end
	end		
	if (not giveReason) then return false; end
	return false, "Action Not Ready, on cooldown";
end
function cPowaActionReady:ShowTimerDurationSlider()
	return true;
end

cPowaOwnSpell = PowaClass(cPowaAura, {AuraType = "OwnSpells", CanHaveTimer=true, CanHaveTimerOnInverse=true, CooldownAura=true});
cPowaOwnSpell.OptionText={buffNameTooltip=PowaAuras.Text.aideBuff8, exactTooltip=PowaAuras.Text.aideExact, typeText=PowaAuras.Text.nomCheckOwnSpell};
cPowaOwnSpell.ShowOptions={["PowaBarTooltipCheck"]=1};
cPowaOwnSpell.CheckBoxes={["PowaGCDButton"]=1,
						  ["PowaInverseButton"]=1,
						  ["PowaIgnoreMajButton"]=1,
						  ["PowaIsInRaidButton"]=1,
						  ["PowaRestingButton"]=1,
						  ["PowaInverseButton"]=1,
						  ["PowaIgnoreMajButton"]=1,
						  ["PowaIsMountedButton"]=1,
						  ["PowaOwntexButton"]=1};
function cPowaOwnSpell:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check Spell:", self.buffname);
	--PowaAuras:Message("Check Spell:", self.buffname);
	local reason = "";
	for pword in string.gmatch(self.buffname, "[^/]+") do
		local spellName, spellIcon = self:GetSpellNameFromMatch(pword);
		if (self.icon == "") then
			if (not spellIcon) then
				_, _, spellIcon = GetSpellInfo(spellName);
			end
			if (spellIcon) then
				getglobal("PowaIconTexture"):SetTexture(spellIcon);
				self.icon = getglobal("PowaIconTexture"):GetTexture();
			end
		end
		local show = false;
		local cdstart, cdduration, enabled = GetSpellCooldown(spellName);
		--PowaAuras:UnitTestDebug("cdstart= ",cdstart," duration= ",cdduration," enabled= ",enabled);
		--PowaAuras:Message("cdstart= ",cdstart," duration= ",cdduration," enabled= ",enabled);
		if (enabled) then
			local isUsable = IsUsableSpell(spellName);
			if (cdduration > 0.2 and cdduration < 1.7 and self.gcd == false) then
				show = (isUsable == 1);
			else
				show = (isUsable == 1 and cdstart == 0);
			end	
			--PowaAuras:Message("show= ",show," self.Timer= ",self.Timer);
			if (show) then
				--self.duration = math.max(cdstart + cdduration - GetTime(), 0)
				if (not giveReason) then return true; end
				return true, "Spell "..spellName.." usable";
			else
				if (self.Timer) then
					self.Timer.DurationInfo = cdstart + cdduration;
					--PowaAuras:Message("Set DurationInfo= ",self.Timer.DurationInfo);
				end
				if (giveReason) then
					reason = reason..spellName.." not usable ";
				end
			end
		elseif (giveReason) then
			reason = reason..spellName.." not enabled "
		end
	end
	if (not giveReason) then return false; end
	if (reason == "") then
		return false, "Spell "..self.buffname.." not found";
	end
	return false, reason
end
function cPowaOwnSpell:ShowTimerDurationSlider()
	return true;
end

cPowaAuraStats = PowaClass(cPowaAura);
cPowaAuraStats.ShowOptions={["PowaBarThresholdSlider"]=1,
						    ["PowaThresholdInvertButton"]=1};					 
cPowaAuraStats.CheckBoxes={["PowaTargetButton"]=1,
						   ["PowaTargetFriendButton"]=1,
						   ["PowaPartyButton"]=1,
						   ["PowaFocusButton"]=1,
						   ["PowaRaidButton"]=1,
						   ["PowaGroupOrSelfButton"]=1,
						   ["PowaGroupAnyButton"]=1,
						   ["PowaOptunitnButton"]=1,
						   ["PowaInverseButton"]=1,
						   ["PowaIsInRaidButton"]=1,
						   ["PowaRestingButton"]=1,
						   ["PowaIsMountedButton"]=1};

function cPowaAuraStats:AddEffect(i)
  if not self.target 
  and not self.targetfriend 
  and not self.party 
  and not self.raid 
  and not self.focus
  and not self.optunitn then
		table.insert(PowaAuras.AurasByType[self.ValueName], i);
	end
	if self.optunitn then
		table.insert(PowaAuras.AurasByType["NamedUnit"..self.ValueName], i);
	end
	if self.focus then     
		table.insert(PowaAuras.AurasByType["Focus"..self.ValueName], i);
	end
	if (self.target or self.targetfriend) then --- TargetHealth
		table.insert(PowaAuras.AurasByType["Target"..self.ValueName], i);
	end
	if self.party then
		table.insert(PowaAuras.AurasByType["Party"..self.ValueName], i);
	end
	if self.raid then
		table.insert(PowaAuras.AurasByType["Raid"..self.ValueName], i);
	end
end
function cPowaAuraStats:CheckUnit(unit)
	--PowaAuras:Debug("CheckUnit " .. unit);
	if (not self:IsCorrectPowerType(unit)) then
		--PowaAuras:UnitTestDebug("Correct powertype " ,self:IsCorrectPowerType(unit));
		return nil;
	end			
	if (UnitIsDeadOrGhost(unit)) then
		--PowaAuras:UnitTestDebug("Correct powertype dead ", UnitIsDeadOrGhost(unit));
		return false;
	end			

	local curValue = self:UnitValue(unit);
	local maxValue = self:UnitValueMax(unit);
	--PowaAuras:UnitTestDebug("curValue=", curValue, " maxValue=", maxValue);
	if (curValue==nil or maxValue==nil) then return false; end

	local curpercenthp = (curValue / maxValue) * 100;
	if self.thresholdinvert then 
		thresholdvalidate = (curpercenthp > self.threshold);
	else
		thresholdvalidate = (curpercenthp < self.threshold)
	end	
	if (thresholdvalidate) then
		if (self.icon == "") then
			getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Spell_fire_meteorstorm");
			self.icon = getglobal("PowaIconTexture"):GetTexture();
		end
		return true;
	end
	return false;
end

function cPowaAuraStats:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check Stat "..self.ValueName);
	return self:CheckAllUnits(giveReason);
end


cPowaHealth = PowaClass(cPowaAuraStats, {ValueName = "Health", MatchReason="Health low", NoMatchReason="Health not low enough"});
cPowaHealth.OptionText={typeText=PowaAuras.Text.nomCheckHealth};
function cPowaHealth:IsCorrectPowerType(unit)
	return true;
end
function cPowaHealth:UnitValue(unit)
	return UnitHealth(unit);
end
function cPowaHealth:UnitValueMax(unit)
	return UnitHealthMax(unit);
end


cPowaMana = PowaClass(cPowaAuraStats, {ValueName = "Mana", MatchReason="Mana low", NoMatchReason="Mana not low enough"});
cPowaMana.OptionText={typeText=PowaAuras.Text.nomCheckMana};
function cPowaMana:IsCorrectPowerType(unit)
	local powerType = UnitPowerType(unit);
	return (powerType and powerType == 0);
end
function cPowaMana:UnitValue(unit)
	--PowaAuras:Debug("Mana UnitValue for ", unit);
	return UnitPower(unit);
end
function cPowaMana:UnitValueMax(unit)
	--PowaAuras:Debug("Mana UnitValueMax for ", unit);
	return UnitPowerMax(unit);
end

cPowaEnergyRagePower = PowaClass(cPowaMana, {ValueName = "RageEnergy", MatchReason="EnergyRagePower low", NoMatchReason="EnergyRagePower not low enough"});
cPowaEnergyRagePower.OptionText={typeText=PowaAuras.Text.nomCheckRageEnergy};
function cPowaEnergyRagePower:IsCorrectPowerType(unit)
	local powerType = UnitPowerType(unit);
	return (powerType and powerType > 0);
end

cPowaAggro = PowaClass(cPowaAura, {ValueName = "Aggro", MatchReason="has aggro", NoMatchReason="does not have aggro"});
cPowaAggro.OptionText={typeText=PowaAuras.Text.nomCheckAggro};
cPowaAggro.CheckBoxes={["PowaPartyButton"]=1,
					   ["PowaRaidButton"]=1,
					   ["PowaGroupOrSelfButton"]=1,
					   ["PowaIsInRaidButton"]=1,
					   ["PowaRestingButton"]=1,
					   ["PowaIsMountedButton"]=1,
					   ["PowaInverseButton"]=1};
function cPowaAggro:AddEffect(i)

	if not self.target 
   and not self.targetfriend 
   and not self.party
   and not self.raid 
   and not self.focus
   and not self.optunitn then --- self Aggro
	table.insert(PowaAuras.AurasByType.Aggro, i);
	end
	if self.party then --- party Aggro
		table.insert(PowaAuras.AurasByType.PartyAggro, i);
	end
	if self.raid then --- raid Aggro
		table.insert(PowaAuras.AurasByType.RaidAggro, i);
	end
end

function cPowaAggro:CheckUnit(unit)
	--PowaAuras:Message(unit," UnitThreatSituation=", UnitThreatSituation(unit));
	return (UnitThreatSituation(unit) or -1)> 0;
end	
function cPowaAggro:CheckIfShouldShow(giveReason)
	if (self.icon == "") then
		getglobal("PowaIconTexture"):SetTexture("Interface\\icons\\Ability_Warrior_EndlessRage");
		self.icon = getglobal("PowaIconTexture"):GetTexture();
	end
	--PowaAuras:Debug("Check Aggro status");
	return self:CheckAllUnits(giveReason);
end

cPowaPvP = PowaClass(cPowaAura, {MatchReason="PvP flag set", NoMatchReason="PvP flag not set"});
cPowaPvP.OptionText={typeText=PowaAuras.Text.nomCheckPvP};
cPowaPvP.CheckBoxes={["PowaTargetButton"]=1,
					 ["PowaTargetFriendButton"]=1,
					 ["PowaPartyButton"]=1,
					 ["PowaGroupOrSelfButton"]=1,
					 ["PowaRaidButton"]=1,
					 ["PowaIsInRaidButton"]=1,
					 ["PowaRestingButton"]=1,
					 ["PowaIsMountedButton"]=1};
							  

function cPowaPvP:AddEffect(i)
	if not self.target 
  and not self.targetfriend 
  and not self.party
	and not self.raid 
	and not self.focus
  and not self.optunitn then --- self pvp flag
		table.insert(PowaAuras.AurasByType.PvP, i);
	end
	if (self.target or self.targetfriend) then --- target flag
		table.insert(PowaAuras.AurasByType.TargetPvP, i);
	end
	if self.party then --- party pvp flagged
		table.insert(PowaAuras.AurasByType.PartyPvP, i);
	end
	if self.raid then --- raid pvp flagged
		table.insert(PowaAuras.AurasByType.RaidPvP, i);
	end
end
function cPowaPvP:CheckUnit(unit)
	return UnitIsPVP(unit);
end	
function cPowaPvP:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check PvP Flag");
	return self:CheckAllUnits(giveReason);
end


cPowaSpellAlert = PowaClass(cPowaAura);
cPowaSpellAlert.OptionText={buffNameTooltip=PowaAuras.Text.aideSpells, exactTooltip=PowaAuras.Text.aideExact, typeText=PowaAuras.Text.nomCheckSpells};
cPowaSpellAlert.CheckBoxes={["PowaTargetButton"]=1,
							["PowaFocusButton"]=1,
							["PowaInverseButton"]=1,
							["PowaIgnoreMajButton"]=1,
							["PowaIsInRaidButton"]=1,
							["PowaOwntexButton"]=1,
							["PowaRestingButton"]=1,
							["PowaIsMountedButton"]=1};

function cPowaSpellAlert:AddEffect(i)
	if not self.target and not self.focus then --- any enemy casts
		table.insert(PowaAuras.AurasByType.Spells, i);
	end
	if self.target then --- target casts
		table.insert(PowaAuras.AurasByType.TargetSpells, i);
	end
	if self.focus then --- focus casts
		table.insert(PowaAuras.AurasByType.FocusSpells, i);
	end
end

function cPowaSpellAlert:CreateSpellFrame(endtime, spellicon)
	local tempicon;
	if (self.owntex == true) then
		getglobal("PowaIconTexture"):SetTexture(spellicon);
		tempicon = getglobal("PowaIconTexture"):GetTexture();
		if (self.icon ~= tempicon) then
			self.icon = tempicon;
		end
	end
	if (self.icon == "") then
	  getglobal("PowaIconTexture"):SetTexture(spellicon);
	  self.icon = getglobal("PowaIconTexture"):GetTexture();
	end
end

function cPowaSpellAlert:GetDuration(durationInfo)
	if (durationInfo and durationInfo > 0) then
		return durationInfo / 1000;
	end
	return 0;
end

function cPowaSpellAlert:CheckUnit(unit)
	if not UnitExists(unit) or UnitIsDead(unit) or not UnitCanAttack(unit, "player") then
		--PowaAuras:UnitTestDebug(unit, " exists=", UnitExists(unit), " dead=", UnitIsDeadOrGhost(unit), " hostile=", UnitCanAttack(unit, "player"));
		return false;
	end
	local spellname, _, _, spellicon, _, endtime = UnitCastingInfo(unit);
	if not spellname then
		spellname, _, _, spellicon, _, endtime = UnitChannelInfo(unit);
	end
	if not spellname then -- not casting
		--PowaAuras:UnitTestDebug(unit, " is not casting");
		return false;
	end
		
	if self:MatchSpell(spellname, spellicon, self.buffname, true) then
		if (self.Timer) then
			self.Timer.DurationInfo = endtime;
		end
		self:CreateSpellFrame(endtime, spellicon);
		return true;
	end
	
	--PowaAuras:UnitTestDebug(unit, " is casting ", spellname, " no match");
	return false;
end	

function cPowaSpellAlert:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check if target/focus is casting ", self.buffname);
	
	-- Check self target/focus first
	if (self:CheckUnit("target")) then
		if (not giveReason) then return true; end
		return true, "Target casting "..self.buffname;
	end
	if (self:CheckUnit("focus")) then
		if (not giveReason) then return true; end
		return true, "Focus casting "..self.buffname;
	end	

	--- Scan raid targets
	local numrm = GetNumRaidMembers();
	if numrm > 0 then
		for i=1, numrm do
			if (self:CheckUnit("raid"..i.."target")) then
				if (not giveReason) then return true; end
				return true, "Raid"..i.."Target casting "..self.buffname;
			end
		end
	else
	    -- Scan party targets
		local numpm = GetNumPartyMembers();
		if numpm > 0 then
			for i=1, numpm do
				if (self:CheckUnit("party"..i.."target")) then
					if (not giveReason) then return true; end
					return true, "Party"..i.."Target casting "..self.buffname;
				end
			end
		end
	end
	if (not giveReason) then return false; end
	return false, "Nobody's target casting "..self.buffname;
end
function cPowaSpellAlert:ShowTimerDurationSlider()
	return true;
end

cPowaStance = PowaClass(cPowaAura, {AuraType = "Stance"});
cPowaStance.OptionText={typeText=PowaAuras.Text.nomCheckStance};
cPowaStance.ShowOptions={["PowaDropDownStance"]=1};
cPowaStance.CheckBoxes={["PowaInverseButton"]=1,
					    ["PowaIsInRaidButton"]=1,
					    ["PowaRestingButton"]=1,
					    ["PowaIsMountedButton"]=1};
function cPowaStance:CheckIfShouldShow(giveReason)
	--PowaAuras:Debug("Check Stance");
	local nStance = GetShapeshiftForm(false);
	--PowaAuras:UnitTestDebug("nStance = "..tostring(nStance).." / self.stance = "..tostring(self.stance));
	if (nStance == self.stance and self.icon == "") then
		local icon = GetShapeshiftFormInfo(nStance);
		getglobal("PowaIconTexture"):SetTexture(icon);
		self.icon = getglobal("PowaIconTexture"):GetTexture();
	end
	if (nStance == self.stance)then
		if (not giveReason) then return true; end
		return true, "Stances match";
	end
	if (not giveReason) then return false; end
	return false, "Stances don't match";
end


-- Concrete Classes
PowaAuras.AuraClasses = {
	[PowaAuras.BuffTypes.Buff]=cPowaBuff,
	[PowaAuras.BuffTypes.Debuff]=cPowaDebuff,
	[PowaAuras.BuffTypes.TypeDebuff]=cPowaTypeDebuff,
	[PowaAuras.BuffTypes.AoE]=cPowaAoE,
	[PowaAuras.BuffTypes.Enchant]=cPowaEnchant,
	[PowaAuras.BuffTypes.Combo]=cPowaCombo,
	[PowaAuras.BuffTypes.ActionReady]=cPowaActionReady,
	[PowaAuras.BuffTypes.Health]=cPowaHealth,
	[PowaAuras.BuffTypes.Mana]=cPowaMana,
	[PowaAuras.BuffTypes.EnergyRagePower]=cPowaEnergyRagePower,
	[PowaAuras.BuffTypes.Aggro]=cPowaAggro,
	[PowaAuras.BuffTypes.PvP]=cPowaPvP,
	[PowaAuras.BuffTypes.SpellAlert]=cPowaSpellAlert,
	[PowaAuras.BuffTypes.Stance]=cPowaStance,
	[PowaAuras.BuffTypes.OwnSpell]=cPowaOwnSpell,
}

-- Instance concrete class based on type
function PowaAuras:AuraFactory(auraType, id, base)
	local class = self.AuraClasses[auraType];
	if (class) then
		--self:Message("AuraFactory "..tostring(auraType).." id="..tostring(id).." class="..tostring(class));
		if (base == nil) then
			base = {};
		end
		base.bufftype = auraType;
		return class(id, base);
	end
	self:Message("AuraFactory unknown "..tostring(auraType).." id="..tostring(id)); --OK
	return nil;
end
