vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
CCWatchDetails = {
        name = "CCWatch",
        version = CWATCH_VERSION,
        releaseDate = "March 27, 2006",
        author = "phoenixfire2001&elwen",
        website = "http://www.curse-gaming.com/mod.php?addid=3650",
        category = MYADDONS_CATEGORY_COMBAT,
        description = CCWATCH_DESCRIPTION,
        optionsframe = "CCWatchOptionsFrame"
};

CCWatchHelp = {
        "/ccw : affiche les commandes possibles\n"..
        "/ccw config : affiche l'interface graphique\n"..
        "\n"..
        ""
}

--CCWATCH_INITIALIZATION_EVENT = "SPELL_CHANGED"

CCWatchLoaded = false;

CCWatchObject = nil;

CCWATCH_MAXBARS = 5;

CCW_EWARN_FADED = 1;
CCW_EWARN_APPLIED = 2;
CCW_EWARN_BROKEN = 4;
CCW_EWARN_LOWTIME = 8;

--[[
local function DebugCompareStrings(str1, str2)
        local str = "";
        if str1 == str2 then
                test = str1.." == "..str2;
        else
                local str = "";
                local len = string.len(str1);
                if len > string.len(str2) then
                        len = string.len(str2);
                end
                local i;
                for i=1,len do
                        s1char = string.sub(str1, i, i);
                        s2char = string.sub(str1, i, i);
                        str = i.." : "..s1char.." ["..string.byte(s1char) .."] -> "..s2char.." ["..string.byte(s2char).."]";
                        if s1char ~= s2char then
                                str = str.." => DIFFERENT";
                        end
                        CCWatch_AddMessage(str);
                end
        end
end
--]]

function CCWatchWarn(msg, effect, target, time)
        local ncc = 0;
        local cc = CCWATCH.WARNTYPE;
        -- Emote, Say, Party, Raid, Yell, Custom:<ccname>
        if cc == "RAID" and UnitInRaid("player") == nil then
                cc = "PARTY";
        end
        if cc == "PARTY" and GetNumPartyMembers() == 0 then
                return;
        end
        if cc == "CHANNEL" then
                ncc = GetChannelName(CCWATCH.WARNCUSTOMCC);
        end
        if time ~= nil then
                msg = format(msg, target, effect, time);
        else
                msg = format(msg, target, effect);
        end
        if cc == "EMOTE" then
                msg = CCWATCH_WARN_EMOTE..msg;
        end
        SendChatMessage(msg, cc, nil, ncc);
end

function CCWatch_Config()
        CCWATCH.CCS = {}

        if CCWatch_ConfigCC ~= nil then
                CCWatch_ConfigCC();
        else
                CCWatch_AddMessage("No CC config");
        end
        if CCWatch_ConfigDebuff ~= nil then
                CCWatch_ConfigDebuff();
        else
                CCWatch_AddMessage("No Debuff config");
        end
        if CCWatch_ConfigBuff ~= nil then
                CCWatch_ConfigBuff();
        else
                CCWatch_AddMessage("No Buff config");
        end
end

function CCWatch_OnLoad()
        CCWatch_Globals();
        CCWatch_Config();

        CCWatchObject = this;

--      this:RegisterEvent(CCWATCH_INITIALIZATION_EVENT);
        this:RegisterEvent("UNIT_AURA");
        this:RegisterEvent("UNIT_COMBAT");

        if UnitLevel("player") < 60 then
                this:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN");
-- TODO : add this
--              this:RegisterEvent("CHAT_MSG_COMBAT_HONOR_GAIN");
        end
-- register this also for < 60 (pvp)
        this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILE_DEATH");

        this:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_OTHER");
        this:RegisterEvent("CHAT_MSG_SPELL_BREAK_AURA");

        this:RegisterEvent("SPELLCAST_START");
        this:RegisterEvent("SPELLCAST_STOP");
        this:RegisterEvent("SPELLCAST_FAILED");
        this:RegisterEvent("SPELLCAST_INTERRUPTED");

        this:RegisterEvent("PLAYER_TARGET_CHANGED");

        SLASH_CCWATCH1 = "/ccwatch";
        SLASH_CCWATCH2 = "/ccw";
        SlashCmdList["CCWATCH"] = function(msg)
                CCWatch_SlashCommandHandler(msg);
        end

        CCWatch_AddMessage(CCWATCH_FULLVERSION..CCWATCH_LOADED);
end

function CCWatch_BarUnlock()
        CCWATCH.STATUS = 2;
        CCWatchCC:EnableMouse(1);
        CCWatchDebuff:EnableMouse(1);
        CCWatchBuff:EnableMouse(1);

        local i;
        for i=1,CCWATCH_MAXBARS do
                getglobal("CCWatchBarCC"..i):Show();
                getglobal("CCWatchBarDebuff"..i):Show();
                getglobal("CCWatchBarBuff"..i):Show();
        end
end

function CCWatch_BarLock()
        CCWATCH.STATUS = 1;
        CCWatchCC:EnableMouse(0);
        CCWatchDebuff:EnableMouse(0);
        CCWatchBuff:EnableMouse(0);

        local i;
        for i=1,CCWATCH_MAXBARS do
                getglobal("CCWatchBarCC"..i):Hide();
                getglobal("CCWatchBarDebuff"..i):Hide();
                getglobal("CCWatchBarBuff"..i):Hide();
        end
end

function CCWatch_SlashCommandHandler(msg)
        if( msg ) then
                local command = string.lower(msg);
                if( command == "on" ) then
                        if( CCWATCH.STATUS == 0 ) then
                                CCWATCH.STATUS = 1;
                                CCWatch_Save[CCWATCH.PROFILE].status = CCWATCH.STATUS;
                                CCWatch_AddMessage(CCWATCH_ENABLED);
                        end
                elseif( command == "off" ) then
                        if( CCWATCH.STATUS ~= 0 ) then
                                CCWATCH.STATUS = 0;
                                CCWatch_Save[CCWATCH.PROFILE].status = CCWATCH.STATUS;
                                CCWatch_AddMessage(CCWATCH_DISABLED);
                        end
                elseif( command == "unlock" ) then
                        CCWatch_BarUnlock();
                        CCWatch_AddMessage(CCWATCH_UNLOCKED);
                        CCWatchOptionsFrameUnlock:SetChecked(true);
                elseif( command == "lock" ) then
                        CCWatch_BarLock();
                        CCWatch_AddMessage(CCWATCH_LOCKED);
                        CCWatchOptionsFrameUnlock:SetChecked(false);
                elseif( command == "invert" ) then
                        CCWATCH.INVERT = not CCWATCH.INVERT;
                        CCWatch_Save[CCWATCH.PROFILE].invert = CCWATCH.INVERT;
                        if CCWATCH.INVERT then
                                CCWatch_AddMessage(CCWATCH_INVERSION_ON);
                        else
                                CCWatch_AddMessage(CCWATCH_INVERSION_OFF);
                        end
                        CCWatchOptionsFrameInvert:SetChecked(CCWATCH.INVERT);
                elseif( command == "timers off" ) then
                        CCWatch_Save[CCWATCH.PROFILE].timers = 0;
                        CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers;
                        CCWatch_AddMessage(CCWATCH_TIMERS_OFF)
                        CCWatchTimersDropDownText:SetText(CCWATCH_OPTION_TIMERS_OFF);
                elseif( command == "timers on" ) then
                        CCWatch_Save[CCWATCH.PROFILE].timers = 1;
                        CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers;
                        CCWatch_AddMessage(CCWATCH_TIMERS_ON)
                        CCWatchTimersDropDownText:SetText(CCWATCH_OPTION_TIMERS_ON);
                elseif( command == "timers rev" ) then
                        CCWatch_Save[CCWATCH.PROFILE].timers = 2;
                        CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers;
                        CCWatch_AddMessage(CCWATCH_TIMERS_REVERSE)
                        CCWatchTimersDropDownText:SetText(CCWATCH_OPTION_TIMERS_REVERSE);
                elseif( command == "grow off" ) then
                        CCWatch_Save[CCWATCH.PROFILE].growth = 0;
                        CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth;
                        CCWatch_AddMessage(CCWATCH_GROW_OFF)
                        CCWatchGrowthDropDownText:SetText(CCWATCH_OPTION_GROWTH_OFF);
                elseif( command == "grow up" ) then
                        CCWatch_Save[CCWATCH.PROFILE].growth = 1;
                        CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth;
                        CCWatch_AddMessage(CCWATCH_GROW_UP)
                        CCWatchGrowthDropDownText:SetText(CCWATCH_OPTION_GROWTH_UP);
                elseif( command == "grow down" ) then
                        CCWatch_Save[CCWATCH.PROFILE].growth = 2;
                        CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth;
                        CCWatch_AddMessage(CCWATCH_GROW_DOWN)
                        CCWatchGrowthDropDownText:SetText(CCWATCH_OPTION_GROWTH_DOWN);
                elseif( command == "clear" ) then
                        CCWatch_Save[CCWATCH.PROFILE] = nil;
                        CCWatch_Globals();
                        CCWatch_Config();
                        CCWatch_LoadVariables();
                elseif( command == "u" ) then
                        CCWatch_Config();
                        CCWatch_LoadConfCCs();
                        CCWatch_LoadCustomCCs();
                        CCWatch_UpdateClassSpells(true);
                elseif( command == "config" ) then
                        CCWatchOptionsFrame:Show();
                elseif( string.sub(command, 1, 5) == "scale" ) then
                        local scale = tonumber(string.sub(command, 7))
                        if( scale <= 3.0 and scale >= 0.25 ) then
                                CCWatch_Save[CCWATCH.PROFILE].scale = scale;
                                CCWATCH.SCALE = scale;
                                CCWatchCC:SetScale(CCWATCH.SCALE);
                                CCWatchDebuff:SetScale(CCWATCH.SCALE);
                                CCWatchBuff:SetScale(CCWATCH.SCALE);
                                CCWatch_AddMessage(CCWATCH_SCALE..scale);
                                CCWatchSliderScale:SetValue(CCWATCH.SCALE);
                        else
                                CCWatch_Help()
                        end
                elseif( string.sub(command, 1, 5) == "width" ) then
                        local width = tonumber(string.sub(command, 7))
                        if( width <= 300 and width >= 50 ) then
                                CCWatch_Save[CCWATCH.PROFILE].width = width;
                                CCWATCH.WIDTH = width;
                                CCWatch_SetWidth(CCWATCH.WIDTH);
                                CCWatch_AddMessage(CCWATCH_WIDTH..width);
                                CCWatchSliderWidth:SetValue(CCWATCH.WIDTH);
                        else
                                CCWatch_Help()
                        end
                elseif( string.sub(command, 1, 5) == "alpha" ) then
                        local alpha = tonumber(string.sub(command, 7))
                        if( alpha <= 1 and alpha >= 0 ) then
                                CCWatch_Save[CCWATCH.PROFILE].alpha = alpha;
                                CCWATCH.ALPHA = alpha;
                                CCWatch_AddMessage(CCWATCH_ALPHA..alpha);
                                CCWatchSliderAlpha:SetValue(CCWATCH.ALPHA);
                        else
                                CCWatch_Help()
                        end
                elseif( command == "print" ) then
                        CCWatch_AddMessage(CCWATCH_PROFILE_TEXT..CCWATCH.PROFILE);
                        if( CCWATCH.STATUS == 0 ) then
                                CCWatch_AddMessage(CCWATCH_DISABLED);
                        elseif( CCWATCH.STATUS == 2 ) then
                                CCWatch_AddMessage(CCWATCH_UNLOCKED);
                        else
                                CCWatch_AddMessage(CCWATCH_ENABLED);
                        end
                        if CCWATCH.INVERT then
                                CCWatch_AddMessage(CCWATCH_INVERSION_ON);
                        else
                                CCWatch_AddMessage(CCWATCH_INVERSION_OFF);
                        end
                        if CCWATCH.TIMERS == 0 then
                                CCWatch_AddMessage(CCWATCH_TIMERS_OFF);
                        elseif CCWATCH.TIMERS == 1 then
                                CCWatch_AddMessage(CCWATCH_TIMERS_ON);
                        else
                                CCWatch_AddMessage(CCWATCH_TIMERS_REVERSE);
                        end
                        if CCWATCH.GROWTH == 0 then
                                CCWatch_AddMessage(CCWATCH_GROW_OFF);
                        elseif CCWATCH.GROWTH == 1 then
                                CCWatch_AddMessage(CCWATCH_GROW_UP);
                        else
                                CCWatch_AddMessage(CCWATCH_GROW_DOWN);
                        end
                        CCWatch_Config();
                        CCWatch_LoadConfCCs();
                        CCWatch_LoadCustomCCs();
                        CCWatch_UpdateClassSpells(true); -- Update at the same time

                        CCWatch_AddMessage(CCWATCH_SCALE..CCWATCH.SCALE);
                        CCWatch_AddMessage(CCWATCH_WIDTH..CCWATCH.WIDTH);
                        CCWatch_AddMessage(CCWATCH_ALPHA..CCWATCH.ALPHA);
                elseif( string.sub(command, 1, 6) == "warncc" ) then
                        local cc = string.sub(command, 8);
                        if cc ~= "EMOTE" or cc ~= "SAY" or cc ~= "PARTY" or cc ~= "RAID"
                                or cc ~= "YELL" or cc ~= "CHANNEL" then
                                CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC = cc;
                                CCWATCH.WARNCUSTOMCC = cc;
                                CCWatch_Save[CCWATCH.PROFILE].WarnType = "CHANNEL";
                                CCWatch_AddMessage(CCWATCH_WARNCC_CUSTOM..cc);
                        else
                                CCWatch_Save[CCWATCH.PROFILE].WarnType = cc;
                                CCWatch_AddMessage(CCWATCH_WARNCC_SETTO..cc);
                        end
                        CCWATCH.WARNTYPE = CCWatch_Save[CCWATCH.PROFILE].WarnType;
                elseif( command == "warn" ) then
                        if CCWATCH.WARNMSG then
                                CCWATCH.WARNMSG = 0;
                                CCWatch_AddMessage(CCWATCH_WARN_DISABLED);
                        else
                                CCWATCH.WARNMSG = bit.bor(CCW_EWARN_FADED, CCW_EWARN_APPLIED, CCW_EWARN_BROKEN, CCW_EWARN_LOWTIME);
                                CCWatch_AddMessage(CCWATCH_WARN_ENABLED);
                                UpdateWarnUIPage();
                        end
                        CCWatch_Save[CCWATCH.PROFILE].WarnMsg = CCWATCH.WARNMSG;
                else
                        CCWatch_Help();
                end
        end
end

function CCWatch_OnEvent(event)
--      if ( CCWATCH.STATUS == 0 and event ~= CCWATCH_INITIALIZATION_EVENT ) then
        if ( CCWATCH.STATUS == 0 ) then
                return
        end

        CCWatch_EventHandler[event](arg1, arg2, arg3, arg4, arg5);
end

CCWatch_EventHandler = {}

local SpellCast = nil;

--CCWatch_EventHandler[CCWATCH_INITIALIZATION_EVENT] = function()
--      if not CCWatchObject then
--              if(myAddOnsFrame_Register) then
--                      myAddOnsFrame_Register(CCWatchDetails, CCWatchHelp);
--              end
--              CCWatch_LoadVariables();
--      end
--end

CCWatch_EventHandler["SPELLCAST_START"] = function()
        SpellCast = arg1;
--      duration = arg2;        -- might wanna play with it to deduce the used rank
end

CCWatch_EventHandler["SPELLCAST_STOP"] = function()
        local effect;
        effect = SpellCast;
        local target = UnitName("target");
        if effect ~= nil and target ~= nil then
                if CCWATCH.CCS[effect] then
                        local group = CCWATCH.CCS[effect].GROUP;
                        local etype = CCWATCH.CCS[effect].ETYPE;
                        local index = 0;
                        -- find the effect in the queue, if it's not there index stays 0
                        if etype == ETYPE_BUFF then
                                table.foreach( CCWATCH.GROUPSBUFF[group].EFFECT, function(k,v) if( v == effect ) then index = k end end );
                        elseif etype == ETYPE_DEBUFF then
                                table.foreach( CCWATCH.GROUPSDEBUFF[group].EFFECT, function(k,v) if( v == effect ) then index = k end end );
                        else
                                table.foreach( CCWATCH.GROUPSCC[group].EFFECT, function(k,v) if( v == effect ) then index = k end end );
                        end

                        if( index ~= 0 ) then
-- Found the effect in a group, hence it is active, hence we are resetting it
                                CCWATCH.UNIT_AURA.TIME = GetTime();
                                CCWATCH.UNIT_AURA.TARGET = target;
                                CCWATCH.CCS[effect].TARGET = target;
                                local diff = CCWATCH.UNIT_AURA.TIME - CCWATCH.CCS[effect].TIMER_START;
                                CCWATCH.CCS[effect].TIMER_START = CCWATCH.CCS[effect].TIMER_START + diff;
                                CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_END + diff;
                        end
                end
        end
        SpellCast = nil;
end

CCWatch_EventHandler["SPELLCAST_FAILED"] = function()
        SpellCast = nil;
end

CCWatch_EventHandler["SPELLCAST_INTERRUPTED"] = function()
        SpellCast = nil;
end

CCWatch_EventHandler["UNIT_AURA"] = function()
        if( arg1 == "target") then
                CCWATCH.UNIT_AURA.TARGET = UnitName("target");
                CCWATCH.UNIT_AURA.TIME = GetTime();

                -- get rid of any old events so they don't clutter the queue
                while table.getn(CCWATCH.EFFECT) > 0 and (CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME) > CCWATCH.THRESHOLD do
                        CCWatch_UnqueueEvent();
                end

                if table.getn(CCWATCH.EFFECT) > 0 then
                        CCWatch_EffectHandler[CCWATCH.EFFECT[1].STATUS]();
                end
        end
end

CCWatch_EventHandler["PLAYER_TARGET_CHANGED"] = function()
        if not UnitCanAttack("player", "target") then
                return;
        end
        local index = 0;
        local target = UnitName("target");
-- 1. Check if current target is present in the list
        table.foreach( CCWATCH.LASTTARGETS, function(k,v) if( v.TARGET == target ) then index = k end end );
        local ltime = GetTime();
        if index == 0 then
-- 2. add it
                CCWatch_AddLastTarget(target, ltime);
        else
-- or update target time effect
                CCWATCH.LASTTARGETS[index].TIME = ltime;
        end
end

CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"] = function()
        local mobname;
        local effect;
        for mobname, effect in string.gfind( arg1, CCWATCH_TEXT_ON ) do
                if( CCWATCH.STYLE > 1 or CCWatch_CheckRecentTargets(mobname) ) then
                        if CCWATCH.CCS[effect] and CCWATCH.CCS[effect].MONITOR and bit.band(CCWATCH.CCS[effect].ETYPE, CCWATCH.MONITORING) ~= 0 then
                                CCWatch_QueueEvent(effect, mobname, GetTime(), 1)

                                CCWatch_EffectHandler[1]();
                        end
                end
        end
end

CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS"] = function()
        local mobname;
        local effect;
        for mobname, effect in string.gfind( arg1, CCWATCH_TEXT_BUFF_ON ) do
                if( CCWATCH.STYLE > 1 or CCWatch_CheckRecentTargets(mobname) ) then
                        if CCWATCH.CCS[effect] and CCWATCH.CCS[effect].MONITOR and bit.band(CCWATCH.CCS[effect].ETYPE, CCWATCH.MONITORING) ~=0 then
                                CCWatch_QueueEvent(effect, mobname, GetTime(), 1)

                                CCWatch_EffectHandler[1]();
                        end
                end
        end
end

CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"] = CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS"];
CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"] = CCWatch_EventHandler["CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"];

CCWatch_EventHandler["CHAT_MSG_SPELL_AURA_GONE_OTHER"] = function()
        local mobname;
        local effect;
        for effect, mobname in string.gfind( arg1, CCWATCH_TEXT_OFF ) do
                if CCWATCH.CCS[effect] then
                        if( CCWATCH.CCS[effect].TARGET == mobname ) then
                                CCWatch_QueueEvent(effect, mobname, GetTime(), 2)

                                CCWatch_EffectHandler[2]();
                        end
                end
        end
end

CCWatch_EventHandler["CHAT_MSG_SPELL_BREAK_AURA"] = function()
        local mobname;
        local effect;
        for mobname, effect in string.gfind( arg1, CCWATCH_TEXT_BREAK ) do
                if( CCWATCH.CCS[effect] ) then
                        if( CCWATCH.CCS[effect].TARGET == mobname ) then
                        CCWatch_QueueEvent(effect, mobname, GetTime(), 3)

                        CCWatch_EffectHandler[3]();
                        end
                end
        end
end

local DeadMob = "";
local function CCWHandleTargetDeath(k, v)
        if( v ) then
                if( v.TARGET == DeadMob ) then
--CCWatch_AddMessage("Removing effect "..k);
                        CCWATCH.CCS[k].TIMER_END = GetTime();
                        CCWatch_RemoveEffect(k, false);
                end
        end
end

CCWatch_EventHandler["CHAT_MSG_COMBAT_HOSTILE_DEATH"] = function()
        local mobname;
        for mobname in string.gfind( arg1, CCWATCH_TEXT_DIE ) do
-- for each effect (arg oO) check if target is current
                DeadMob = mobname;
                table.foreach(CCWATCH.CCS, CCWHandleTargetDeath);
        end
end

CCWatch_EventHandler["CHAT_MSG_COMBAT_XP_GAIN"] = function()
        local mobname;
        for mobname in string.gfind( arg1, CCWATCH_TEXT_DIEXP ) do
-- for each effect (arg oO) check if target is current
                DeadMob = mobname;
                table.foreach(CCWATCH.CCS, CCWHandleTargetDeath);
        end
end

CCWatch_EventHandler["UNIT_COMBAT"] = function()
        if( GetComboPoints() > 0 ) then
                CCWATCH.COMBO = GetComboPoints();
        end
end

CCWatch_EffectHandler = {}

CCWatch_EffectHandler[0] = function()
-- no effect

end

CCWatch_EffectHandler[1] = function()
-- applied
        if( CCWATCH.STYLE ~= 0 or math.abs( CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME ) < CCWATCH.THRESHOLD ) then
                local effect = CCWATCH.EFFECT[1].TYPE;
                local mobname = CCWATCH.EFFECT[1].TARGET;

                if( GetTime() > ( CCWATCH.CCS[effect].TIMER_END + 15 ) or mobname ~= CCWATCH.CCS[effect].TARGET ) then
-- quick & dirty hack for shared DR between Seduce & Fear)
                        if( effect == CCWATCH_FEAR or effect == CCWATCH_SEDUCE ) then
                                CCWATCH.CCS[CCWATCH_FEAR].DIMINISH = 1;
                                CCWATCH.CCS[CCWATCH_SEDUCE].DIMINISH = 1;
                        else
                                CCWATCH.CCS[effect].DIMINISH = 1;
                        end
                end

                CCWATCH.CCS[effect].TARGET = mobname;
                CCWATCH.CCS[effect].PLAYER = UnitIsPlayer("target");
                CCWATCH.CCS[effect].TIMER_START = GetTime();
                if( CCWATCH.CCS[effect].PVPCC and CCWATCH.CCS[effect].PLAYER ) then
                        CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_START + (CCWATCH.CCS[effect].PVPCC / CCWATCH.CCS[effect].DIMINISH);
                else
                        CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_START + (CCWATCH.CCS[effect].LENGTH / CCWATCH.CCS[effect].DIMINISH);
                end
                if( CCWATCH.CCS[effect].COMBO ) then
                        CCWATCH.CCS[effect].TIMER_END = CCWATCH.CCS[effect].TIMER_END + CCWATCH.CCS[effect].A * CCWATCH.COMBO;
                end

                CCWatch_AddEffect(effect);

                CCWatch_UnqueueEvent();
                if CCWATCH.CCS[effect].WARN > 0 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_APPLIED) then
                        CCWatchWarn(CCWATCH_WARN_APPLIED, effect, mobname);
                end
        end
end

CCWatch_EffectHandler[2] = function()
-- faded
        local effect = CCWATCH.EFFECT[1].TYPE;
        local target = CCWATCH.CCS[effect].TARGET;
        local bUnqueueDone = false;
        if( target == CCWATCH.EFFECT[1].TARGET ) then
        -- target and CC target names match, wait for UNIT_AURA to ensure target match
                if( CCWATCH.STYLE ~= 0 or math.abs( CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME ) < CCWATCH.THRESHOLD ) then
                        CCWATCH.CCS[effect].TIMER_END = GetTime();
                        CCWatch_RemoveEffect(effect, false);
                        CCWatch_UnqueueEvent();
                        bUnqueueDone = true;
        -- unless the debuff is gone from the target, then no need for UNIT_AURA to confirm it
                elseif CCWATCH.STYLE == 0 and CCWatch_EffectGone(effect) then
                        CCWATCH.CCS[effect].TIMER_END = GetTime()
                        CCWatch_RemoveEffect(effect, false);
                        CCWatch_UnqueueEvent();
                        bUnqueueDone = true;
                end
        else
        -- target and CC target names don't match, retargetting has occured, no need to wait for UNIT_AuRA
                CCWATCH.CCS[effect].TIMER_END = GetTime();
                CCWatch_RemoveEffect(effect, false);
                CCWatch_UnqueueEvent();
                bUnqueueDone = true;
        end

        -- another hack, to avoid spamming, because when the effect is broken, SOMETIME, WoW also send a faded message (see combat log)
        if bUnqueueDone and CCWATCH.CCS[effect].WARN > 0 and CCWATCH.CCS[effect].WARN ~= 3 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_FADED) then
                CCWatchWarn(CCWATCH_WARN_FADED, effect, target);
        end
end

CCWatch_EffectHandler[3] = function()
-- broken
        local effect = CCWATCH.EFFECT[1].TYPE;
        local target = CCWATCH.CCS[effect].TARGET;
        local bUnqueueDone = false;
        if( target == CCWATCH.EFFECT[1].TARGET ) then
        -- target and CC target names match, wait for UNIT_AURA to ensure target match
                if( CCWATCH.STYLE ~= 0 or math.abs( CCWATCH.UNIT_AURA.TIME - CCWATCH.EFFECT[1].TIME ) < CCWATCH.THRESHOLD ) then
                        CCWATCH.CCS[effect].TIMER_END = GetTime();
                        CCWatch_RemoveEffect(effect, false);
                        CCWatch_UnqueueEvent();
                        bUnqueueDone = true;
        -- unless the debuff is gone from the target, then no need for UNIT_AURA to confirm it
                elseif CCWATCH.STYLE == 0 and CCWatch_EffectGone(effect) then
                        CCWATCH.CCS[effect].TIMER_END = GetTime()
                        CCWatch_RemoveEffect(effect, false);
                        CCWatch_UnqueueEvent();
                        bUnqueueDone = true;
                end
        else
        -- target and CC target names don't match, retargetting has occured, no need to wait for UNIT_AuRA
                CCWATCH.CCS[effect].TIMER_END = GetTime();

                CCWatch_RemoveEffect(effect, false);
                CCWatch_UnqueueEvent();
                bUnqueueDone = true;
        end
        if bUnqueueDone and CCWATCH.CCS[effect].WARN > 0 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_BROKEN) then
                CCWatchWarn(CCWATCH_WARN_BROKEN, effect, target);
                CCWATCH.CCS[effect].WARN = 3;
        end
end


function CCWatch_QueueEvent(effect, mobname, time, status)
        local effect_structure = {}
        effect_structure.TYPE = effect;
        effect_structure.TARGET = mobname;
        effect_structure.TIME = time;
        effect_structure.STATUS = status
        table.insert( CCWATCH.EFFECT, effect_structure )
end

function CCWatch_UnqueueEvent()
        table.remove( CCWATCH.EFFECT, 1)
end

function CCWatch_EffectGone(effect)
        local i;
        local effectgone = false; -- assume effect is gone unless we find it
        for i = 1,16 do
                if UnitDebuff("target", i) == CCWATCH.CCS[effect].TEXTURE then
                        effectgone = true
                end
        end
        return effectgone;
end

function CCWatch_AddEffect(effect)
        -- first remove any old copies of this effect, to avoid nasty overlap and properly set diminishing returns for multi-CC
        local group = CCWATCH.CCS[effect].group
        local GROUPS;
        CCWatch_RemoveEffect(effect, true)

        if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then
                GROUPS = CCWATCH.GROUPSBUFF;
        elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then
                GROUPS = CCWATCH.GROUPSDEBUFF;
        else
                GROUPS = CCWATCH.GROUPSCC;
        end
        if CCWATCH.GROWTH == 1 then
                group = 1
                -- start at the bottom and find the first available bar, otherwise queue to #CCWATCH_MAXBARS
                while group < CCWATCH_MAXBARS and table.getn(GROUPS[group].EFFECT) > 0 do
                        group = group + 1
                end
                CCWATCH.CCS[effect].GROUP = group
        elseif CCWATCH.GROWTH == 2 then
                group = CCWATCH_MAXBARS
                -- start at the top and find the first available bar, otherwise queue to #1
                while group > 1 and table.getn(GROUPS[group].EFFECT) > 0 do
                        group = group - 1
                end
                CCWATCH.CCS[effect].GROUP = group
        end

        -- new effect goes at the head of the queue... always displaying newest effect
        CCWatch_QueueEffect(effect)
end

function CCWatch_RemoveEffect(effect, dr)
        local group = CCWATCH.CCS[effect].GROUP;
        local GROUPS;
        CCWatch_UnqueueEffect(effect);

        if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then
                GROUPS = CCWATCH.GROUPSBUFF;
        elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then
                GROUPS = CCWATCH.GROUPSDEBUFF;
        else
                GROUPS = CCWATCH.GROUPSCC;
        end

        if CCWATCH.GROWTH == 1 then
                while group < CCWATCH_MAXBARS and table.getn(GROUPS[group].EFFECT) == 0 and table.getn(GROUPS[group+1].EFFECT) > 0 do
                        local move_effect = GROUPS[group+1].EFFECT[1];
                        CCWatch_UnqueueEffect(move_effect);
                        CCWATCH.CCS[move_effect].GROUP = group
                        CCWatch_QueueEffect(move_effect);
                        group = group + 1
                end
        elseif CCWATCH.GROWTH == 2 then
                while group > 1 and table.getn(GROUPS[group].EFFECT) == 0 and table.getn(GROUPS[group-1].EFFECT) > 0 do
                        local move_effect = GROUPS[group-1].EFFECT[1];
                        CCWatch_UnqueueEffect(move_effect);
                        CCWATCH.CCS[move_effect].GROUP = group
                        CCWatch_QueueEffect(move_effect);
                        group = group - 1
                end
        end

        -- set diminishing returns based on CCS[effect].DIMINISHES (documented in CCWatch_ConfigXX.lua)
        if( dr and ((CCWATCH.CCS[effect].PLAYER and CCWATCH.CCS[effect].DIMINISHES > 0) or CCWATCH.CCS[effect].DIMINISHES == 1) ) then
-- quick & dirty hack for shared DR between Seduce & Fear)
                if( effect == CCWATCH_FEAR or effect == CCWATCH_SEDUCE ) then
                        CCWATCH.CCS[CCWATCH_FEAR].DIMINISH = 2 * CCWATCH.CCS[CCWATCH_FEAR].DIMINISH;
                        CCWATCH.CCS[CCWATCH_SEDUCE].DIMINISH = 2 * CCWATCH.CCS[CCWATCH_SEDUCE].DIMINISH;
                else
                        CCWATCH.CCS[effect].DIMINISH = 2 * CCWATCH.CCS[effect].DIMINISH;
                end
        end

        -- ensure if warnable, that WARN is set back to 1
        -- 2 = warn at low time already sent
        -- 3 = broken message seen so no faded message to send if any received
        if CCWATCH.CCS[effect].WARN > 0 then
                CCWATCH.CCS[effect].WARN = 1;
        end
end

function CCWatch_QueueEffect(effect)
        local group = CCWATCH.CCS[effect].GROUP;
        local GROUPS;
        local ext = "";

        if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then
                GROUPS = CCWATCH.GROUPSBUFF;
                ext = "Buff";
        elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then
                GROUPS = CCWATCH.GROUPSDEBUFF;
                ext = "Debuff";
        else
                GROUPS = CCWATCH.GROUPSCC;
                ext = "CC";
        end

        table.insert( GROUPS[group].EFFECT, 1, effect )

        local activebarText = getglobal("CCWatchBar"..ext..group.."Text");
        activebarText:SetText(effect..": "..CCWATCH.CCS[effect].TARGET);

        -- if queue was empty show bar
        if( table.getn(GROUPS[group].EFFECT) == 1 ) then
                local activebar = getglobal("CCWatchBar"..ext..group);
                activebar:Show();
                if CCWATCH.CCS[effect].COLOR then
                        getglobal("CCWatchBar"..ext..group.."StatusBar"):SetStatusBarColor(CCWATCH.CCS[effect].COLOR.r, CCWATCH.CCS[effect].COLOR.g, CCWATCH.CCS[effect].COLOR.b);
                end
        end
end

function CCWatch_UnqueueEffect(effect)
        local group = CCWATCH.CCS[effect].GROUP;
        local GROUPS;
        local ext = "";

        if CCWATCH.CCS[effect].ETYPE == ETYPE_BUFF then
                GROUPS = CCWATCH.GROUPSBUFF;
                ext = "Buff";
        elseif CCWATCH.CCS[effect].ETYPE == ETYPE_DEBUFF then
                GROUPS = CCWATCH.GROUPSDEBUFF;
                ext = "Debuff";
        else
                GROUPS = CCWATCH.GROUPSCC;
                ext = "CC";
        end

        local index = 0;
        -- find the effect in the queue, if it's not there index stays 0
        table.foreach( GROUPS[group].EFFECT, function(k,v) if( v == effect ) then index = k end end );
        if( index ~= 0 ) then
--              CCWATCH.CCS[GROUPS[group].EFFECT[index]].TARGET = ""; -- resetting target for mob death removal
-- commented because of conflict with DR requiring to keep the target name.
-- the name resetting was an unneeded attempt to avoid extra unqueue
                table.remove( GROUPS[group].EFFECT, index );
        end

        -- if queue isn't empty set new name
        if( table.getn(GROUPS[group].EFFECT) > 0 ) then
                local activebarText = getglobal("CCWatchBar"..ext..group.."Text");
                local effect = GROUPS[group].EFFECT[1];
                activebarText:SetText(effect..": "..CCWATCH.CCS[effect].TARGET);
        else
                local activebarText = getglobal("CCWatchBar"..ext..group.."Text");
                activebarText:SetText("CCWatch "..ext.." Bar "..group);
        end
end

function CCWatchBarCC_OnShow(group)
        CCWatchBar_OnShow(group, CCWATCH.GROUPSCC, "CC");
end

function CCWatchBarDebuff_OnShow(group)
        CCWatchBar_OnShow(group, CCWATCH.GROUPSDEBUFF, "Debuff");
end

function CCWatchBarBuff_OnShow(group)
        CCWatchBar_OnShow(group, CCWATCH.GROUPSBUFF, "Buff");
end

function CCWatchBar_OnShow(group, GROUPS, ext)
        local barname = "CCWatch"..ext;
        getglobal(barname):SetScale(CCWATCH.SCALE);

--      local status = GetTime();

        barname = "CCWatchBar"..ext..group;
        local activebar = getglobal(barname);
        activebar:SetBackdropColor(0, 0, 0, 0.35);
        activebar:SetAlpha(CCWATCH.ALPHA);

        getglobal(barname.."StatusBar"):SetStatusBarColor(CCWATCH.COTNORMALCOLOR.r, CCWATCH.COTNORMALCOLOR.g, CCWATCH.COTNORMALCOLOR.b);
        if( table.getn(GROUPS[group].EFFECT) == 0 ) then
                getglobal(barname.."Text"):SetText("CCWatch Bar "..ext.." "..group);
        end

        getglobal(barname.."StatusBarSpark"):SetPoint("CENTER", barname.."StatusBar", "LEFT", 0, 0);
end


function CCWatchBarCC1_OnShow() CCWatchBarCC_OnShow(1) end
function CCWatchBarCC2_OnShow() CCWatchBarCC_OnShow(2) end
function CCWatchBarCC3_OnShow() CCWatchBarCC_OnShow(3) end
function CCWatchBarCC4_OnShow() CCWatchBarCC_OnShow(4) end
function CCWatchBarCC5_OnShow() CCWatchBarCC_OnShow(5) end

function CCWatchBarDebuff1_OnShow() CCWatchBarDebuff_OnShow(1) end
function CCWatchBarDebuff2_OnShow() CCWatchBarDebuff_OnShow(2) end
function CCWatchBarDebuff3_OnShow() CCWatchBarDebuff_OnShow(3) end
function CCWatchBarDebuff4_OnShow() CCWatchBarDebuff_OnShow(4) end
function CCWatchBarDebuff5_OnShow() CCWatchBarDebuff_OnShow(5) end

function CCWatchBarBuff1_OnShow() CCWatchBarBuff_OnShow(1) end
function CCWatchBarBuff2_OnShow() CCWatchBarBuff_OnShow(2) end
function CCWatchBarBuff3_OnShow() CCWatchBarBuff_OnShow(3) end
function CCWatchBarBuff4_OnShow() CCWatchBarBuff_OnShow(4) end
function CCWatchBarBuff5_OnShow() CCWatchBarBuff_OnShow(5) end

function CCWatch_OnUpdate()
        if( CCWATCH.STATUS == 0 ) then
                return
        end

--      local status = GetTime();
        table.foreach( CCWATCH.GROUPSCC, CCWatch_GroupCCUpdate );
        table.foreach( CCWATCH.GROUPSDEBUFF, CCWatch_GroupDebuffUpdate );
        table.foreach( CCWATCH.GROUPSBUFF, CCWatch_GroupBuffUpdate );
end

function CCWatch_GroupCCUpdate(group)
        CCWatch_GroupUpdate(group, CCWATCH.GROUPSCC, "CC");
end

function CCWatch_GroupDebuffUpdate(group)
        CCWatch_GroupUpdate(group, CCWATCH.GROUPSDEBUFF, "Debuff");
end

function CCWatch_GroupBuffUpdate(group)
        CCWatch_GroupUpdate(group, CCWATCH.GROUPSBUFF, "Buff");
end

local function ComputeColor(colorhigh, colorlow, high, low, cur)
        local factor = (cur - low) / (high - low);
-- should be divided by 2, but would lead to too dark cases
        return  (colorhigh.r*factor + colorlow.r*(1-factor)),
                (colorhigh.g*factor + colorlow.g*(1-factor)),
                (colorhigh.b*factor + colorlow.b*(1-factor));
end

local function GetTheRightColorFromTime(curTime)
        if curTime > 2 * CCWATCH.COTLOWVALUE then
                return CCWATCH.COTNORMALCOLOR.r, CCWATCH.COTNORMALCOLOR.g, CCWATCH.COTNORMALCOLOR.b;
        elseif curTime > CCWATCH.COTLOWVALUE then
                return ComputeColor(CCWATCH.COTNORMALCOLOR, CCWATCH.COTLOWCOLOR, 2*CCWATCH.COTLOWVALUE, CCWATCH.COTLOWVALUE, curTime);
        elseif curTime > CCWATCH.COTURGEVALUE then
                return ComputeColor(CCWATCH.COTLOWCOLOR, CCWATCH.COTURGECOLOR, CCWATCH.COTLOWVALUE, CCWATCH.COTURGEVALUE, curTime);
        else
                return CCWATCH.COTURGECOLOR.r, CCWATCH.COTURGECOLOR.g, CCWATCH.COTURGECOLOR.b;
        end
end

function CCWatch_GroupUpdate(group, GROUPS, ext)
        local activebar = getglobal("CCWatchBar"..ext..group)

        if( table.getn(GROUPS[group].EFFECT) > 0 ) then
        -- active effect on this bar
                activebar:SetAlpha(CCWATCH.ALPHA);

                local status = GetTime();
                local effect = GROUPS[group].EFFECT[1]
                local activebarStatusBar = getglobal("CCWatchBar"..ext..group.."StatusBar");
                local activebarTextBar = getglobal("CCWatchBar"..ext..group.."StatusBarText");
                local str = "";

                if( status <= CCWATCH.CCS[effect].TIMER_END  ) then
                -- CC hasn't expired
                        activebarStatusBar:SetMinMaxValues(CCWATCH.CCS[effect].TIMER_START, CCWATCH.CCS[effect].TIMER_END);
                        local sparkPosition = ((status - CCWATCH.CCS[effect].TIMER_START) / (CCWATCH.CCS[effect].TIMER_END - CCWATCH.CCS[effect].TIMER_START)) * CCWATCH.WIDTH;
                        if( CCWATCH.INVERT ) then
                                sparkPosition = CCWATCH.WIDTH - sparkPosition;
                                activebarStatusBar:SetValue(CCWATCH.CCS[effect].TIMER_START + CCWATCH.CCS[effect].TIMER_END - status);
                        else
                                activebarStatusBar:SetValue(status);
                        end
                        local elapsedTime = CCWATCH.CCS[effect].TIMER_END - status;
                        if( sparkPosition < 1 ) then
                                sparkPosition = 1;
                        end
                        local activebarSpark = getglobal("CCWatchBar"..ext..group.."StatusBarSpark");
                        activebarSpark:SetPoint("CENTER", "CCWatchBar"..ext..group.."StatusBar", "LEFT", sparkPosition, 0);
                        if CCWATCH.TIMERS == 1 then
                                str = format("%.2f", status - CCWATCH.CCS[effect].TIMER_START);
                        elseif CCWATCH.TIMERS == 2 then
                                str = format("%.2f", elapsedTime);
                        end
                        activebarTextBar:SetText(str);
                        if CCWATCH.COLOROVERTIME and not CCWATCH.CCS[effect].COLOR then
                                local r, g, b = GetTheRightColorFromTime(elapsedTime);
                                activebarStatusBar:SetStatusBarColor(r, g, b);
                        end

                        if CCWATCH.CCS[effect].WARN > 0 and bit.band(CCWATCH.WARNMSG, CCW_EWARN_LOWTIME) then
                                if CCWATCH.CCS[effect].TIMER_END - CCWATCH.CCS[effect].TIMER_START > CCWATCH.WARNLOW and CCWATCH.WARNLOW > elapsedTime then
                                        if CCWATCH.CCS[effect].WARN == 1 then 
                                                CCWatchWarn(CCWATCH_WARN_LOWTIME, effect, CCWATCH.CCS[effect].TARGET, CCWATCH.WARNLOW);
                                                CCWATCH.CCS[effect].WARN = 2;
                                        end
                                elseif CCWATCH.CCS[effect].WARN == 2 then -- reset if ever disconnected while fighting
                                        CCWATCH.CCS[effect].WARN = 1;
                                end
                        end
                elseif status > CCWATCH.CCS[effect].TIMER_END + 0.2 then
                -- CC has expired. Try to leave room for a fade effect to be catched, then remove anyway
                        CCWatch_RemoveEffect(effect, false)
                end

        elseif( activebar:GetAlpha() > 0 ) then
        -- otherwise fade out this bar if not unlocked
                if( CCWATCH.STATUS == 1 ) then
                        local activebarText = getglobal("CCWatchBar"..ext..group.."Text");
                        activebarText:SetText("TimeOut");
                        local alpha = activebar:GetAlpha() - 0.2;
                        if( alpha > 0 ) then
                                activebar:SetAlpha(alpha);
                        else
                                activebar:Hide();
                        end
                end
        else
        -- done fading, hide this bar
                activebar:Hide();
        end
end

local function GetConfCC(k, v)
--CCWatch_AddMessage("Updating conf for : "..k);
        if CCWATCH.CCS[k] then
                CCWATCH.CCS[k].MONITOR = v.MONITOR;
                CCWATCH.CCS[k].WARN = v.WARN;
                CCWATCH.CCS[k].COLOR = v.COLOR;
        end
end

local function GetSavedCC(k, v)
        if v == nil then
--CCWatch_AddMessage("Removing "..k);
                CCWATCH.CCS[k] = nil;
                return;
        end
        if v.GROUP == nil or v.ETYPE == nil or v.LENGTH == nil or v.DIMINISHES == nil then
                CCWATCH.CCS[k] = nil;
                return;
        end
--CCWatch_AddMessage("Adding "..k.." ("..type(k)..")");
        CCWATCH.CCS[k] = {
                GROUP = v.GROUP,
                ETYPE = v.ETYPE,
                LENGTH = v.LENGTH,
                DIMINISHES = v.DIMINISHES,
                WARN = v.WARN,
                COLOR = v.COLOR,

                TARGET = "",
                PLAYER = nil,
                TIMER_START = 0,
                TIMER_END = 0,
                DIMINISH = 1,
                MONITOR = true
        }
end


function CCWatch_LoadConfCCs()
-- update array with CC conf
        table.foreach(CCWatch_Save[CCWATCH.PROFILE].ConfCC, GetConfCC);
end

function CCWatch_LoadCustomCCs()
-- update array with saved CCs
        table.foreach(CCWatch_Save[CCWATCH.PROFILE].SavedCC, GetSavedCC);
end

function CCWatch_LoadVariablesOnUpdate(arg1)
        if not CCWATCH.LOADEDVARIABLES then
                if(myAddOnsFrame_Register) then
                        myAddOnsFrame_Register(CCWatchDetails, CCWatchHelp);
                end
                CCWatch_LoadVariables();
                CCWATCH.LOADEDVARIABLES = true;
        end
end

function CCWatch_LoadVariables()
        CCWATCH.PROFILE = UnitName("player").." of "..GetCVar("RealmName");

        if CCWatch_Save[CCWATCH.PROFILE] == nil then
                CCWatch_Save[CCWATCH.PROFILE] = {};
        end

        if CCWatch_Save[CCWATCH.PROFILE].SavedCC == nil then
                CCWatch_Save[CCWATCH.PROFILE].SavedCC = {};
        end

        if CCWatch_Save[CCWATCH.PROFILE].ConfCC == nil then
                CCWatch_Save[CCWATCH.PROFILE].ConfCC = {};
        end

        if CCWatch_Save[CCWATCH.PROFILE].status == nil then
                CCWatch_Save[CCWATCH.PROFILE].status = CCWATCH.STATUS;
        end

        if CCWatch_Save[CCWATCH.PROFILE].invert == nil then
                CCWatch_Save[CCWATCH.PROFILE].invert = false;
        end

        if CCWatch_Save[CCWATCH.PROFILE].growth == nil then
                CCWatch_Save[CCWATCH.PROFILE].growth = 0;
        end

        if CCWatch_Save[CCWATCH.PROFILE].scale == nil then
                CCWatch_Save[CCWATCH.PROFILE].scale = 1;
        end

        if CCWatch_Save[CCWATCH.PROFILE].width == nil then
                CCWatch_Save[CCWATCH.PROFILE].width = 160;
        end

        if CCWatch_Save[CCWATCH.PROFILE].alpha == nil then
                CCWatch_Save[CCWATCH.PROFILE].alpha = 1;
        end

        if CCWatch_Save[CCWATCH.PROFILE].arcanist == nil then
                CCWatch_Save[CCWATCH.PROFILE].arcanist = false;
        end

        if CCWatch_Save[CCWATCH.PROFILE].timers == nil then
                CCWatch_Save[CCWATCH.PROFILE].timers = 1;
        end

        if CCWatch_Save[CCWATCH.PROFILE].style == nil then
                CCWatch_Save[CCWATCH.PROFILE].style = 0;
        end

        if CCWatch_Save[CCWATCH.PROFILE].Monitoring == nil then
                CCWatch_Save[CCWATCH.PROFILE].Monitoring = bit.bor(ETYPE_CC, ETYPE_DEBUFF, ETYPE_BUFF);
        end

        if CCWatch_Save[CCWATCH.PROFILE].WarnType == nil then
                CCWatch_Save[CCWATCH.PROFILE].WarnType = "PARTY";
        end

        if CCWatch_Save[CCWATCH.PROFILE].WarnLow == nil then
                CCWatch_Save[CCWATCH.PROFILE].WarnLow = 10;
        end

        if CCWatch_Save[CCWATCH.PROFILE].WarnMsg == nil then
                CCWatch_Save[CCWATCH.PROFILE].WarnMsg = bit.bor(CCW_EWARN_FADED, CCW_EWARN_APPLIED, CCW_EWARN_BROKEN, CCW_EWARN_LOWTIME);
        end

        if CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC == nil then
                CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC = "";
        end

        if CCWatch_Save[CCWATCH.PROFILE].ColorOverTime == nil then
                CCWatch_Save[CCWATCH.PROFILE].ColorOverTime = false;
        end

        if CCWatch_Save[CCWATCH.PROFILE].CoTUrgeColor == nil then
                CCWatch_Save[CCWATCH.PROFILE].CoTUrgeColor = { r=1, g=0, b=0 };
        end

        if CCWatch_Save[CCWATCH.PROFILE].CoTLowColor == nil then
                CCWatch_Save[CCWATCH.PROFILE].CoTLowColor = { r=1, g=0.5, b=0 };
        end

        if CCWatch_Save[CCWATCH.PROFILE].CoTNormalColor == nil then
                CCWatch_Save[CCWATCH.PROFILE].CoTNormalColor = { r=1, g=1, b=0 };
        end

        if CCWatch_Save[CCWATCH.PROFILE].CoTUrgeValue == nil then
                CCWatch_Save[CCWATCH.PROFILE].CoTUrgeValue = 1;
        end

        if CCWatch_Save[CCWATCH.PROFILE].CoTLowValue == nil then
                CCWatch_Save[CCWATCH.PROFILE].CoTLowValue = 5;
        end

        if CCWatch_Save[CCWATCH.PROFILE].LeadingTimer == nil then
                CCWatch_Save[CCWATCH.PROFILE].LeadingTimer = true;
        end

        CCWATCH.ARCANIST = CCWatch_Save[CCWATCH.PROFILE].arcanist;

        CCWatch_LoadConfCCs();
        CCWatch_LoadCustomCCs();
        CCWatch_UpdateTextures();
--      CCWatch_UpdateClassSpells(false);
        CCWatch_UpdateClassSpells(true);

        CCWATCH.STATUS = CCWatch_Save[CCWATCH.PROFILE].status;
        CCWATCH.INVERT = CCWatch_Save[CCWATCH.PROFILE].invert;
        CCWATCH.TIMERS = CCWatch_Save[CCWATCH.PROFILE].timers;
        CCWATCH.GROWTH = CCWatch_Save[CCWATCH.PROFILE].growth;
        CCWATCH.SCALE = CCWatch_Save[CCWATCH.PROFILE].scale;
        CCWATCH.WIDTH = CCWatch_Save[CCWATCH.PROFILE].width;
        CCWATCH.ALPHA = CCWatch_Save[CCWATCH.PROFILE].alpha;

        CCWATCH.MONITORING = CCWatch_Save[CCWATCH.PROFILE].Monitoring;
        CCWATCH.WARNTYPE = CCWatch_Save[CCWATCH.PROFILE].WarnType;
        CCWATCH.WARNLOW = CCWatch_Save[CCWATCH.PROFILE].WarnLow;
        CCWATCH.WARNMSG = CCWatch_Save[CCWATCH.PROFILE].WarnMsg;
        CCWATCH.WARNCUSTOMCC = CCWatch_Save[CCWATCH.PROFILE].WarnCustomCC;
        CCWATCH.COLOROVERTIME = CCWatch_Save[CCWATCH.PROFILE].ColorOverTime;
        CCWATCH.COTURGECOLOR = CCWatch_Save[CCWATCH.PROFILE].CoTUrgeColor;
        CCWATCH.COTLOWCOLOR = CCWatch_Save[CCWATCH.PROFILE].CoTLowColor;
        CCWATCH.COTNORMALCOLOR = CCWatch_Save[CCWATCH.PROFILE].CoTNormalColor;
        CCWATCH.COTURGEVALUE = CCWatch_Save[CCWATCH.PROFILE].CoTUrgeValue;
        CCWATCH.COTLOWVALUE = CCWatch_Save[CCWATCH.PROFILE].CoTLowValue;

        CCWATCH.LEADINGTIMER = CCWatch_Save[CCWATCH.PROFILE].LeadingTimer;
        CCWatch_SetLeadingTimer(CCWATCH.LEADINGTIMER);

        if bit.band(CCWATCH.MONITORING, ETYPE_CC) ~= 0 or bit.band(CCWATCH.MONITORING, ETYPE_DEBUFF) ~= 0 then
                CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE");
                CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE");
        end
        if bit.band(CCWATCH.MONITORING, ETYPE_BUFF) ~= 0 then
                CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS");
                CCWatchObject:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS");
        end

        CCWATCH.STYLE = CCWatch_Save[CCWATCH.PROFILE].style;

        CCWatchCC:SetScale(CCWATCH.SCALE);
        CCWatchDebuff:SetScale(CCWATCH.SCALE);
        CCWatchBuff:SetScale(CCWATCH.SCALE);
        CCWatch_SetWidth(CCWATCH.WIDTH);

        if( CCWATCH.STATUS == 2 ) then
                CCWatch_BarUnlock();
        end

        CCWatchOptions_Init();

        CCWatch_BarLock();

-- Pure cosmetic for Unlock move
        local i;
        for i=1,CCWATCH_MAXBARS do
                getglobal("CCWatchBarCC"..i.."StatusBarText"):SetText("0.00");
                getglobal("CCWatchBarDebuff"..i.."StatusBarText"):SetText("0.00");
                getglobal("CCWatchBarBuff"..i.."StatusBarText"):SetText("0.00");
        end
end

function CCWatch_SetLeadingTimer(bLeading)
        local point;
        local relpoint;
        if bLeading then
                point = "RIGHT";
                relpoint = "LEFT";
        else
                point = "LEFT";
                relpoint = "RIGHT";
        end
        
        local i;
        local bar;
        for i=1,CCWATCH_MAXBARS do
                bar = getglobal("CCWatchBarCC"..i.."StatusBarText");
                bar:ClearAllPoints();
                bar:SetPoint(point, getglobal("CCWatchBarCC"..i.."StatusBar"), relpoint);

                bar = getglobal("CCWatchBarDebuff"..i.."StatusBarText");
                bar:ClearAllPoints();
                bar:SetPoint(point, getglobal("CCWatchBarDebuff"..i.."StatusBar"), relpoint);

                bar = getglobal("CCWatchBarBuff"..i.."StatusBarText");
                bar:ClearAllPoints();
                bar:SetPoint(point, getglobal("CCWatchBarBuff"..i.."StatusBar"), relpoint);
        end
end


function CCWatch_UpdateTextures()
        local i = 1
        while true do
                local name, rank = GetSpellName(i, BOOKTYPE_SPELL)
                if not name then return end
                if CCWATCH.CCS[name] then
                        CCWATCH.CCS[name].TEXTURE = GetSpellTexture(i, BOOKTYPE_SPELL)
                elseif CCWATCH_SPELLS[name] then
                        if CCWATCH_SPELLS[name].EFFECTNAME then
                                CCWATCH.CCS[CCWATCH_SPELLS[name].EFFECTNAME].TEXTURE = GetSpellTexture(i, BOOKTYPE_SPELL);
                        else
                                CCWatch_AddMessage("Warning : ranked spell '"..name.."' has a different name from its effect, but no effect name in its definition.");
                        end
                end
                i = i + 1
        end
end

function CCWatch_UpdateImpGouge(bPrint)
        local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 2, 1 );
        if texture then
                if bPrint then
                        CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                end
                if rank ~= 0 then
                        CCWATCH.CCS[CCWATCH_GOUGE].LENGTH = 4 + rank * 0.5;
                end
        elseif CCWATCH.CCS[CCWATCH_GOUGE].LENGTH == nil then
                CCWATCH.CCS[CCWATCH_GOUGE].LENGTH = 4;
        end
end

function CCWatch_UpdateImpGarotte(bPrint)
        local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 8 );
        if texture then
                if bPrint then
                        CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                end
                if rank ~= 0 then
                        CCWATCH.CCS[CCWATCH_GAROTTE].LENGTH = 18 + rank * 3;
                end
        elseif CCWATCH.CCS[CCWATCH_GAROTTE].LENGTH == nil then
                CCWATCH.CCS[CCWATCH_GAROTTE].LENGTH = 18;
        end
end

function CCWatch_UpdateKidneyShot(bPrint)
        local i = 1
        while true do
                local name, rank = GetSpellName(i, BOOKTYPE_SPELL)
                if not name then
                        if( CCWATCH.CCS[CCWATCH_KS].LENGTH == nil ) then
                                CCWATCH.CCS[CCWATCH_KS].LENGTH = 1;
                        end
                        return
                end

                if( name == CCWATCH_KS ) then
                        if bPrint then
                                CCWatch_AddMessage(name.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                        end
                        if( string.sub(rank,string.len(rank)) == "1" ) then
                                CCWATCH.CCS[CCWATCH_KS].LENGTH = 0;
                        else
                                CCWATCH.CCS[CCWATCH_KS].LENGTH = 1;
                        end
                        return
                end

                i = i + 1
        end
end

function CCWatch_UpdateImpTrap(bPrint)
        local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 7 );
        if texture then
                if bPrint then
                        CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                end
                if rank ~= 0 then
-- Freezing Trap is a true multi rank, hence already updated
                        CCWATCH.CCS[CCWATCH_FREEZINGTRAP].LENGTH = CCWATCH.CCS[CCWATCH_FREEZINGTRAP].LENGTH * (1 + rank * 0.15);
                end
        end
end


function CCWatch_UpdateImpSeduce(bPrint)
        local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 2, 7 );
        if texture then
                if bPrint then
                        CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                end
                if rank ~= 0 then
                        CCWATCH.CCS[CCWATCH_SEDUCE].LENGTH = 15 * (1 + rank * 0.10);
                end
        end
end


function CCWatch_UpdateBrutalImpact(bPrint)
        local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 2, 4 );
        if texture then
                if bPrint then
                        CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                end
                if rank ~= 0 then
-- Bash is a true multi rank, hence already updated
                        CCWATCH.CCS[CCWATCH_POUNCE].LENGTH = 2 + rank * 0.50;
                        CCWATCH.CCS[CCWATCH_BASH].LENGTH = CCWATCH.CCS[CCWATCH_BASH].LENGTH + rank * 0.50;
                end
        end
end


function CCWatch_UpdatePermafrost(bPrint)
        local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 2 );
        if texture then
                if bPrint then
                        CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                end
                if rank ~= 0 then
-- Frostbolt is a true multi rank, hence already updated
                        CCWATCH.CCS[CCWATCH_CONEOFCOLD].LENGTH = 8 + 0.50 + rank * 0.50;
                        CCWATCH.CCS[CCWATCH_FROSTBOLT].LENGTH = CCWATCH.CCS[CCWATCH_FROSTBOLT].LENGTH + 0.50 + rank * 0.50;
                end
        end
end

function CCWatch_UpdateImpShadowWordPain(bPrint)
        local talentname, texture, _, _, rank, _, _, _ = GetTalentInfo( 3, 4 );
        if texture then
                if bPrint then
                        CCWatch_AddMessage(talentname.." "..CCWATCH_RANK.." "..rank.." "..CCWATCH_DETECTED);
                end
                if rank ~= 0 then
                        CCWATCH.CCS[CCWATCH_SHADOWWORDPAIN].LENGTH = 18 + rank * 3;
                end
        end
end


function CCWatch_GetSpellRank(spellname, spelleffect, bPrint)
        local i = 1;
        local gotone = false;
        local maxrank = CCWATCH_SPELLS[spellname].RANKS;

        while true do
                local name, rank = GetSpellName(i, BOOKTYPE_SPELL)

                if not name then
                        if not gotone then
                                if bPrint then
                                        CCWatch_AddMessage(spellname.." "..CCWATCH_NOTDETECTED);
                                end
                                if( CCWATCH.CCS[spelleffect].LENGTH == nil ) then
                                        CCWATCH.CCS[spelleffect].LENGTH = CCWATCH_SPELLS[spellname].DURATION[maxrank];
                                end
                        end
                        return;
                end

                if( name == spellname ) then
                        local currank = 1;
                        while currank <= maxrank do
                                if( tonumber(string.sub(rank,string.len(rank))) == currank) then
                                        if bPrint then
                                                CCWatch_AddMessage(spellname.." "..CCWATCH_RANK.." "..currank.." "..CCWATCH_DETECTED);
                                        end

                                        CCWATCH.CCS[spelleffect].LENGTH = CCWATCH_SPELLS[spellname].DURATION[currank];
                                        gotone = true;
                                end
                                currank = currank + 1;
                        end
                end

                i = i + 1
        end
end

function CCWatch_UpdateClassSpells(bPrint)
        local _, eclass = UnitClass("player");
        CCWatchOptionsFrameArcanist:Hide();
        if eclass == "ROGUE" then
                CCWatch_GetSpellRank(CCWATCH_SAP, CCWATCH_SAP, bPrint);
                CCWatch_UpdateImpGouge(bPrint);
                CCWatch_UpdateKidneyShot(bPrint);
                if CCWatch_ConfigBuff ~= nil then
                        CCWatch_UpdateImpGarotte(bPrint);
                end
        elseif eclass == "WARLOCK" then
                CCWatch_GetSpellRank(CCWATCH_FEAR, CCWATCH_FEAR, bPrint);
                CCWatch_GetSpellRank(CCWATCH_BANISH, CCWATCH_BANISH, bPrint);
                CCWatch_UpdateImpSeduce(bPrint);
        elseif eclass == "PALADIN" then
                CCWatch_GetSpellRank(CCWATCH_HOJ, CCWATCH_HOJ, bPrint);
                if CCWatch_ConfigBuff ~= nil then
                        CCWatch_GetSpellRank(CCWATCH_DIVINESHIELD, CCWATCH_DIVINESHIELD, bPrint);
                end
        elseif eclass == "HUNTER" then
                CCWatch_GetSpellRank(CCWATCH_FREEZINGTRAP_SPELL, CCWATCH_FREEZINGTRAP, bPrint);
                CCWatch_GetSpellRank(CCWATCH_SCAREBEAST, CCWATCH_SCAREBEAST, bPrint);
                CCWatch_UpdateImpTrap(bPrint);
        elseif eclass == "PRIEST" then
                CCWatch_GetSpellRank(CCWATCH_SHACKLE, CCWATCH_SHACKLE, bPrint);
                if CCWatch_ConfigDebuff ~= nil then
                        CCWatch_UpdateImpShadowWordPain(bPrint);
                end
        elseif eclass == "MAGE" then
                CCWatch_GetSpellRank(CCWATCH_POLYMORPH, CCWATCH_POLYMORPH, bPrint);
                if CCWatch_ConfigDebuff ~= nil then
                        CCWatch_GetSpellRank(CCWATCH_FROSTBOLT, CCWATCH_FROSTBOLT, bPrint);
                        CCWatch_GetSpellRank(CCWATCH_FIREBALL, CCWATCH_FIREBALL, bPrint);
                        CCWatch_UpdatePermafrost(bPrint);
                end
                CCWatchOptionsFrameArcanist:Show();
                if CCWATCH.ARCANIST then
                        CCWATCH.CCS[CCWATCH_POLYMORPH].LENGTH = CCWATCH.CCS[CCWATCH_POLYMORPH].LENGTH + 15;
                end
        elseif eclass == "DRUID" then
                CCWatch_GetSpellRank(CCWATCH_ROOTS, CCWATCH_ROOTS, bPrint);
                CCWatch_GetSpellRank(CCWATCH_HIBERNATE, CCWATCH_HIBERNATE, bPrint);
                CCWatch_GetSpellRank(CCWATCH_BASH, CCWATCH_BASH, bPrint);
                CCWatch_UpdateBrutalImpact(bPrint);
        end
end

function CCWatch_Help()
        CCWatch_AddMessage(CCWATCH_FULLVERSION..CCWATCH_HELP1);
        CCWatch_AddMessage(CCWATCH_HELP2);
        CCWatch_AddMessage(CCWATCH_HELP3);
        CCWatch_AddMessage(CCWATCH_HELP4);
        CCWatch_AddMessage(CCWATCH_HELP5);
        CCWatch_AddMessage(CCWATCH_HELP6);
        CCWatch_AddMessage(CCWATCH_HELP7);
        CCWatch_AddMessage(CCWATCH_HELP8);
        CCWatch_AddMessage(CCWATCH_HELP9);
        CCWatch_AddMessage(CCWATCH_HELP10);
        CCWatch_AddMessage(CCWATCH_HELP11);
        CCWatch_AddMessage(CCWATCH_HELP12);
        CCWatch_AddMessage(CCWATCH_HELP13);
        CCWatch_AddMessage(CCWATCH_HELP14);
        CCWatch_AddMessage(CCWATCH_HELP15);
        CCWatch_AddMessage(CCWATCH_HELP16);
        CCWatch_AddMessage(CCWATCH_HELP17);
end

function CCWatch_SetWidth(width)
        local i, j, k;
        for j, k in ipairs({"CC","Debuff","Buff"}) do
                for i=1,CCWATCH_MAXBARS do
                        getglobal("CCWatchBar"..k..i):SetWidth(width + 10);
                        getglobal("CCWatchBar"..k..i.."Text"):SetWidth(width);
                        getglobal("CCWatchBar"..k..i.."StatusBar"):SetWidth(width);
                end
                getglobal("CCWatch"..k):SetWidth(width + 10);
        end
end



function CCWatch_CheckRecentTargets(mobname)
        local target = UnitName("target");
-- Simple compare if using current target monitoring
        if CCWATCH.STYLE == 0 then
                return mobname == target;
        end
        local index = 0;
-- Check mobname against the list
        table.foreach( CCWATCH.LASTTARGETS, function(k,v) if( v.TARGET == mobname ) then index = k end end );
        if index ~= 0 then
                return true;
        end

-- return false if target not found
        return false;
end

function CCWatch_AddLastTarget(mobname, time)
        local lt_struct = {}
        lt_struct.TARGET = mobname;
        lt_struct.TIME = time;

--      CCWatch_AddMessage("Adding "..mobname);

-- if the array is full
        if table.getn(CCWATCH.LASTTARGETS) >= 5 then
-- remove the oldest target
                local oldest = 0;
                local index = 0;
                table.foreach(CCWATCH.LASTTARGETS, function(k,v) if oldest == 0 then oldest = v.TIME; index = k; elseif( v.TIME < oldest ) then oldest = v.TIME; index = k; end end);
--              CCWatch_AddMessage("Removing old target : "..CCWATCH.LASTTARGETS[index].TARGET);
                table.remove(CCWATCH.LASTTARGETS, index);
        end
        table.insert( CCWATCH.LASTTARGETS, lt_struct )
-- DEBUG :
--      local targets = "Current targets : "
--      table.foreach(CCWATCH.LASTTARGETS, function(k,v) targets = targets.."'"..v.TARGET.."',"; end);
--      CCWatch_AddMessage(targets);
end

function CCWatch_AddMessage(msg)
        DEFAULT_CHAT_FRAME:AddMessage("<CCWatch> "..msg);
end