--[[
	Stuff to track spell casting
	
	Main usage in SW Stats: Track mana efficiency of spells
	Might add more here
	
	Basic idea from:
	http://www.wowwiki.com/HOWTO:_Detecting_Instant_Cast_Spells
	
	approach for cancel, stop is different
	
	for ae we accept the spell at SPELLCAST_CHANNEL_START
	Stop messages for instant casts are never made pending, stop + instant = ok
	
	The idea of the "pending cast" is used because a fail message can come after a stop message for "normal" spells.
	
--]]

-- holds mana / spell info for cast by name
SW_CastByNameLookup = {};
-- holds mana / spell info for cast by name without rank
SW_CastByNameLookupMax = {};

--spells that are instant
SW_InstantLookup = {};

-- holds info until know if a spell failed
SW_PendingCast = {};
-- holds info of the spell to cast
SW_SelectedSpell = {};

local SW_ManaRegEx = string.gsub(MANA_COST, "%%d","(%%d+)");

function SW_GetManaCost(str)
	if str == nil then return nil; end
	local _,_, spellCost = string.find(str, SW_ManaRegEx);
	if spellCost == nil then return nil; end
	return tonumber(spellCost);
end

function SW_CalcManaUsage()
	local who = SW_S_Details[SW_SELF_STRING];
	if who == nil then return; end
	
	local perSpell = SW_S_SpellInfo[SW_SELF_STRING];
	if perSpell == nil then return; end
	
	local manaUsage = {0, 0, 0}; -- dmg, heal, total mana
	local manaUsed = 0;
	
	for k,v in pairs(perSpell) do
		if k ~= SW_DECURSEDUMMY then
			manaUsage[3] = manaUsage[3] + v[2];
			
			if who[k] ~= nil then
				manaUsed = v[2];
				if manaUsed > 0 then
					
					if who[k][1] > 0 then
						manaUsage[1] = manaUsage[1] + manaUsed;						
					end
					if who[k][2] > 0 then
						manaUsage[2] = manaUsage[2] + manaUsed;
					end
				end
			end	
		end
	end
	
	SW_S_ManaUsage[SW_SELF_STRING] = {manaUsage[1],manaUsage[2],manaUsage[3]}; -- dmg, heal, total.
	
	
end
function SW_AcceptPendingCast()
	--SW_printStr("SW_AcceptPendingCast");
	local spN = SW_PendingCast[1];
	if spN == nil then
		SW_PendingCast = {};
		return;
	end
	--SW_printStr(spN);
	--SW_printStr("-SW_AcceptPendingCast-"..spN);
	local updateMana = (SW_PendingCast[2] > 0);
	
	if SW_S_SpellInfo[SW_SELF_STRING] == nil then
		SW_S_SpellInfo[SW_SELF_STRING] = {};
	end
	if SW_S_SpellInfo[SW_SELF_STRING][spN] == nil then
		SW_S_SpellInfo[SW_SELF_STRING][spN] = {0,0};
	end
	spN = SW_S_SpellInfo[SW_SELF_STRING][spN];
	spN[1] = spN[1] + 1;
	spN[2] = spN[2] + SW_PendingCast[2];
	
	SW_PendingCast = {};
	
	-- only update this if mana was really used
	if updateMana then
		SW_CalcManaUsage();
	end
end
-- used in special cases see SPELLCAST_STOP in core.lua
function SW_AcceptSelectedCast()
	--SW_printStr("SW_AcceptSelectedCast");
	local spN = SW_SelectedSpell[1];
	if spN == nil then
		SW_SelectedSpell = {};
		return;
	end
	--SW_printStr(spN);
	--SW_printStr("-SW_AcceptSelectedCast-"..spN);
	local updateMana = (SW_SelectedSpell[2] > 0);
	
	if SW_S_SpellInfo[SW_SELF_STRING] == nil then
		SW_S_SpellInfo[SW_SELF_STRING] = {};
	end
	if SW_S_SpellInfo[SW_SELF_STRING][spN] == nil then
		SW_S_SpellInfo[SW_SELF_STRING][spN] = {0,0};
	end
	spN = SW_S_SpellInfo[SW_SELF_STRING][spN];
	spN[1] = spN[1] + 1;
	spN[2] = spN[2] + SW_SelectedSpell[2];
	
	SW_SelectedSpell = {};
	
	-- only update this if mana was really used
	if updateMana then
		SW_CalcManaUsage();
	end	
end
function SW_UpdateCastByNameLookup()
	local i = 1
	local spellCost;
	--SW_printStr("SW_CastByNameLookup rebuilt");
	SW_CastByNameLookup = {};
	SW_CastByNameLookupMax = {};
	SW_InstantLookup = {};
	SW_SpellHookTT:SetOwner(UIParent, "ANCHOR_NONE");

	while true do
		local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL)
		if not spellName then
			do break end
		end
		SW_SpellHookTT:SetSpell(i, BOOKTYPE_SPELL);
		if ( spellRank and (strlen(spellRank) > 0) ) then
			
			spellCost = SW_GetManaCost(SW_SpellHookTTTextLeft2:GetText());
			if spellCost == nil then
				SW_CastByNameLookup[ spellName .. '(' .. spellRank .. ')' ] = {spellName, spellRank, 0};
			else
				SW_CastByNameLookup[ spellName .. '(' .. spellRank .. ')' ] = {spellName, spellRank, spellCost};
			end
			
		else
			spellCost = SW_GetManaCost(SW_SpellHookTTTextLeft2:GetText());
			if spellCost == nil then
				SW_CastByNameLookup[ spellName ] = {spellName, nil, 0};
			else
				SW_CastByNameLookup[ spellName ] = {spellName, nil, spellCost};
			end
		end
		if SW_CastByNameLookupMax[spellName] == nil or spellCost > SW_CastByNameLookupMax[spellName] then
			SW_CastByNameLookupMax[spellName] = spellCost;
		end
		if (SPELL_CAST_TIME_INSTANT == SW_SpellHookTTTextLeft3:GetText()) then
			SW_InstantLookup[ spellName ] = true;
		end
		
		i = i + 1
	end
end


SWHook_oldCastSpell = CastSpell;
function SWHook_newCastSpell(spellId, spellbookTabNum)
	--SW_printStr("CastSpell");
	-- if we are casting something already, do normal stuff
	-- don't need to check .channeling a new cast abborts channeling
	if getglobal("CastingBarFrame").casting then
		SWHook_oldCastSpell(spellId, spellbookTabNum);
		return;
	end
	SW_SpellHookTT:SetOwner(UIParent, "ANCHOR_NONE");
	-- Load the tooltip with the spell information
	SW_SpellHookTT:SetSpell(spellId, spellbookTabNum);
	local spellName = SW_SpellHookTTTextLeft1:GetText();
	if spellName == nil then
		SWHook_oldCastSpell(spellId, spellbookTabNum);
		return;
	end
	
	local spellCost = SW_GetManaCost(SW_SpellHookTTTextLeft2:GetText());
	local instant = SW_InstantLookup[spellName];
	
	if spellCost == nil then
		SW_SelectedSpell = {spellName, 0, instant};
	else
		SW_SelectedSpell = {spellName, spellCost, instant};
	end
	SWHook_oldCastSpell(spellId, spellbookTabNum);
end
CastSpell = SWHook_newCastSpell;

--1.3.2 changed this to be wow 1.10 ready (onSelf will be added)
SWHook_oldCastSpellByName = CastSpellByName;
function SWHook_newCastSpellByName(spellName, onSelf)
	if getglobal("CastingBarFrame").casting then
		SWHook_oldCastSpellByName(spellName, onSelf)
		return;
	end
	
	local spell, spellCost;
	
	if SW_CastByNameLookup[spellName] ~= nil then
		spell = SW_CastByNameLookup[spellName][1];
		spellCost = SW_CastByNameLookup[spellName][3];
	elseif SW_CastByNameLookupMax[spellName] ~= nil then
		spell = spellName;
		spellCost = SW_CastByNameLookupMax[spellName];
	end
	local instant = SW_InstantLookup[spellName];
	-- can happen if we are using a macro of a spell we dont have
	if spell ~= nil and spellCost~= nil and spellCost > 0 then
		SW_SelectedSpell = {spell, spellCost, instant};
	end
	
	-- Call the original function
	SWHook_oldCastSpellByName(spellName, onSelf)

end
CastSpellByName = SWHook_newCastSpellByName;


SWHook_oldUseAction = UseAction

function SWHook_newUseAction(a1, a2, a3)
	--SW_printStr("Action");
	if getglobal("CastingBarFrame").casting then
		SWHook_oldUseAction(a1, a2, a3);
		return;
	end
	
	-- Call the original function
	SWHook_oldUseAction(a1, a2, a3);
	
	-- Test to see if this is a macro
	if GetActionText(a1) then 
		return ;
	end
	SW_SpellHookTT:SetOwner(UIParent, "ANCHOR_NONE");
	
	SW_SpellHookTT:SetAction(a1)
	
	-- need to lookup the info this way because the "enhanced tooltip" could be turned off.
	-- name and rank are always displayed. 
	local spellNRank = "";
	local spellCost;
	local spell = SW_SpellHookTTTextLeft1:GetText();
	if spell == nil then 
		return;
	end
	local instant = SW_InstantLookup[spell];
	local spellRank = SW_SpellHookTTTextRight1:GetText();
	if ( spellRank and (strlen(spellRank) > 0) ) then
		spellNRank = spell.."("..spellRank..")";
	else
		spellNRank = spell;
	end
	if SW_CastByNameLookup[spellNRank] ~= nil then
		spellCost = SW_CastByNameLookup[spellNRank][3];
	end
	
	if spellCost == nil then
		--SW_printStr(spellName);
		SW_SelectedSpell = {spell, 0, instant};
	else
		SW_SelectedSpell = {spell, spellCost, instant};
	end
end
UseAction = SWHook_newUseAction

--[[ usless same event order
SWHook_oldCastingBarFrame_OnEvent = CastingBarFrame_OnEvent
function SWHook_newCastingBarFrame_OnEvent()
	if ( event == "SPELLCAST_START" ) then
		SW_printStr("CBE_SPELLCAST_START");
	elseif ( event == "SPELLCAST_STOP" ) then
		SW_printStr("CBE_SPELLCAST_STOP");
	elseif ( event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" ) then
		SW_printStr("CBE_SPELLCAST_FAILED");
	elseif ( event == "SPELLCAST_DELAYED" ) then
		SW_printStr("CBE_SPELLCAST_DELAYED");
	elseif ( event == "SPELLCAST_CHANNEL_START" ) then
		SW_printStr("CBE_SPELLCAST_CHANNEL_START");
	elseif ( event == "SPELLCAST_CHANNEL_UPDATE" ) then
		SW_printStr("CBE_SPELLCAST_CHANNEL_UPDATE");
	end
	SWHook_oldCastingBarFrame_OnEvent();
end
CastingBarFrame_OnEvent = SWHook_newCastingBarFrame_OnEvent;
--]]
