vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
--[[
 Decursive (v 1.9.7) add-on for World of Warcraft UI
 Copyright (C) 2005 Archarodim ( http://www.2072productions.com/?to=decursive-continued.txt )
 This is the continued work of the original Decursive (v1.9.4) by Quu
 Decursive 1.9.4 is in public domain ( www.quutar.com )
 
 License:
        This program is free software; you can redistribute it and/or
        modify it under the terms of the GNU General Public License
        as published by the Free Software Foundation; either version 2
        of the License, or (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
 
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
--]]
--
-- TODO allow people to edit and store the debuffs them selves... to custimze the skip list
-- TODO add a debuff priority list... "IE look for these first"
-- TODO make the main bar "hideable" instead of just closeable
-- TODO figure out a way to show that there is more than one debuff in the live list
-- TODO add more macro and keybidnings
-- TODO do a code cleanup
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- Debug commands
--
-- These are commands to change any of the default actions of Decursive.
-- Change these to customize how you want things. The purpose of these flags
-- is for mod developers to customize the behavour, or for confidant people
-- to muck with things
-------------------------------------------------------------------------------
-- this will spam... really only use it for testing
local Dcr_Print_Spell_Found = false; -- XXX
-- how many seconds... can be fractional... needs to be more than 0.4... 1.0 is optimal
local Dcr_SpellCombatDelay = 1.0;
-- print out a fuckload of info
Dcr_Print_DEBUG = false;
Dcr_Print_DEBUG_bis = false;
-------------------------------------------------------------------------------



-------------------------------------------------------------------------------
-- here is the global variables, these should not be changed. These basically
-- are the limits of WoW client.
-------------------------------------------------------------------------------
DCR_MAXDEBUFFS = 16;
DCR_MAXBUFFS   = 16;
DCR_START_SLOT = 1;
DCR_END_SLOT   = 120;
-------------------------------------------------------------------------------
-- and any internal HARD settings for decursive
DCR_MAX_LIVE_SLOTS = 15;
DCR_TEXT_LIFETIME = 4;
-- DCR_MAX_RANGE_CHECK = 4;
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- The stored variables
-------------------------------------------------------------------------------
Dcr_Saved = {
    -- this is the items that are stored... I might later do this per account.                                                  

    -- this is the priority list of people to cure
    PriorityList = { };

    -- this is the people to skip
    SkipList = { };

    -- this is wiether or not to show the "live" list   
    Show_LiveList = true;

    -- This will turn on and off the sending of messages to the default chat frame
    Print_ChatFrame = false;

    -- this will send the messages to a custom frame that is moveable   
    Print_CustomFrame = true;

    -- this will disable error messages
    Print_Error = true;

    -- check for abolish XXX before curing poison or disease
    Check_For_Abolish = true;

    -- this is "fix" for the fact that rank 1 of dispell magic does not always remove
    -- the high level debuffs properly. This carrys over to other things.
    AlwaysUseBestSpell = true;

    -- should we do the orders randomly?
    Random_Order = false;

    -- should we scan pets
    Scan_Pets = true;

    -- should we ignore stealthed units
    Ingore_Stealthed = false;

    -- how many to show in the livelist
    Amount_Of_Afflicted = 5;

    -- how many seconds to "black list" someone with a failed spell
    CureBlacklist       = 5.0;

    -- how often to poll for afflictions in seconds
    ScanTime = 0.2;

    -- do a range check
    -- RangeCheck = true;

    -- Are prio list members protected from blacklisting?
    DoNot_Blacklist_Prio_List = false;

    -- Play a sound when there is something to decurse
    PlaySound = true;

    -- Hide the buttons
    HideButtons = false;

};
-- this is something i use for remote debugging
DCR_REMOTE_DEBUG = { };
-- This array avoid to test someone we've just blackisted twice.
local DCR_ThisCleanBlaclisted = { };
-- local DCR_ThisNumberOoRUnits  = 0;

-------------------------------------------------------------------------------

function Dcr_OnLoad (Frame)
   Frame:RegisterEvent("PLAYER_LOGIN");
end

local Dcr_CheckingPET = false;
local Dcr_DelayedReconf = false;

function Dcr_OnEvent (event)
    local Frame = this;

     -- Dcr_debug_bis ("Event was catch: " .. event);
    

    if (event == "UNIT_PET" and arg1 == "player" and not Dcr_CheckingPET) then
        Dcr_CheckingPET = true;
        Dcr_debug_bis ("PLAYER pet detected! Poll in 2 seconds");
        return;
    elseif (event == "UNIT_PET" and (arg1 ~= "player" or Dcr_CheckingPET)) then
        return;
    elseif (event == "PLAYER_ENTER_COMBAT") then
        Dcr_EnterCombat();
        return;
    elseif (event == "PLAYER_LEAVE_COMBAT") then
        Dcr_LeaveCombat();
        return;
    elseif (event == "UI_ERROR_MESSAGE") then
        if (arg1 == SPELL_FAILED_LINE_OF_SIGHT) then
            Dcr_errln("Out of sight!");
            Dcr_SpellCastFailed();
        end
        return;
        --[[ elseif (
        (event == "SPELLCAST_FAILED") or
        (event == "SPELLCAST_INTERRUPTED")
        ) then
        if (arg1) then --  XXX
            Dcr_errln("test arg on cast failed: " .. arg1);

        end
        Dcr_SpellCastFailed();
        return;
        --]]
    elseif (event == "SPELLCAST_STOP") then
        Dcr_SpellWasCast();
        return;
    elseif (not Dcr_DelayedReconf and event == "SPELLS_CHANGED" and arg1==nil) then
        Dcr_DelayedReconf = true;
        return;
    elseif (event == "LEARNED_SPELL_IN_TAB") then
        Dcr_Configure();
        return;
    
    end

    if (event == "PLAYER_LOGIN") then
        Frame:RegisterEvent("PLAYER_ENTERING_WORLD");
        Frame:RegisterEvent("PLAYER_LEAVING_WORLD");
        Dcr_Init();
        return;
    end

    if (
        (event == "PLAYER_ENTERING_WORLD")
        ) then
        Frame:RegisterEvent("PLAYER_ENTER_COMBAT");
        Frame:RegisterEvent("PLAYER_LEAVE_COMBAT");
        -- Frame:RegisterEvent("SPELLCAST_FAILED");
        -- Frame:RegisterEvent("SPELLCAST_INTERRUPTED");
        Frame:RegisterEvent("SPELLCAST_STOP");
        Frame:RegisterEvent("UNIT_PET");
        Frame:RegisterEvent("SPELLS_CHANGED");
        Frame:RegisterEvent("LEARNED_SPELL_IN_TAB");
        Frame:RegisterEvent("UI_ERROR_MESSAGE");

    elseif (event == "PLAYER_LEAVING_WORLD") then

        Frame:UnregisterEvent("PLAYER_ENTER_COMBAT");
        Frame:UnregisterEvent("PLAYER_LEAVE_COMBAT");
        -- Frame:UnregisterEvent("SPELLCAST_FAILED");
        -- Frame:UnregisterEvent("SPELLCAST_INTERRUPTED");
        Frame:UnregisterEvent("SPELLCAST_STOP");
        Frame:UnregisterEvent("UNIT_PET");
        Frame:UnregisterEvent("SPELLS_CHANGED");
        Frame:UnregisterEvent("LEARNED_SPELL_IN_TAB");
        Frame:UnregisterEvent("UI_ERROR_MESSAGE");
    end

end

-------------------------------------------------------------------------------
-- and the printing functions
-------------------------------------------------------------------------------
function Dcr_debug( Message)
    if (Dcr_Print_DEBUG) then
        table.insert(DCR_REMOTE_DEBUG, Message);
        DEFAULT_CHAT_FRAME:AddMessage(Message, 0.1, 0.1, 1);
    end
end


function Dcr_debug_bis( Message)
    if (Dcr_Print_DEBUG_bis) then
        table.insert(DCR_REMOTE_DEBUG, Message);
        DEFAULT_CHAT_FRAME:AddMessage(Message, 0.1, 0.1, 1);
    end
end

function Dcr_println( Message)

    if (Dcr_Saved.Print_ChatFrame) then
        DEFAULT_CHAT_FRAME:AddMessage(Message, 1, 1, 1);
    end
    if (Dcr_Saved.Print_CustomFrame) then
        DecursiveTextFrame:AddMessage(Message, 1, 1, 1, 0.9, DCR_TEXT_LIFETIME);
    end
end

function Dcr_errln( Message)
    if (Dcr_Saved.Print_Error) then
        if (Dcr_Saved.Print_ChatFrame) then
            DEFAULT_CHAT_FRAME:AddMessage(Message, 1, 0.1, 0.1);
        end
        if (Dcr_Saved.Print_CustomFrame) then
            DecursiveTextFrame:AddMessage(Message, 1, 0.1, 0.1, 0.9, DCR_TEXT_LIFETIME);
        end
    end
end
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- local variables
-------------------------------------------------------------------------------
local Dcr_CuringAction_Icons = { };

-- the new spellbook (made it simpler due to localization problems)
local DCR_HAS_SPELLS = false;
local DCR_SPELL_MAGIC_1 = {0,"", ""};
local DCR_SPELL_MAGIC_2 = {0,"", ""};
local DCR_CAN_CURE_MAGIC = false;
local DCR_SPELL_ENEMY_MAGIC_1 = {0,"", ""};
local DCR_SPELL_ENEMY_MAGIC_2 ={0,"", ""};
local DCR_CAN_CURE_ENEMY_MAGIC = false;
local DCR_SPELL_DISEASE_1 = {0,"", ""};
local DCR_SPELL_DISEASE_2 = {0,"", ""};
local DCR_CAN_CURE_DISEASE = false;
local DCR_SPELL_POISON_1 = {0,"", ""};
local DCR_SPELL_POISON_2 = {0,"", ""};
local DCR_CAN_CURE_POISON = false;
local DCR_SPELL_CURSE = {0,"", ""};
local DCR_CAN_CURE_CURSE = false;
local DCR_SPELL_COOLDOWN_CHECK = {0,"", ""};

-- for the blacklist
local Dcr_Casting_Spell_On = nil;
local Dcr_Blacklist_Array = { };

-------------------------------------------------------------------------------
-- init functions and configuration functions
-------------------------------------------------------------------------------
function Dcr_Init()
    Dcr_println(DCR_VERSION_STRING);

    Dcr_debug_bis( "Decursive Initialization started !");

    Dcr_debug( "Registering the slash commands");
    SLASH_DECURSIVE1 = DCR_MACRO_COMMAND;
    SlashCmdList["DECURSIVE"] = function(msg)
        Dcr_Clean();
    end

    SLASH_DECURSIVEPRADD1 = DCR_MACRO_PRADD;
    SlashCmdList["DECURSIVEPRADD"] = function(msg)
        Dcr_AddTargetToPriorityList();
    end
    SLASH_DECURSIVEPRCLEAR1 = DCR_MACRO_PRCLEAR;
    SlashCmdList["DECURSIVEPRCLEAR"] = function(msg)
        Dcr_ClearPriorityList();
    end
    SLASH_DECURSIVEPRLIST1 = DCR_MACRO_PRLIST;
    SlashCmdList["DECURSIVEPRLIST"] = function(msg)
        Dcr_PrintPriorityList();
    end
    SLASH_DECURSIVEPRSHOW1 = DCR_MACRO_PRSHOW;
    SlashCmdList["DECURSIVEPRSHOW"] = function(msg)
        Dcr_ShowHidePriorityListUI();
    end

    SLASH_DECURSIVESKADD1 = DCR_MACRO_SKADD;
    SlashCmdList["DECURSIVESKADD"] = function(msg)
        Dcr_AddTargetToSkipList();
    end
    SLASH_DECURSIVESKCLEAR1 = DCR_MACRO_SKCLEAR;
    SlashCmdList["DECURSIVESKCLEAR"] = function(msg)
        Dcr_ClearSkipList();
    end
    SLASH_DECURSIVESKLIST1 = DCR_MACRO_SKLIST;
    SlashCmdList["DECURSIVESKLIST"] = function(msg)
        Dcr_PrintSkipList();
    end
    SLASH_DECURSIVESKSHOW1 = DCR_MACRO_SKSHOW;
    SlashCmdList["DECURSIVESKSHOW"] = function(msg)
        Dcr_ShowHideSkipListUI();
    end

    SLASH_DECURSIVESHOW1 = DCR_MACRO_SHOW;
    SlashCmdList["DECURSIVESHOW"] = function(msg)
        Dcr_ShowHideAfflictedListUI();
    end

    SLASH_DECURSIVERESET1 = DCR_MACRO_RESET;
    SlashCmdList["DECURSIVERESET"] = function(msg)
        Dcr_ResetWindow();
    end

    if (Dcr_Saved.Show_LiveList) then
        DecursiveAfflictedListFrame:Show();
    else
        DecursiveAfflictedListFrame:Hide();
    end

    if (Dcr_Saved.HideButtons == nil) then
        Dcr_Saved.HideButtons = false;
    end

    Dcr_ShowHideButtons(true);

    -- check the spellbook once
    Dcr_Configure();
    DEFAULT_CHAT_FRAME:AddMessage(DCR_IS_HERE_MSG, 0.3, 0.5, 1);
    DEFAULT_CHAT_FRAME:AddMessage(DCR_SHOW_MSG, 0.3, 0.5, 1);
end

-- this resets the location of the windows
function Dcr_ResetWindow()
    DecursiveAfflictedListFrame:ClearAllPoints();
    DecursiveAfflictedListFrame:SetPoint("CENTER", "UIParent");

    DecursivePriorityListFrame:ClearAllPoints();
    DecursivePriorityListFrame:SetPoint("CENTER", "UIParent");

    DecursiveSkipListFrame:ClearAllPoints();
    DecursiveSkipListFrame:SetPoint("CENTER", "UIParent");

    DecursivePopulateListFrame:ClearAllPoints();
    DecursivePopulateListFrame:SetPoint("CENTER", "UIParent");

    DcrOptionsFrame:ClearAllPoints();
    DcrOptionsFrame:SetPoint("CENTER", "UIParent");
end

-- this gets an array of units for us to check
function Dcr_GetUnitArray()
    -- TODO: OPTIMIZE this function... a lot of things are done several times.
    local Dcr_Unit_Array = { };
    -- create the array of curable units

    -- first... the priority list... names that go first!
    local pname;
    for _, pname in Dcr_Saved.PriorityList do
        local unit = Dcr_NameToUnit( pname);
        if (unit) then
            table.insert(Dcr_Unit_Array,unit);
        end
    end

    -- then everything else
    local i;
    local raidnum = GetNumRaidMembers();
    local temp_table = { };

    -- add your self (you are never skipped) except if you are already in the prio list...
    if (not Dcr_IsInSkipOrPriorList(UnitName("player"))) then
        table.insert(Dcr_Unit_Array, "player");
    end

    -- add the party members... if they exist
    for i = 1, 4 do
        if (UnitExists("party"..i)) then
            pname = UnitName("party"..i);
            -- check the name to see if we skip
            if (not Dcr_IsInSkipOrPriorList(pname)) then
                -- we don't skip them
                if (Dcr_Saved.Random_Order) then
                    table.insert(temp_table,"party"..i);
                else
                    table.insert(Dcr_Unit_Array,"party"..i);
                end
            end
        end
    end
    if (Dcr_Saved.Random_Order) then
        local temp_max = table.getn(temp_table);
        for i = 1, temp_max do
            table.insert(Dcr_Unit_Array,table.remove(temp_table,random(1, table.getn(temp_table))));
        end
    end

    -- add the raid IDs that are valid...
    -- add it from the sub group after yours... and then loop
    -- around to the group right before yours
    if ( raidnum > 0 ) then
        local currentGroup = 0;
        local name = UnitName( "player");

        for i = 1, raidnum do
            local rName, _, rGroup = GetRaidRosterInfo(i);
            if (rName == name) then
                currentGroup = rGroup;
                break;
            end
        end

        -- first the groups that are after yours
        for i = 1, raidnum do
            local pname, _, rGroup = GetRaidRosterInfo(i);
            -- get the group and name
            if (rGroup > currentGroup) then
                -- group is after ours
                if (not Dcr_IsInSkipOrPriorList(pname)) then
                    -- and we are not skipping this name
                    if (Dcr_Saved.Random_Order) then
                        table.insert(temp_table,"raid"..i);
                    else
                        table.insert(Dcr_Unit_Array,"raid"..i);
                    end
                end
            end
        end
        -- the the ones that are before yours
        for i = 1, raidnum do
            local pname, _, rGroup = GetRaidRosterInfo(i);
            -- get the group and name
            if (rGroup < currentGroup) then
                -- its before our group
                if (not Dcr_IsInSkipOrPriorList(pname)) then
                    -- and we are not skipping this name
                    if (Dcr_Saved.Random_Order) then
                        table.insert(temp_table,"raid"..i);
                    else
                        table.insert(Dcr_Unit_Array,"raid"..i);
                    end
                end
            end
        end
        -- don't bother with your own group... since its also party 1-4

        if (Dcr_Saved.Random_Order) then
            local temp_max = table.getn(temp_table);
            for i = 1, temp_max do
                table.insert(Dcr_Unit_Array,table.remove(temp_table,random(1, table.getn(temp_table))));
            end
        end
    end

    if (not Dcr_Saved.Scan_Pets) then
        -- we are not doing pets... leave here
        return Dcr_Unit_Array;
    end
    -- now the pets

    -- your own pet
    if (UnitExists("pet")) then
        table.insert(Dcr_Unit_Array,"pet");
    end

    -- the parties pets if they have them
    for i = 1, 4 do
        if (UnitExists("partypet"..i)) then
            pname = UnitName("partypet"..i);
            -- get the pet name
            if (not Dcr_IsInSkipOrPriorList(pname)) then
                -- to see if we skip it
                if (Dcr_Saved.Random_Order) then
                    table.insert(temp_table,"partypet"..i);
                else
                    table.insert(Dcr_Unit_Array,"partypet"..i);
                end
            end
        end
    end
    if (Dcr_Saved.Random_Order) then
        local temp_max = table.getn(temp_table);
        for i = 1, temp_max do
            table.insert(Dcr_Unit_Array,table.remove(temp_table,random(1, table.getn(temp_table))));
        end
    end

    -- and then the raid pets if they are out
    -- don't worry about the fancier logic with the pets
    if ( raidnum > 0 ) then
        for i = 1, raidnum do
            if (UnitExists("raidpet"..i)) then
                pname = UnitName("raidpet"..i);
                -- get pet name
                if (not Dcr_IsInSkipOrPriorList(pname)) then
                    -- to see if we skip it
                    if (Dcr_Saved.Random_Order) then
                        table.insert(temp_table,"raidpet"..i);
                    else
                        table.insert(Dcr_Unit_Array,"raidpet"..i);
                    end
                end
            end
        end
        if (Dcr_Saved.Random_Order) then
            local temp_max = table.getn(temp_table);
            for i = 1, temp_max do
                table.insert(Dcr_Unit_Array,table.remove(temp_table,random(1, table.getn(temp_table))));
            end
        end
    end

    return Dcr_Unit_Array;
end

-- Raid/Party Name Check Function
-- this returns the UnitID that the Name points to
-- this does not check "target" or "mouseover"
function Dcr_NameToUnit( Name)
    if (not Name) then
        return false;
    elseif (Name == UnitName("player")) then
        return "player";
    elseif (Name == UnitName("pet")) then
        return "pet";
    elseif (Name == UnitName("party1")) then
        return "party1";
    elseif (Name == UnitName("party2")) then
        return "party2";
    elseif (Name == UnitName("party3")) then
        return "party3";
    elseif (Name == UnitName("party4")) then
        return "party4";
    elseif (Name == UnitName("partypet1")) then
        return "partypet1";
    elseif (Name == UnitName("partypet2")) then
        return "partypet2";
    elseif (Name == UnitName("partypet3")) then
        return "partypet3";
    elseif (Name == UnitName("partypet4")) then
        return "partypet4";
    else
        local numRaidMembers = GetNumRaidMembers();
        if (numRaidMembers > 0) then
            -- we are in a raid
            local i;
            for i=1, numRaidMembers do
                local RaidName = GetRaidRosterInfo(i);
                if ( Name == RaidName) then
                    return "raid"..i;
                end
                if ( Name == UnitName("raidpet"..i)) then
                    return "raidpet"..i;
                end
            end
        end
    end
    return false;
end

function Dcr_CheckSpellName (id, booktype, spellname)

    if id ~= 0  then
        Dcr_debug_bis("testing spell for name changes: id="..id);
        local found_spellname, spellrank = GetSpellName(id, booktype);

        if spellname ~= found_spellname then
            return false;
        end
    end

    return true;
end

function Dcr_ReConfigure()

    if not DCR_HAS_SPELLS then
        return;
    end

    Dcr_debug_bis("Dcr_ReConfigure was called!");

    local DoNotReconfigure = true;

    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_MAGIC_1[1], DCR_SPELL_MAGIC_1[2], DCR_SPELL_MAGIC_1[3]);
    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_MAGIC_2[1], DCR_SPELL_MAGIC_2[2], DCR_SPELL_MAGIC_2[3]);

    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_ENEMY_MAGIC_1[1], DCR_SPELL_ENEMY_MAGIC_1[2], DCR_SPELL_ENEMY_MAGIC_1[3]);
    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_ENEMY_MAGIC_2[1], DCR_SPELL_ENEMY_MAGIC_2[2], DCR_SPELL_ENEMY_MAGIC_2[3]);

    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_DISEASE_1[1], DCR_SPELL_DISEASE_1[2], DCR_SPELL_DISEASE_1[3]);
    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_DISEASE_2[1], DCR_SPELL_DISEASE_2[2], DCR_SPELL_DISEASE_2[3]);

    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_POISON_1[1], DCR_SPELL_POISON_1[2], DCR_SPELL_POISON_1[3]);
    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_POISON_2[1], DCR_SPELL_POISON_2[2], DCR_SPELL_POISON_2[3]);
    
    DoNotReconfigure = Dcr_CheckSpellName(DCR_SPELL_CURSE[1], DCR_SPELL_CURSE[2], DCR_SPELL_CURSE[3]);

    if DoNotReconfigure == false then
        Dcr_debug_bis("Dcr_ReConfigure RECONFIGURATION!");
        Dcr_Configure();
        return;
    end
    Dcr_debug_bis("Dcr_ReConfigure No reconfiguration required!");

end

Dcr_PlayerClass = "";
function Dcr_Configure()

    -- first empty out the old "spellbook"
    DCR_HAS_SPELLS = false;
    DCR_SPELL_MAGIC_1 = {0,"", ""};
    DCR_SPELL_MAGIC_2 = {0,"", ""};
    DCR_CAN_CURE_MAGIC = false;
    DCR_SPELL_ENEMY_MAGIC_1 = {0,"", ""};
    DCR_SPELL_ENEMY_MAGIC_2 = {0,"", ""};
    DCR_CAN_CURE_ENEMY_MAGIC = false;
    DCR_SPELL_DISEASE_1 = {0,"", ""};
    DCR_SPELL_DISEASE_2 = {0,"", ""};
    DCR_CAN_CURE_DISEASE = false;
    DCR_SPELL_POISON_1 = {0,"", ""};
    DCR_SPELL_POISON_2 = {0,"", ""};
    DCR_CAN_CURE_POISON = false;
    DCR_SPELL_CURSE = {0,"", ""};
    DCR_CAN_CURE_CURSE = false;


    Dcr_debug_bis("Configuring Decursive...");
    -- parse through the entire library...
    -- look for known cleaning spells...
    -- this will be called everytime the spellbook changes

    -- this is just used to make things simpler in the checking
    local Dcr_Name_Array = {
        [DCR_SPELL_CURE_DISEASE] = true,
        [DCR_SPELL_ABOLISH_DISEASE] = true,
        [DCR_SPELL_PURIFY] = true,
        [DCR_SPELL_CLEANSE] = true,
        [DCR_SPELL_DISPELL_MAGIC] = true,
        [DCR_SPELL_CURE_POISON] = true,
        [DCR_SPELL_ABOLISH_POISON] = true,
        [DCR_SPELL_REMOVE_LESSER_CURSE] = true,
        [DCR_SPELL_REMOVE_CURSE] = true,
        [DCR_SPELL_PURGE] = true,
        [DCR_PET_FEL_CAST] = true,
        [DCR_PET_DOOM_CAST] = true,
    }

    local i = 1;

    local BookType = BOOKTYPE_SPELL;
    local break_flag = false
    while not break_flag  do

        while (true) do
            local spellName, spellRank = GetSpellName(i, BookType);
            if (not spellName) then
                if (BookType == BOOKTYPE_PET) then
                    break_flag = true;
                    break;
                end
                BookType = BOOKTYPE_PET;
                i = 1;
                break;

            end

            Dcr_debug( "Checking spell - "..spellName);

            if (Dcr_Name_Array[spellName]) then
                Dcr_debug( "Its one we care about");
                DCR_HAS_SPELLS = true;

                -- any of them will work for the cooldown... we store the last
                DCR_SPELL_COOLDOWN_CHECK[1] = i; DCR_SPELL_COOLDOWN_CHECK[2] = BookType;

                -- put it in the range icon array
                local icon = GetSpellTexture(i, BookType)
                Dcr_CuringAction_Icons[icon] = spellName;

                -- print out the spell
                Dcr_debug( string.gsub(DCR_SPELL_FOUND, "$s", spellName));
                if (Dcr_Print_Spell_Found) then
                    Dcr_println( string.gsub(DCR_SPELL_FOUND, "$s", spellName));
                end

                -- big ass if statement... due to the way that the different localizations work
                -- I used to do this more elegantly... but the german WoW broke it

                if ((spellName == DCR_SPELL_CURE_DISEASE) or (spellName == DCR_SPELL_ABOLISH_DISEASE) or
                    (spellName == DCR_SPELL_PURIFY) or (spellName == DCR_SPELL_CLEANSE)) then
                    DCR_CAN_CURE_DISEASE = true;
                    if ((spellName == DCR_SPELL_CURE_DISEASE) or (spellName == DCR_SPELL_PURIFY)) then
                        Dcr_debug( "Adding to disease 1");
                        DCR_SPELL_DISEASE_1[1] = i; DCR_SPELL_DISEASE_1[2] = BookType; DCR_SPELL_DISEASE_1[3] = spellName;
                    else
                        Dcr_debug( "Adding to disease 2");
                        DCR_SPELL_DISEASE_2[1] = i; DCR_SPELL_DISEASE_2[2] = BookType; DCR_SPELL_DISEASE_2[3] = spellName;
                    end
                end

                if ((spellName == DCR_SPELL_CURE_POISON) or (spellName == DCR_SPELL_ABOLISH_POISON) or
                    (spellName == DCR_SPELL_PURIFY) or (spellName == DCR_SPELL_CLEANSE)) then
                    DCR_CAN_CURE_POISON = true;
                    if ((spellName == DCR_SPELL_CURE_POISON) or (spellName == DCR_SPELL_PURIFY)) then
                        Dcr_debug( "Adding to poison 1");
                        DCR_SPELL_POISON_1[1] = i; DCR_SPELL_POISON_1[2] = BookType; DCR_SPELL_POISON_1[3] = spellName;
                    else
                        Dcr_debug( "Adding to poison 2");
                        DCR_SPELL_POISON_2[1] = i; DCR_SPELL_POISON_2[2] = BookType; DCR_SPELL_POISON_2[3] = spellName;
                    end
                end

                if ((spellName == DCR_SPELL_REMOVE_CURSE) or (spellName == DCR_SPELL_REMOVE_LESSER_CURSE)) then
                    Dcr_debug( "Adding to curse");
                    DCR_CAN_CURE_CURSE = true;
                    DCR_SPELL_CURSE[1] = i; DCR_SPELL_CURSE[2] =  BookType; DCR_SPELL_CURSE[3] = spellName;
                end

                if ((spellName == DCR_SPELL_DISPELL_MAGIC) or (spellName == DCR_SPELL_CLEANSE) or (spellName == DCR_PET_FEL_CAST) or (spellName == DCR_PET_DOOM_CAST)) then
                    DCR_CAN_CURE_MAGIC = true;
                    if (spellName == DCR_SPELL_CLEANSE) then
                        Dcr_debug( "Adding to magic 1");
                        DCR_SPELL_MAGIC_1[1] = i; DCR_SPELL_MAGIC_1[2] = BookType; DCR_SPELL_MAGIC_1[3] = spellName;
                    else
                        if (spellRank == DCR_SPELL_RANK_1) then
                            Dcr_debug( "Adding to magic 1");
                            Dcr_debug_bis( "Adding to magic 1");
                            DCR_SPELL_MAGIC_1[1] = i; DCR_SPELL_MAGIC_1[2] = BookType; DCR_SPELL_MAGIC_1[3] = spellName;
                        else
                            Dcr_debug( "adding to magic 2");
                            Dcr_debug_bis( "Adding to magic 2");
                            DCR_SPELL_MAGIC_2[1] = i; DCR_SPELL_MAGIC_2[2] = BookType; DCR_SPELL_MAGIC_2[3] = spellName;
                        end
                    end
                end

                if ((spellName == DCR_SPELL_DISPELL_MAGIC) or (spellName == DCR_SPELL_PURGE) or (spellName == DCR_PET_FEL_CAST) or (spellName == DCR_PET_DOOM_CAST)) then
                    DCR_CAN_CURE_ENEMY_MAGIC = true;
                    if (spellRank == DCR_SPELL_RANK_1) then
                        Dcr_debug( "Adding to enemy magic 1");
                        Dcr_debug_bis( "Adding to enemy magic 1");
                        DCR_SPELL_ENEMY_MAGIC_1[1] = i; DCR_SPELL_ENEMY_MAGIC_1[2] = BookType; DCR_SPELL_ENEMY_MAGIC_1[3] = spellName;
                    else
                        Dcr_debug( "Adding to enemy magic 2");
                        Dcr_debug_bis( "Adding to enemy magic 2");
                        DCR_SPELL_ENEMY_MAGIC_2[1] = i; DCR_SPELL_ENEMY_MAGIC_2[2] = BookType; DCR_SPELL_ENEMY_MAGIC_2[3] = spellName;
                    end
                end

            end

            i = i + 1
        end
    end
   
    local _, PlayerClass = UnitClass("player");

    Dcr_PlayerClass = PlayerClass;
    --[[
    if (DCR_HAS_SPELLS and Dcr_PlayerClass ~= DCR_CLASS_WARLOCK and Dcr_FindCureingActionSlot(Dcr_CuringAction_Icons)==0) then

            message(DCR_STR_NEED_CURE_ACTION_IN_BARS);
    end
    --]]

end
-------------------------------------------------------------------------------


-------------------------------------------------------------------------------
-- the priority and skip list function... stuff to manage the lists
-------------------------------------------------------------------------------
function Dcr_ShowHideAfflictedListUI()
    if (DecursiveAfflictedListFrame:IsVisible()) then
        Dcr_Saved.Show_LiveList = false;
        DecursiveAfflictedListFrame:Hide();
    else
        Dcr_Saved.Show_LiveList = true;
        DecursiveAfflictedListFrame:Show();
    end
end

-- priority list stuff
function Dcr_ShowHidePriorityListUI()
    if (DecursivePriorityListFrame:IsVisible()) then
        DecursivePriorityListFrame:Hide();
    else
        DecursivePriorityListFrame:Show();
    end
end

function Dcr_ThisSetText(text)
    getglobal(this:GetName().."Text"):SetText(text);
end

function Dcr_AddTargetToPriorityList()
    Dcr_debug( "Adding the target to the priority list");
    DcrAddUnitToPriorityList("target");
end

function DcrAddUnitToPriorityList( unit)
    if (UnitExists(unit)) then
        if (UnitIsPlayer(unit)) then
            local name = UnitName( unit);
            for _, pname in Dcr_Saved.PriorityList do
                if (name == pname) then
                    return;
                end
            end
            table.insert(Dcr_Saved.PriorityList,name);
        end
        DecursivePriorityListFrame.UpdateYourself = true;
    end
end

function Dcr_RemoveIDFromPriorityList(id)
    table.remove( Dcr_Saved.PriorityList,id);
    DecursivePriorityListFrame.UpdateYourself = true;
end

function Dcr_ClearPriorityList()
    local i;
    local max = table.getn(Dcr_Saved.PriorityList);
    for i = 1, max do
        table.remove( Dcr_Saved.PriorityList);
    end
    DecursivePriorityListFrame.UpdateYourself = true;
end

function Dcr_PrintPriorityList()
    for id, name in Dcr_Saved.PriorityList do
        Dcr_println( id.." - "..name);
    end
end

-- skip list stuff
function Dcr_ShowHideSkipListUI()
    if (DecursiveSkipListFrame:IsVisible()) then
        DecursiveSkipListFrame:Hide();
    else
        DecursiveSkipListFrame:Show();
    end
end

function Dcr_ShowHideOptionsUI()
    if (DcrOptionsFrame:IsVisible()) then
        DcrOptionsFrame:Hide();
    else
        DcrOptionsFrame:Show();
    end
end

function Dcr_ShowHideTextAnchor()
    if (DecursiveAnchor:IsVisible()) then
        DecursiveAnchor:Hide();
    else
        DecursiveAnchor:Show();
    end
end

function Dcr_ShowHideButtons(UseCurrentValue)

    local DecrFrame = "DecursiveAfflictedListFrame";
    local buttons = {
        DecrFrame .. "Priority",
        DecrFrame .. "Skip",
        DecrFrame .. "Options",
        DecrFrame .. "Hide",
    }

    DCRframeObject = getglobal(DecrFrame);

    if (not UseCurrentValue) then
        Dcr_Saved.HideButtons = (not Dcr_Saved.HideButtons);
    end

    for _, ButtonName in buttons do
        Button = getglobal(ButtonName);

        if (Dcr_Saved.HideButtons) then
            Button:Hide();
            DCRframeObject.isLocked = 1;
        else
            Button:Show();
            DCRframeObject.isLocked = 0;
        end

    end



end

function Dcr_AddTargetToSkipList()
    Dcr_debug( "Adding the target to the Skip list");
    DcrAddUnitToSkipList("target");
end

function DcrAddUnitToSkipList( unit)
    if (UnitExists(unit)) then
        if (UnitIsPlayer(unit)) then
            local name = UnitName( unit);
            for _, pname in Dcr_Saved.SkipList do
                if (name == pname) then
                    return;
                end
            end
            table.insert(Dcr_Saved.SkipList,name);
            DecursiveSkipListFrame.UpdateYourself = true;
        end
    end
end

function Dcr_RemoveIDFromSkipList(id)
    table.remove( Dcr_Saved.SkipList,id);
    DecursiveSkipListFrame.UpdateYourself = true;
end

function Dcr_ClearSkipList()
    local i;
    local max = table.getn(Dcr_Saved.SkipList);
    for i = 1, max do
        table.remove( Dcr_Saved.SkipList);
    end
    DecursiveSkipListFrame.UpdateYourself = true;
end

function Dcr_PrintSkipList()
    for id, name in Dcr_Saved.SkipList do
        Dcr_println( id.." - "..name);
    end
end

function Dcr_IsInPriorList (name)
    for _, PriorName in Dcr_Saved.PriorityList do
        if (PriorName == name) then
            return true;
        end
    end
    return false;
end

function Dcr_IsInSkipList (name)
    for _, SkipName in Dcr_Saved.SkipList do
        if (SkipName == name) then
            return true;
        end
    end
    return false
end

function Dcr_IsInSkipOrPriorList( name )
    if (Dcr_IsInSkipList(name)) then
        return true;
    end

    if (Dcr_IsInPriorList(name)) then
        return true;
    end
    return false;

    --[[
    -- Dcr_debug_bis("Dcr_IsInSkipOrPriorList called with: " .. name);
    if (name) then
        for _, SkipName in Dcr_Saved.SkipList do
            if (SkipName == name) then
                return true;
            end
        end
        for _, PriorName in Dcr_Saved.PriorityList do
            if (PriorName == name) then
                return true;
            end
        end
    end
    return false;
    --]]
end
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- the combat saver functions and events. These keep us in combat mode
-------------------------------------------------------------------------------
local Dcr_CombatMode = false;
function Dcr_EnterCombat()
    Dcr_debug("Entering combat");
    Dcr_CombatMode = true;
end

function Dcr_LeaveCombat()
    Dcr_debug("Leaving combat");
    Dcr_CombatMode = false;
end


local Dcr_CheckPet_Delay        = 2;
local Dcr_DelayedReconf_delay   = 1;

local Dcr_DelayedReconf_timer   = 0;
local Dcr_CheckPet_Timer        = 0;
local Dcr_Delay_Timer           = 0;

local last_DemonType = nil;
local curr_DemonType = nil;

-- This function update Decursive states :
--   - Reconf if needed
--   - check for a pet
--   - clear the black list
function Dcr_OnUpdate(arg1)


    --checkinfgfor reconf need
    if Dcr_DelayedReconf then
        Dcr_DelayedReconf_timer = Dcr_DelayedReconf_timer + arg1;
        if (Dcr_DelayedReconf_timer >= Dcr_DelayedReconf_delay) then
            Dcr_DelayedReconf_timer = 0;

            Dcr_ReConfigure();
            Dcr_DelayedReconf = false;
            return;
        end
    end

    -- checking for pet
    if (Dcr_CheckingPET) then
        Dcr_CheckPet_Timer = Dcr_CheckPet_Timer + arg1;

        if (Dcr_CheckPet_Timer >= Dcr_CheckPet_Delay) then
            Dcr_CheckPet_Timer = 0;

            curr_DemonType = UnitCreatureFamily("pet");

            if (curr_DemonType) then Dcr_debug_bis ("Pet Type: " .. curr_DemonType);  end;

            if (last_DemonType ~= curr_DemonType) then
                if (curr_DemonType) then Dcr_debug_bis ("Pet name changed: " .. curr_DemonType); else  Dcr_debug_bis ("No more pet!"); end;

                last_DemonType = curr_DemonType;
                Dcr_Configure();
            end

            Dcr_CheckingPET = false;
            return;
        end

    end

    -- clean up the blacklist
    for unit in Dcr_Blacklist_Array do
        Dcr_Blacklist_Array[unit] = Dcr_Blacklist_Array[unit] - arg1;
        if (Dcr_Blacklist_Array[unit] < 0) then
            Dcr_Blacklist_Array[unit] = nil;
        end
    end

    -- wow the next command SPAMS alot
    -- Dcr_debug("got update "..arg1);

    -- this is the fix for the AttackTarget() bug
    if (Dcr_Delay_Timer > 0) then
        Dcr_Delay_Timer = Dcr_Delay_Timer - arg1;
        if (Dcr_Delay_Timer <= 0) then
            if (not Dcr_CombatMode) then
                Dcr_debug("trying to reset the combat mode");
                AttackTarget();
            else
                Dcr_debug("already in combat mode");
            end
        end;
    end
end

-------------------------------------------------------------------------------
-- Scanning functionalty... this scans the parties and groups
-------------------------------------------------------------------------------
local Dcr_AlreadyCleanning = false;
local Dcr_RestoreTarget = true;
function Dcr_Clean(UseThisTarget, SwitchToTarget)
    -----------------------------------------------------------------------
    -- first we do the setup, make sure we can cast the spells
    -----------------------------------------------------------------------

    if (not DCR_HAS_SPELLS) then
        -- check the spellbook again... (mod by Archarodim)
        Dcr_errln(DCR_NO_SPELLS);
        Dcr_Configure();
        if (not DCR_HAS_SPELLS) then
            Dcr_errln(DCR_NO_SPELLS);
            return false;
        end
    end

    Dcr_RestoreTarget = true;
    if (UseThisTarget and SwitchToTarget) then
        TargetUnit(UseThisTarget);
        Dcr_RestoreTarget = false;
    end

    if (Dcr_AlreadyCleanning) then
        Dcr_debug_bis("I'm already cleaning!!!!"); -- seems to be useless
        return false;
    end

    Dcr_AlreadyCleanning = true;

    --[[
    local isUsable, notEnoughMana = Dcr_IsSpellUsable();

    if (not isUsable) then
        if (notEnoughMana) then
            Dcr_errln(DCR_STR_NOMANA);
            Dcr_AlreadyCleanning = false;
            return false;
        elseif (Dcr_PlayerClass ~= DCR_CLASS_PRIEST) then
            Dcr_errln(DCR_STR_UNUSABLE);
            Dcr_AlreadyCleanning = false;
            return false;
        end
    end
    --]]


    local _, cooldown = GetSpellCooldown(DCR_SPELL_COOLDOWN_CHECK[1], DCR_SPELL_COOLDOWN_CHECK[2])
    if (cooldown ~= 0) then
        -- this used to be an errline... changed it to debugg
        Dcr_debug_bis(DCR_NO_SPELLS_RDY);
        Dcr_AlreadyCleanning = false;
        return false;
    end


    -- reset blaclisted people in this clean session
    DCR_ThisCleanBlaclisted = { };
    -- reset the number of out of ranged units for this clean session
    DCR_ThisNumberOoRUnits  = 0;


    -----------------------------------------------------------------------
    -----------------------------------------------------------------------
    -- then we see what our target looks like, if freindly, check them
    -----------------------------------------------------------------------

    local targetEnemy = false;
    local targetName = nil; -- if friendly
    local cleaned = false;
    local resetCombatMode = false;
    Dcr_Casting_Spell_On = nil;



    if (UnitExists("target")) then
        Dcr_debug("We have a target");
        -- if we are currently targeting something
        -- ###
        -- This block is here to know what the current target is, so we can clean it, restor it
        -- or clear the target at the end of this function
        -- ###

        if (Dcr_CombatMode) then
            Dcr_debug("when done scanning... if switched target reset the mode!");
            resetCombatMode = true;
        end

        if (
            ( UnitIsFriend("target", "player") ) -- unit is a friend ie: not FriendLY just a friend that could be MC :/
            and 
            (not UnitIsCharmed("target")) -- and is not mind controlled
            ) then
            Dcr_debug(" It is friendly");

            -- try cleaning the current target first
            -- if we are not asked to clean a specific target
            -- or if we already switched to the target to clean
            if (not UseThisTarget or SwitchToTarget) then 
                cleaned = Dcr_CureUnit("target");
            end

            -- we are targeting a player that is not MC, save the name to switch back later
            targetName = UnitName("target");

        else -- unit is aggressiv or is charmed
            Dcr_debug(" It is not friendly");
            -- we are targeting an enemy... switch back when done
            targetEnemy = true;

            if ( UnitIsCharmed("target")) then
                Dcr_debug( "Unit is enemey... and charmed... so its a mind controlled friendly");
                -- try cleaning mind controlled person first
                if (not UseThisTarget or SwitchToTarget) then 
                    cleaned = Dcr_CureUnit("target");
                end
            end
        end
    end

    if (UseThisTarget and not SwitchToTarget and not cleaned) then
        Dcr_debug( "A target to clean was specifyed");
        if (UnitIsVisible(UseThisTarget)) then
            -- if the unit is even close by


            if (DCR_CAN_CURE_ENEMY_MAGIC and UnitIsCharmed(UseThisTarget)) then
                -- if the unit is mind controlled and we can cure it
                if (Dcr_CureUnit(UseThisTarget)) then
                    cleaned = true;
                end

            else -- we can't cure magic on enemies or the unit is not charmed
                if (not Dcr_CheckUnitStealth(UseThisTarget)) then
                    -- we are either not ignoring the stealthed people,
                    -- or it's not stealthed
                    if (Dcr_CureUnit(UseThisTarget)) then
                        cleaned = true;
                    end
                end
            end
        end
    end

    if (not cleaned) then

        -----------------------------------------------------------------------
        -----------------------------------------------------------------------
        -- now we check the partys (raid and local)
        -----------------------------------------------------------------------
        Dcr_debug( "Checking the arrays");

        -- this is the cleaning loops...
        local Dcr_Unit_Array = Dcr_GetUnitArray();
        -- the order is player, party1-4, raid, pet, partypet1-4, raidpet1-40
        -- the raid is current party + 1 to 8... then 1 to current party - 1

        -- mind control first
        if( not cleaned) then
            Dcr_debug(" looking for mind controll");
            if (DCR_CAN_CURE_ENEMY_MAGIC) then
                for _, unit in Dcr_Unit_Array do
                    -- all of the units...
                    if (not Dcr_Blacklist_Array[unit]) then
                        -- if the unit is not black listed
                        if (UnitIsVisible(unit)) then
                            -- if the unit is even close by
                            if (UnitIsCharmed(unit)) then
                                -- if the unit is mind controlled
                                if (Dcr_CureUnit(unit)) then
                                    cleaned = true;
                                    break;
                                end
                            end
                        end
                    end
                end
            end
        end

        -- normal cleaning
        if( not cleaned) then
            -- Dcr_debug(" normal loop");
            for _, unit in Dcr_Unit_Array do
                -- all of the units...
                if (not Dcr_Blacklist_Array[unit]) then
                    -- if the unit is not black listed
                    if (UnitIsVisible(unit)) then
                        -- if the unit is even close by
                        if (not UnitIsCharmed(unit)) then
                            -- we can't cure mind controlled people
                            if (not Dcr_CheckUnitStealth(unit)) then
                                -- we are either not ignoring the stealthed people,
                                -- or it's not stealthed
                                if (Dcr_CureUnit(unit)) then
                                    cleaned = true;
                                    break;
                                end
                            end
                        end
                    end
                end
            end
        end

        if ( not cleaned) then
            Dcr_debug(" double check the black list");
            for unit in Dcr_Blacklist_Array do
                -- now... all of the black listed units
                if (not DCR_ThisCleanBlaclisted[unit]) then
                    -- we do not re-check unit that have been blaclisted just before
                    if (UnitExists(unit)) then
                        -- if the unit still exists
                        if (UnitIsVisible(unit)) then
                            -- if the unit is even close by
                            if (not Dcr_CheckUnitStealth(unit)) then
                                -- we are either not ignoring the stealthed people,
                                -- or it's not stealthed
                                if (Dcr_CureUnit(unit)) then
                                    -- hey... we cleaned it... remove from the black list
                                    Dcr_Blacklist_Array[unit] = nil;
                                    cleaned = true;
                                    break;
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    -----------------------------------------------------------------------
    -----------------------------------------------------------------------
    -- ok... done with the cleaning... lets try to clean this up
    -- basically switch targets back if they were changed
    -----------------------------------------------------------------------

    if (not SwitchToTarget) then -- if not explicitly ask to switch to the target
        if (targetEnemy) then
            -- we had somethign "bad" targeted
            if (not UnitIsEnemy("target", "player")) then
                -- and we tested for range, cast dispell magic, or some how broke target... switch back
                Dcr_debug("targeting enemy");
                -- TargetLastEnemy();
                TargetUnit("playertarget"); -- XXX to test
                if (resetCombatMode) then
                    -- resetCombatMode is the fix for "auto attack"
                    Dcr_Delay_Timer = Dcr_SpellCombatDelay;
                    Dcr_debug("done... now we wait for the leave combat event");
                end
            end
        elseif (targetName) then
            -- we had a friendly targeted... switch back if not still targeted
            if ( targetName ~= UnitName("target") ) then
                TargetByName(targetName);
            end
        else
            -- we had nobody targeted originally
            if (UnitExists("target")) then
                -- we checked for range
                ClearTarget();
            end
        end
    end

    if (not cleaned) then
        Dcr_println( DCR_NOT_CLEANED);
    end

    Dcr_AlreadyCleanning = false;
    return cleaned;
end



-------------------------------------------------------------------------------
-- these are the spells used to clean a "unit" given
-------------------------------------------------------------------------------
function Dcr_CureUnit(Unit)
    Dcr_debug( "Scanning to cure unit - "..Unit);

    local Magic_Count   = 0;
    local Disease_Count = 0;
    local Poison_Count  = 0;
    local Curse_Count   = 0;

    local TClass, UClass = UnitClass(Unit);

    local i = 1;
    while (UnitDebuff(Unit, i)) do
        -- the "break" was not working all that well, so we stor a go on variable
        local Go_On = true;

        local debuff_name, debuff_type = Dcr_GetUnitDebuff(Unit, i);

        if (debuff_name == nil) then
            -- this should only happen when things are "broke"
            Dcr_errln("%$#@*& !!! Impossible to get debuff info from tooltip :'(, if this error continues to show up, type /console reloadui");
            Dcr_debug( "Debuff name not found!");                                       
            Go_On = false;
        elseif (debuff_name ~= "") then
            Dcr_debug( debuff_name.." found!");

            -- test if we have to ignore this debuff {{{ --
            -- Ignore the ones that make the target immune... abort the user
            if (DCR_IGNORELIST[debuff_name]) then
                Dcr_errln( string.gsub( string.gsub(DCR_IGNORE_STRING, "$t", UnitName(Unit)), "$a", debuff_name));
                return false;
            end


            -- Ignore debuffs that are in fact buffs
            if (DCR_SKIP_LIST[debuff_name]) then
                Dcr_errln( string.gsub( string.gsub(DCR_IGNORE_STRING, "$t", UnitName(Unit)), "$a", debuff_name));
                Go_On = false; -- == continue
            end

            -- If we are in combat lets see if there is any debuffs we cn afford to not remove until ths fight is over
            if (UnitAffectingCombat("player")) then
                if (DCR_SKIP_BY_CLASS_LIST[UClass]) then
                    if (DCR_SKIP_BY_CLASS_LIST[UClass][debuff_name]) then
                        -- these are just ones you don't care about by class
                        Dcr_errln( string.gsub( string.gsub(DCR_IGNORE_STRING, "$t", UnitName(Unit)), "$a", debuff_name));
                        Go_On = false; -- == continue
                    end
                end
            end
            -- }}}

            if (Go_On) then
                -- it is one we "care" about... lets catalog it -- {{{ --
                if (debuff_type and debuff_type ~= "") then
                    if (debuff_type == DCR_MAGIC) then
                        Dcr_debug( "it's magic");
                        Magic_Count = Magic_Count + 1;
                    elseif (debuff_type == DCR_DISEASE) then
                        Dcr_debug( "it's disease");
                        Disease_Count = Disease_Count + 1;
                    elseif (debuff_type == DCR_POISON) then
                        Dcr_debug( "it's poison");
                        Poison_Count = Poison_Count + 1;
                    elseif (debuff_type == DCR_CURSE) then
                        Dcr_debug( "it's curse");
                        Curse_Count = Curse_Count + 1
                    else
                        Dcr_debug( "it's unknown - "..debuff_type);
                    end
                else
                    Dcr_debug( "it's untyped");
                end
                -- }}}
            end
        end

        i = i + 1;
    end

    local res = false;
    -- order these in the way you find most important
    if (not res) then
        res = Dcr_Cure_Magic(Magic_Count, Unit);
    end
    if (not res) then
        res = Dcr_Cure_Curse( Curse_Count, Unit);
    end
    if (not res) then
        res = Dcr_Cure_Poison( Poison_Count, Unit);
    end
    if (not res) then
        res = Dcr_Cure_Disease( Disease_Count, Unit);
    end

    return res;
end

function Dcr_Cure_Magic(Magic_Count, Unit)
    Dcr_debug( "magic count "..Magic_Count);
    if (DCR_CAN_CURE_MAGIC) then
        Dcr_debug( "Can cure magic");
    end
    if (DCR_CAN_CURE_ENEMY_MAGIC) then
        Dcr_debug( "Can cure enemy magic");
    end

    if ( (not (DCR_CAN_CURE_MAGIC or DCR_CAN_CURE_ENEMY_MAGIC)) or (Magic_Count == 0) ) then
        -- here is no magical effects... or
        -- we can't cure magic don't bother going forward
        Dcr_debug( "no magic");
        return false;
    end
    Dcr_debug( "curing magic");

    if ( DCR_CAN_CURE_ENEMY_MAGIC and UnitIsCharmed(Unit) and UnitCanAttack("player", Unit) ) then
        -- unit is charmed... and has magic debuffs on them... and we CAN attack it
        -- there is a good chance that it is the mind controll type spell
        -- the checking for the UnitCanAttack is due to the mind controlled pets and other enslaves
        if (DCR_SPELL_ENEMY_MAGIC_2[1] ~= 0 ) and (Dcr_Saved.AlwaysUseBestSpell or (Magic_Count > 1) or (DCR_SPELL_MAGIC_1[1] == 0)) then
            return Dcr_Cast_CureSpell( DCR_SPELL_ENEMY_MAGIC_2, Unit, DCR_CHARMED, true);
        else
            return Dcr_Cast_CureSpell( DCR_SPELL_ENEMY_MAGIC_1, Unit, DCR_CHARMED, true);
        end
    elseif (DCR_CAN_CURE_MAGIC and (not UnitCanAttack("player", Unit))) then
        -- we can cure magic... and the unit is NOT hostile to us (we can't cast on those)
        if (DCR_SPELL_MAGIC_2[1] ~= 0 ) and (Dcr_Saved.AlwaysUseBestSpell or (Magic_Count > 1) or (DCR_SPELL_MAGIC_1[1] == 0)) then
            return Dcr_Cast_CureSpell( DCR_SPELL_MAGIC_2, Unit, DCR_MAGIC, DCR_CAN_CURE_ENEMY_MAGIC);
        else
            return Dcr_Cast_CureSpell( DCR_SPELL_MAGIC_1, Unit, DCR_MAGIC, DCR_CAN_CURE_ENEMY_MAGIC);
        end
    -- else
        -- what it means:
        -- not (DCR_CAN_CURE_ENEMY_MAGIC and UnitIsCharmed(Unit) and UnitCanAttack("player", Unit)
        -- not (DCR_CAN_CURE_MAGIC and (not UnitCanAttack("player", Unit)))
        --
        -- !DCR_CAN_CURE_ENEMY_MAGIC or !UnitIsCharmed(Unit) or !UnitCanAttack("player", Unit)   =====> not MC or we can't attack it
        -- AND
        -- !DCR_CAN_CURE_MAGIC UnitCanAttack("player", Unit)
        --
        -- we can't cure enemy magic
        -- Dcr_errln("Something strange happened :/ Dcr_Cure_Magic() did nothing :-o");
    end
    return false;
end

function Dcr_Cure_Curse( Curse_Count, Unit)
    if ( (not DCR_CAN_CURE_CURSE) or (Curse_Count == 0)) then
        -- no curses or no curse curing spells
        Dcr_debug( "no curse");
        return false;
    end
    Dcr_debug( "curing curse");

    if (UnitIsCharmed(Unit)) then
        -- we can not cure a mind contorolled player
        return;
    end

    if (DCR_SPELL_CURSE ~= 0) then
        return Dcr_Cast_CureSpell(DCR_SPELL_CURSE, Unit, DCR_CURSE, false);
    end
    return false;
end

function Dcr_Cure_Poison(Poison_Count, Unit)
    if ( (not DCR_CAN_CURE_POISON) or (Poison_Count == 0)) then
        -- here is no magical effects... or
        -- we can't cure magic don't bother going forward
        Dcr_debug( "no poison");
        return false;
    end
    Dcr_debug( "curing poison");

    if (UnitIsCharmed(Unit)) then
        -- we can not cure a mind contorolled player
        return;
    end

    if (Dcr_Saved.Check_For_Abolish and Dcr_CheckUnitForBuff(Unit, DCR_SPELL_ABOLISH_POISON)) then
        return false;
    end

    if (DCR_SPELL_POISON_2[1] ~= 0 ) and (Dcr_Saved.AlwaysUseBestSpell or (Poison_Count > 1)) then
        return Dcr_Cast_CureSpell( DCR_SPELL_POISON_2, Unit, DCR_POISON, false);
    else
        return Dcr_Cast_CureSpell( DCR_SPELL_POISON_1, Unit, DCR_POISON, false);
    end
end

function Dcr_Cure_Disease(Disease_Count, Unit)
    if ( (not DCR_CAN_CURE_DISEASE) or (Disease_Count == 0)     ) then
        -- here is no magical effects... or
        -- we can't cure magic don't bother going forward
        Dcr_debug( "no disease");
        return false;
    end
    Dcr_debug( "curing disease");

    if (UnitIsCharmed(Unit)) then
        -- we can not cure a mind contorolled player
        return;
    end

    if (Dcr_Saved.Check_For_Abolish and Dcr_CheckUnitForBuff(Unit, DCR_SPELL_ABOLISH_DISEASE)) then
        return false;
    end

    if (DCR_SPELL_DISEASE_2[1] ~= 0 ) and (Dcr_Saved.AlwaysUseBestSpell or (Disease_Count > 1)) then
        return Dcr_Cast_CureSpell( DCR_SPELL_DISEASE_2, Unit, DCR_DISEASE, false);
    else
        return Dcr_Cast_CureSpell( DCR_SPELL_DISEASE_1, Unit, DCR_DISEASE, false);
    end
end

function Dcr_Cast_CureSpell( spellID, Unit, AfflictionType, ClearCurrentTarget)
    local name = UnitName(Unit);


    if (spellID[1] == 0) then
        Dcr_errln("Stupid call to Dcr_Cast_CureSpell() with a null spellID!!!");
        return false;
    end

    -- check to see if we are in range
    if (
            (spellID[2] ~= BOOKTYPE_PET) and
            (not Dcr_UnitInRange(Unit))
        ) then

        -- XXX We do not blacklist out of range people any more, they don't prevent anything from hapenning
        -- it will just spam a bit if there are a lot of them...

        -- Dcr_Blacklist_Array[Unit] = nil; -- attempt to remove it
        -- Dcr_Blacklist_Array[Unit] = Dcr_Saved.CureBlacklist; -- add it to the blacklist, hopefully at the end

        -- DCR_ThisCleanBlaclisted[Unit] = true;

        Dcr_errln( string.gsub( string.gsub(DCR_OUT_OF_RANGE, "$t", name), "$a", AfflictionType));
        -- DCR_ThisNumberOoRUnits = DCR_ThisNumberOoRUnits + 1;
        return false;
    else
        Dcr_debug_bis("Unit is in range or we don't check for range");
    end
    Dcr_debug_bis( "try to cast: "..spellID[1] .." - ".. spellID[2]);
    local spellName = GetSpellName(spellID[1], spellID[2]);
    Dcr_debug( "casting - "..spellName);

    -- clear the target if it will interfear
    if (ClearCurrentTarget) then
        -- it can target enemys... do don't target ANYTHING else
        if ( not UnitIsUnit( "target", Unit) ) then
            ClearTarget();
        end
    elseif ( UnitIsFriend( "player", "target") ) then
        -- we can accedenally cure friendly targets...
        if ( not UnitIsUnit( "target", Unit) ) then
            -- and we want to cure someone else who is not targeted
            ClearTarget();
        end
    end

            -- ClearTarget();
    Dcr_println( string.gsub( string.gsub( string.gsub(DCR_CLEAN_STRING, "$t", string.upper(name)), "$a", AfflictionType), "$s", spellName));
    Dcr_debug_bis( "casting on " .. UnitName(Unit) .. " -- " .. Unit);
    if (spellID[2] == BOOKTYPE_PET) then
        TargetUnit(Unit);
    end

    -- if a spell is awaiting for a target, cancel it
    if ( SpellIsTargeting()) then
        SpellStopTargeting();
    end

    -- cast the spell
    Dcr_Casting_Spell_On = Unit;
    CastSpell(spellID[1],  spellID[2]);

    -- if the spell doesn't need a target
    if (Dcr_RestoreTarget and spellID[2] == BOOKTYPE_PET) then
        TargetUnit("playertarget"); -- restore previous target 
    else
        -- if the cast succeeded
        if (SpellIsTargeting()) then
            SpellTargetUnit(Unit);
        end
    end

    -- if the targeting failed (still waiting for a target), cancel the cast
    if ( SpellIsTargeting()) then
        SpellStopTargeting();
    end

    return true;
end


function Dcr_SpellCastFailed()
    if (
        Dcr_Casting_Spell_On        -- a cast failed and we were casting on someone
        and not (
            UnitIsUnit(Dcr_Casting_Spell_On, "player")   -- we do not blacklist ourself
            or
            (
                -- we do not blacklist people in the priority list
                Dcr_Saved.DoNot_Blacklist_Prio_List and Dcr_IsInPriorList ( UnitName(Dcr_Casting_Spell_On) )
            )
                )
        ) then

        Dcr_Blacklist_Array[Dcr_Casting_Spell_On] = nil;
        Dcr_Blacklist_Array[Dcr_Casting_Spell_On] = Dcr_Saved.CureBlacklist;
        DCR_ThisCleanBlaclisted[Dcr_Casting_Spell_On] = true;
    end
end

function Dcr_SpellWasCast()
    Dcr_Casting_Spell_On = nil;
end

function Dcr_GetUnitBuff (Unit, i)
    Dcr_ScanningTooltipTextLeft1:SetText("");

    Dcr_ScanningTooltip:SetUnitBuff(Unit, i); -- fill this fake thing with buff info

    local buff_name = Dcr_ScanningTooltipTextLeft1:GetText(); -- get the buff name
    -- local buff_type = Dcr_ScanningTooltipTextRight1:GetText();

    return buff_name;

end

function Dcr_GetUnitDebuff  (Unit, i)
    -- Dcr_ScanningTooltip:ClearLines(); -- clear the tooltip
    Dcr_ScanningTooltipTextRight1:SetText("");
    Dcr_ScanningTooltipTextLeft1:SetText("");

    Dcr_ScanningTooltip:SetUnitDebuff(Unit, i); -- fill this fake thing with Debuff info
    
    local debuff_name = Dcr_ScanningTooltipTextLeft1:GetText(); -- get the debuff name
    local debuff_type = Dcr_ScanningTooltipTextRight1:GetText(); -- get the debuff type

    return debuff_name, debuff_type;
end

function Dcr_CheckUnitForBuff(Unit, BuffName)
    for i = 1, DCR_MAXBUFFS do
        local buff_texture = UnitBuff(Unit, i);

        if buff_texture then

            local found_buff_name = Dcr_GetUnitBuff(Unit, i);

            if (found_buff_name == BuffName) then
                return true;
            end


        else
            break; -- XXX to verify
        end
    end
    return false;
end

function Dcr_CheckUnitStealth(Unit)
    if (Dcr_Saved.Ingore_Stealthed) then
        for BuffName in DCR_INVISIBLE_LIST do
            if Dcr_CheckUnitForBuff(Unit, BuffName) then
                return true;
            end
        end
    end
    return false;
end

function Dcr_IsSpellUsable ()
    local CuringActionSlot = Dcr_FindCureingActionSlot(Dcr_CuringAction_Icons);

    if (CuringActionSlot ~= 0) then
        return IsUsableAction(CuringActionSlot);
    else
        return true;
    end
end

-------------------------------------------------------------------------------
-- now the range functions....
-------------------------------------------------------------------------------
--[[
function Dcr_UnitInRange(Unit)
    -- this means that we are not even fraking close...
    -- don't bother going further
    if (not UnitIsVisible(Unit)) then
        return false;
    end

    -- Dcr_Saved.RangeCheck = false; -- disable this option for now
    if (not Dcr_Saved.RangeCheck) then
        -- we are not bothering to check for range.
        -- this will keep a pally from breaking swing most times
        return true;
    end

    local Dcr_Range_Slot = Dcr_FindCureingActionSlot(Dcr_CuringAction_Icons);

    if (Dcr_Range_Slot ~= 0) then
        TargetUnit(Unit);
        if UnitIsUnit("target", Unit) then
            return (IsActionInRange(Dcr_Range_Slot) == 1);
        else
            return false; -- if we can't target... then its out of range
        end
    end

    -- we don't know... return true just in case
    return true;

end
--]]


function Dcr_UnitInRange(Unit)
--    if (not Dcr_Saved.RangeCheck) then
--      return true;
--    end
    if(CheckInteractDistance(Unit, 4)) then
        return true;
    end
    return false;
end


local Dcr_LastFoundSlot = nil;
local Dcr_LastActionBarScan = 0;
function Dcr_FindCureingActionSlot(iconArray)

    if (Dcr_PlayerClass == DCR_CLASS_WARLOCK) then
        return 0;
    end

    if (Dcr_LastFoundSlot) then
        if (HasAction(Dcr_LastFoundSlot)) then
            icon = GetActionTexture(Dcr_LastFoundSlot);
            if (iconArray[icon]) then
                if (GetActionText(Dcr_LastFoundSlot) == nil) then
                    local spellName = iconArray[icon];

                    Dcr_ScanningTooltipTextLeft1:SetText("");

                    Dcr_ScanningTooltip:SetAction(Dcr_LastFoundSlot);

                    local slotName = Dcr_ScanningTooltipTextLeft1:GetText();

                    if (spellName == slotName) then
                        Dcr_debug_bis("cache used!");
                        return Dcr_LastFoundSlot;
                    end
                end
            end
        end
    end

    -- This is to prevent a freeze issue
    if (GetTime() - Dcr_LastActionBarScan < 30) then
        return 0;
    end
    local i = 0;
    for i = DCR_START_SLOT, DCR_END_SLOT do
        if (HasAction(i)) then
            icon = GetActionTexture(i);
            if (iconArray[icon]) then
                if (GetActionText(i) == nil) then
                    local spellName = iconArray[icon];

                    Dcr_ScanningTooltipTextLeft1:SetText("");

                    Dcr_ScanningTooltip:SetAction(i);

                    local slotName = Dcr_ScanningTooltipTextLeft1:GetText();

                    if (spellName == slotName) then
                        Dcr_LastFoundSlot = i;
                        return i;
                    end
                else
                    Dcr_debug_bis("GetActionText: " .. GetActionText(i) );
                end
            end
        end
    end
    Dcr_LastActionBarScan = GetTime();
    Dcr_errln("Decursive can't find your curing spell in your action bars, next try in 30 seconds...");
    return 0;
end

-------------------------------------------------------------------------------
-- the UI code
-------------------------------------------------------------------------------

function Dcr_PriorityListEntryTemplate_OnClick()
    local id = this:GetID();
    if (id) then
        if (this.Priority) then
            Dcr_RemoveIDFromPriorityList(id);
        else
            Dcr_RemoveIDFromSkipList(id);
        end
    end
    this.UpdateYourself = true;
    
end

function Dcr_PriorityListEntryTemplate_OnUpdate()
    if (this.UpdateYourself) then
        this.UpdateYourself = false;
        local baseName = this:GetName();
        local NameText = getglobal(baseName.."Name");

        local id = this:GetID();
        if (id) then
            local name
            if (this.Priority) then
                name = Dcr_Saved.PriorityList[id];
            else
                name = Dcr_Saved.SkipList[id];
            end
            if (name) then
                NameText:SetText(id.." - "..name);
            else
                NameText:SetText("Error - ID Invalid!");
            end
        else
            NameText:SetText("Error - No ID!");
        end
    end
end

function Dcr_PriorityListFrame_OnUpdate()
    if (this.UpdateYourself) then
        this.UpdateYourself = false;
        local baseName = this:GetName();
        local up = getglobal(baseName.."Up");
        local down = getglobal(baseName.."Down");


        local size = table.getn(Dcr_Saved.PriorityList);

        if (size < 11 ) then
            this.Offset = 0;
            up:Hide();
            down:Hide();
        else
            if (this.Offset <= 0) then
                this.Offset = 0;
                up:Hide();
                down:Show();
            elseif (this.Offset >= (size - 10)) then
                this.Offset = (size - 10);
                up:Show();
                down:Hide();
            else
                up:Show();
                down:Show();
            end
        end

        local i;
        for i = 1, 10 do
            local id = ""..i;
            if (i < 10) then
                id = "0"..i;
            end
            local btn = getglobal(baseName.."Index"..id);

            btn:SetID( i + this.Offset);
            btn.UpdateYourself = true;

            if (i <= size) then
                btn:Show();
            else
                btn:Hide();
            end
        end
end

end

function Dcr_SkipListFrame_OnUpdate()
    if (this.UpdateYourself) then
        this.UpdateYourself = false;
        local baseName = this:GetName();
        local up = getglobal(baseName.."Up");
        local down = getglobal(baseName.."Down");


        local size = table.getn(Dcr_Saved.SkipList);

        if (size < 11 ) then
            this.Offset = 0;
            up:Hide();
            down:Hide();
        else
            if (this.Offset <= 0) then
                this.Offset = 0;
                up:Hide();
                down:Show();
            elseif (this.Offset >= (size - 10)) then
                this.Offset = (size - 10);
                up:Show();
                down:Hide();
            else
                up:Show();
                down:Show();
            end
        end

        local i;
        for i = 1, 10 do
            local id = ""..i;
            if (i < 10) then
                id = "0"..i;
            end
            local btn = getglobal(baseName.."Index"..id);

            btn:SetID( i + this.Offset);
            btn.UpdateYourself = true;

            if (i <= size) then
                btn:Show();
            else
                btn:Hide();
            end
        end
    end

end

function Dcr_DisplayTooltip(Message, RelativeTo)
    DcrDisplay_Tooltip:SetOwner(RelativeTo, "ANCHOR_TOPRIGHT");
    DcrDisplay_Tooltip:ClearLines();
    DcrDisplay_Tooltip:SetText(Message);
    DcrDisplay_Tooltip:Show();
end

function Dcr_PopulateButtonPress()
    local addFunction = this:GetParent().addFunction;

    if (this.ClassType) then
        -- for the class type stuff... we do party

        local _, pclass = UnitClass("player");
        if (pclass == this.ClassType) then
            addFunction("player");
        end

        _, pclass = UnitClass("party1");
        if (pclass == this.ClassType) then
            addFunction("party1");
        end
        _, pclass = UnitClass("party2");
        if (pclass == this.ClassType) then
            addFunction("party2");
        end
        _, pclass = UnitClass("party3");
        if (pclass == this.ClassType) then
            addFunction("party3");
        end
        _, pclass = UnitClass("party4");
        if (pclass == this.ClassType) then
            addFunction("party4");
        end
    end

    local max = GetNumRaidMembers();
    local i;
    if (max > 0) then
        for i = 1, max do
            local _, _, pgroup, _, _, pclass = GetRaidRosterInfo(i);

            if (this.ClassType) then
                if (pclass == this.ClassType) then
                    addFunction("raid"..i);
                end
            end
            if (this.GroupNumber) then
                if (pgroup == this.GroupNumber) then
                    addFunction("raid"..i);
                end
            end
        end
    end

end

function Dcr_DebuffTemplate_OnEnter()
    DcrDisplay_Tooltip:SetOwner(this, "ANCHOR_CURSOR");
    DcrDisplay_Tooltip:ClearLines();
    DcrDisplay_Tooltip:SetUnitDebuff(this.unit,this.debuff); -- OK
    DcrDisplay_Tooltip:Show();
end

function Dcr_LiveListItem_OnUpdate()
    if (this.UpdateMe) then
        this.UpdateMe = false;
        local texture = UnitDebuff(this.unit,this.debuff);
        if (texture) then
            local baseFrame = this:GetName();
            getglobal(baseFrame.."DebuffIcon"):SetTexture(texture);

            getglobal(baseFrame.."Name"):SetText(UnitName(this.unit));

            local debuff_name, debuff_type = Dcr_GetUnitDebuff(this.unit, this.debuff);

            getglobal(baseFrame.."Affliction"):SetText(debuff_name);
        end
    end
end

local Dcr_SoundPlayed = false;
function Dcr_PlaySound ()
    if (Dcr_Saved.PlaySound and not Dcr_SoundPlayed) then
        -- good sounds: Sound\\Doodad\\BellTollTribal.wav
        --              Sound\\interface\\AuctionWindowOpen.wav
        PlaySoundFile("Sound\\Doodad\\BellTollTribal.wav");
        Dcr_SoundPlayed = true;
    end
end

local Dcr_timeLeft = 0;
function Dcr_AfflictedListFrame_OnUpdate(elapsed)


    -- XXX find the use of this block
    if Dcr_Saved.Amount_Of_Afflicted < 1 then
        Dcr_Saved.Amount_Of_Afflicted = 1;
    elseif Dcr_Saved.Amount_Of_Afflicted > DCR_MAX_LIVE_SLOTS then
        Dcr_Saved.Amount_Of_Afflicted = DCR_MAX_LIVE_SLOTS;
    end

    Dcr_timeLeft = Dcr_timeLeft - elapsed;
    if (Dcr_timeLeft <= 0) then
        Dcr_timeLeft = Dcr_Saved.ScanTime;
        local index = 1;
        local Dcr_Unit_Array = Dcr_GetUnitArray();

        if (DCR_CAN_CURE_ENEMY_MAGIC) then
            for _, unit in Dcr_Unit_Array do
                if (index > Dcr_Saved.Amount_Of_Afflicted) then
                    break;
                end
                if (UnitIsVisible(unit)) then
                    -- if the unit is even close by
                    if (UnitIsCharmed(unit)) then
                        -- if the unit is mind controlled
                        if (Dcr_ScanUnit(unit, index)) then
                            if (index == 1) then
                                Dcr_PlaySound();
                            end
                            index = index + 1;
                        end
                    end
                end
            end
        end

        -- Dcr_debug(" normal loop");
        for _, unit in Dcr_Unit_Array do
            if (index > Dcr_Saved.Amount_Of_Afflicted) then
                break;
            end
            if (UnitIsVisible(unit)) then
                if (not UnitIsCharmed(unit)) then
                    -- if the unit is even close by
                    if (Dcr_ScanUnit(unit, index)) then
                        if (index == 1) then
                            Dcr_PlaySound();
                        end
                        index = index + 1;
                    end
                end
            end
        end

        for i = index, DCR_MAX_LIVE_SLOTS do
            if i == 1 then
                Dcr_SoundPlayed = false;
            end
            local item = getglobal("DecursiveAfflictedListFrameListItem"..i);
            item.unit = "player";
            item.debuff = 0;
            item:Hide();
        end

        -- for testing only             
        -- Dcr_UpdateLiveDisplay( 1, "player", 1)

    end
end

function Dcr_ScanUnit( Unit, Index)
    local i = 1;
    while (UnitDebuff(Unit, i)) do

        local debuff_name, debuff_type = Dcr_GetUnitDebuff(Unit, i);

        if (debuff_name ~= "") then

            -- test if we have to ignore this debuf  {{{ --
            if (DCR_IGNORELIST[debuff_name]) then
                -- these are the BAD ones... the ones that make the target immune... abort the user
                Dcr_debug( string.gsub( string.gsub(DCR_IGNORE_STRING, "$t", UnitName(Unit)), "$a", debuff_name));
                return false;
            end

            if (DCR_SKIP_LIST[debuff_name]) then
                -- these are just ones you don't care about
                Dcr_debug( string.gsub( string.gsub(DCR_IGNORE_STRING, "$t", UnitName(Unit)), "$a", debuff_name));
                break;
            end
            if (UnitAffectingCombat("player")) then
                if (DCR_SKIP_BY_CLASS_LIST[UClass]) then
                    if (DCR_SKIP_BY_CLASS_LIST[UClass][debuff_name]) then
                        -- these are just ones you don't care about by class
                        Dcr_debug( string.gsub( string.gsub(DCR_IGNORE_STRING, "$t", UnitName(Unit)), "$a", debuff_name));
                        break;
                    end
                end
            end
            -- }}}

            if (debuff_type and debuff_type ~= "") then
                -- // {{{ --
                if (debuff_type == DCR_MAGIC) then
                    if (UnitIsCharmed(Unit)) then
                        if (DCR_CAN_CURE_ENEMY_MAGIC) then
                            Dcr_UpdateLiveDisplay(Index, Unit, i);
                            return true;
                        end
                    else
                        if (DCR_CAN_CURE_MAGIC) then
                            Dcr_UpdateLiveDisplay(Index, Unit, i);
                            return true;
                        end
                    end
                elseif (debuff_type == DCR_DISEASE) then
                    if (DCR_CAN_CURE_DISEASE) then
                        Dcr_UpdateLiveDisplay(Index, Unit, i);
                        return true;
                    end
                elseif (debuff_type == DCR_POISON) then
                    if (DCR_CAN_CURE_POISON) then
                        Dcr_UpdateLiveDisplay(Index, Unit, i);
                        return true;
                    end
                elseif (debuff_type == DCR_CURSE) then
                    if (DCR_CAN_CURE_CURSE) then
                        Dcr_UpdateLiveDisplay(Index, Unit, i);
                        return true;
                    end
                end
                -- // }}}
            end

        end -- end of if (debuff_name ~= "")

        i = i + 1;
    end
    return false;
end

function Dcr_UpdateLiveDisplay( Index, Unit, DebuffIndex)
    local item = getglobal("DecursiveAfflictedListFrameListItem"..Index);
    item.unit = Unit;
    item.debuff = DebuffIndex;
    item.UpdateMe = true;
    item:Show();

    item = getglobal("DecursiveAfflictedListFrameListItem"..Index.."Debuff");
    item.unit = Unit;
    item.debuff = DebuffIndex;

    item = getglobal("DecursiveAfflictedListFrameListItem"..Index.."ClickMe");
    item.unit = Unit;
    item.debuff = DebuffIndex;
end

function Dcr_AmountOfAfflictedSlider_OnShow()
    getglobal(this:GetName().."High"):SetText("15");
    getglobal(this:GetName().."Low"):SetText("5");

    getglobal(this:GetName() .. "Text"):SetText(DCR_AMOUNT_AFFLIC .. Dcr_Saved.Amount_Of_Afflicted);

    this:SetMinMaxValues(1, 15);
    this:SetValueStep(1);
    this:SetValue(Dcr_Saved.Amount_Of_Afflicted);
end

function Dcr_AmountOfAfflictedSlider_OnValueChanged()
    Dcr_Saved.Amount_Of_Afflicted = this:GetValue();
    getglobal(this:GetName() .. "Text"):SetText(DCR_AMOUNT_AFFLIC .. Dcr_Saved.Amount_Of_Afflicted);
end

function Dcr_CureBlacklistSlider_OnShow()
    getglobal(this:GetName().."High"):SetText("20");
    getglobal(this:GetName().."Low"):SetText("1");

    getglobal(this:GetName() .. "Text"):SetText(DCR_BLACK_LENGTH .. Dcr_Saved.CureBlacklist);

    this:SetMinMaxValues(1, 20);
    this:SetValueStep(0.1);
    this:SetValue(Dcr_Saved.CureBlacklist);
end

function Dcr_CureBlacklistSlider_OnValueChanged()
    Dcr_Saved.CureBlacklist = this:GetValue() * 10;
    if (Dcr_Saved.CureBlacklist < 0) then
        Dcr_Saved.CureBlacklist = ceil(Dcr_Saved.CureBlacklist - 0.5)
    else
        Dcr_Saved.CureBlacklist = floor(Dcr_Saved.CureBlacklist + 0.5)
    end
    Dcr_Saved.CureBlacklist = Dcr_Saved.CureBlacklist / 10;
    getglobal(this:GetName() .. "Text"):SetText(DCR_BLACK_LENGTH .. Dcr_Saved.CureBlacklist);
end

function Dcr_ScanTimeSlider_OnShow()
    getglobal(this:GetName().."High"):SetText("1");
    getglobal(this:GetName().."Low"):SetText("0.1");

    getglobal(this:GetName() .. "Text"):SetText(DCR_SCAN_LENGTH .. Dcr_Saved.ScanTime);

    this:SetMinMaxValues(0.1, 1);
    this:SetValueStep(0.1);
    this:SetValue(Dcr_Saved.ScanTime);
end

function Dcr_ScanTimeSlider_OnValueChanged()
    Dcr_Saved.ScanTime = this:GetValue() * 10;
    if (Dcr_Saved.ScanTime < 0) then
        Dcr_Saved.ScanTime = ceil(Dcr_Saved.ScanTime - 0.5)
    else
        Dcr_Saved.ScanTime = floor(Dcr_Saved.ScanTime + 0.5)
    end
    Dcr_Saved.ScanTime = Dcr_Saved.ScanTime / 10;
    getglobal(this:GetName() .. "Text"):SetText(DCR_SCAN_LENGTH .. Dcr_Saved.ScanTime);
end