vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:
UIPanelWindows["CT_RaidTrackerFrame"] = { area = "left", pushable = 1 };
CT_RAIDTRACKER_RAIDS = "Raids: %d";
CT_RaidTracker_Online = { };

CT_RaidTracker_Version = "v1.2";
CT_RaidTracker_Events = { };

CT_RaidTracker_LastPage = { };

CT_RaidTracker_SortOptions = {
        ["method"] = "name",
        ["way"] = "asc",
        ["itemmethod"] = "looted",
        ["itemway"] = "asc",
        ["itemfilter"] = 1,
        ["playerraidway"] = "desc",
        ["playeritemfilter"] = 1,
        ["playeritemmethod"] = "name",
        ["playeritemway"] = "asc",
        ["itemhistorymethod"] = "name",
        ["itemhistoryway"] = "asc"
};

CT_RaidTracker_ItemTextures = {
        ["Head"] = "INV_Helmet_22",
        ["Neck"] = "INV_Jewelry_Necklace_11",
        ["Shoulder"] = "INV_Shoulder_23",
        ["Back"] = "INV_Misc_Cape_16",
        ["Chest"] = "INV_Chest_Chain_05",
        ["Shirt"] = "INV_Shirt_Black_01",
        ["Shield"] = "INV_Shield_05",
        ["Tabard"] = "INV_Misc_TabardPVP_04",
        ["Wrist"] = "INV_Bracer_07",
        ["Two-Hand-Other"] = "INV_Sword_39",
        ["Two-Hand-Sword"] = "INV_Sword_39",
        ["Two-Hand-Staff"] = "INV_Staff_30",
        ["Two-Hand-Polearm"] = "INV_Spear_06",
        ["Two-Hand-Axe"] = "INV_Axe_09",
        ["Two-Hand-Mace"] = "INV_Hammer_04",
        ["Back"] = "INV_Misc_Cape_16",
        ["Off Hand"] = "INV_Misc_Book_06",
        ["Held In Off-hand"] = "INV_Misc_Book_06",
        ["Off Hand-Other"] = "INV_Misc_Wrench_01",
        ["Gun"] = "INV_Weapon_Rifle_01",
        ["Bow"] = "INV_Weapon_Bow_01",
        ["Wand"] = "INV_Wand_02",
        ["Projectile"] = "INV_Ammo_Arrow_01",
        ["Thrown"] = "INV_Spear_07",
        ["Hands"] = "INV_Gauntlets_16",
        ["Waist"] = "INV_Belt_02",
        ["Legs"] = "INV_Pants_11",
        ["Feet"] = "INV_Boots_05",
        ["Finger"] = "INV_Jewelry_Ring_30",
        ["Trinket"] = "INV_Jewelry_Talisman_10",
        ["Other"] = "INV_Misc_Gear_08",
        ["Special-Sword"] = "INV_Sword_18",
        ["Special-Dagger"] = "INV_Weapon_ShortBlade_11",
        ["Special-Mace"] = "INV_Hammer_17",
        ["Special-Axe"] = "INV_Axe_09",
        ["Special-Fist Weapon"] = "INV_Misc_MonsterClaw_04",
        ["Special-Shield"] = "INV_Shield_05",
};

CT_RaidTracker_RarityTable = {
        ["ff9d9d9d"] = -1,
        ["ffffffff"] = 0,
        ["ff1eff00"] = 1,
        ["ff0070dd"] = 2,
        ["ffa335ee"] = 3,
        ["ffff8000"] = 4
};


function CT_RaidTracker_GetTime(dDate)
        if ( not dDate ) then
                return nil;
        end
        local _, _, mon, day, year, hr, min, sec = string.find(dDate, "(%d+)/(%d+)/(%d+) (%d+):(%d+):(%d+)");
        local table = date("*t");
        table["month"] = tonumber(mon);
        table["year"] = tonumber("20" .. year);
        table["day"] = tonumber(day);
        table["hour"] = tonumber(hr);
        table["min"] = tonumber(min);
        table["sec"] = tonumber(sec);
        return time(table);
end

function CT_RaidTracker_SortRaidTable()
        table.sort(
                CT_RaidTracker_RaidLog,
                function(a1, a2)
                        if ( a1 and a2 ) then
                                return CT_RaidTracker_GetTime(a1.key) > CT_RaidTracker_GetTime(a2.key);
                        end
                end
        );
end

function CT_RaidTracker_GetRaidTitle(id, hideid)
        if ( CT_RaidTracker_RaidLog[id] and CT_RaidTracker_RaidLog[id].key ) then
                local _, _, mon, day, year, hr, min, sec = string.find(CT_RaidTracker_RaidLog[id].key, "(%d+)/(%d+)/(%d+) (%d+):(%d+):(%d+)");
                if ( mon ) then
                        local months = {
                                "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                        };
                        if ( hideid ) then
                                return months[tonumber(mon)] .. " " .. day .. " '" .. year .. ", " .. hr .. ":" .. min;
                        else
                                return "[" .. (getn(CT_RaidTracker_RaidLog)-id+1) .. "] " .. months[tonumber(mon)] .. " " .. day .. " '" .. year .. ", " .. hr .. ":" .. min;
                        end
                else
                        return "";
                end
        end
        return "";
end

function CT_RaidTracker_SaveNote(id)
        local text = CT_RaidTrackerEditNoteFrameNoteEB:GetText();
        if ( strlen(text) == 0 ) then
                text = nil;
        end
        if ( CT_RaidTrackerEditNoteFrame.type == "item" ) then
                CT_RaidTracker_RaidLog[id]["Loot"][CT_RaidTrackerEditNoteFrame.itemid]["note"] = text;

        elseif ( CT_RaidTrackerEditNoteFrame.type == "raid" ) then
                CT_RaidTracker_RaidLog[id]["note"] = text;

        else
                CT_RaidTracker_RaidLog[id]["Notes"][CT_RaidTrackerEditNoteFrame.playerid] = text;

        end
        CT_RaidTracker_Update();
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_EditNote_OnShow()
        local text;
        if ( this.type == "raid" ) then
                text = CT_RaidTracker_RaidLog[this.id]["note"];
        elseif ( this.type == "item" ) then
                text = CT_RaidTracker_RaidLog[this.id]["Loot"][this.itemid]["note"];
        else
                text = CT_RaidTracker_RaidLog[this.id]["Notes"][this.playerid];
        end
        if ( text ) then
                getglobal(this:GetName() .. "NoteEB"):SetText(text);
                getglobal(this:GetName() .. "NoteEB"):HighlightText();
        else
                getglobal(this:GetName() .. "NoteEB"):SetText("");
        end

        getglobal(this:GetName() .. "Editing"):SetText("Editing note for " .. this.type .. " \"|c" .. this.color .. "" .. this.text .. "|r\"");
end

function CT_RaidTracker_Update()
        if ( getn(CT_RaidTracker_LastPage) > 0 ) then
                CT_RaidTrackerFrameBackButton:Enable();
        else
                CT_RaidTrackerFrameBackButton:Disable();
        end
        if ( getn(CT_RaidTracker_RaidLog) > 0 ) then
                if ( CT_RaidTrackerFrame.selected ) then
                        local selected;
                        if ( not CT_RaidTracker_RaidLog[CT_RaidTrackerFrame.selected] ) then
                                while ( not selected ) do
                                        if ( CT_RaidTrackerFrame.selected < 1 ) then
                                                selected = 1;
                                                CT_RaidTrackerFrame.selected = nil;
                                        else
                                                CT_RaidTrackerFrame.selected = CT_RaidTrackerFrame.selected - 1;
                                                if ( CT_RaidTracker_RaidLog[CT_RaidTrackerFrame.selected] ) then
                                                        selected = 2;
                                                end
                                        end
                                end
                        end
                        if ( not selected or selected == 2 ) then
                                if ( not CT_RaidTracker_RaidLog[CT_RaidTrackerFrame.selected] or getn(CT_RaidTracker_RaidLog[CT_RaidTrackerFrame.selected]["Loot"]) == 0 ) then
                                        CT_RaidTrackerFrame.type = "raids";
                                        CT_RaidTrackerFrameViewButton:Disable();
                                else
                                        CT_RaidTrackerFrameViewButton:Enable();
                                end
                        end
                end

                CT_EmptyRaidTrackerFrame:Hide();
                CT_RaidTrackerFrameNoteButton:Enable();
                CT_RaidTrackerFrameDeleteButton:Enable();

                local hasItem;
                for k, v in CT_RaidTracker_RaidLog do
                        for key, val in v["Loot"] do
                                if ( val["player"] == CT_RaidTrackerFrame.player ) then
                                        hasItem = 1;    
                                        break;
                                end
                        end
                        if ( hasItem ) then
                                break;
                        end
                end

                if ( CT_RaidTrackerFrame.type == "raids" or not CT_RaidTrackerFrame.type ) then
                        CT_RaidTrackerFrameViewButton:SetText("View Items");
                elseif ( CT_RaidTrackerFrame.type == "items" ) then
                        CT_RaidTrackerFrameViewButton:SetText("View Players");
                elseif ( CT_RaidTrackerFrame.type == "player" ) then
                        if ( not hasItem ) then
                                CT_RaidTrackerFrameViewButton:Disable();
                        else
                                CT_RaidTrackerFrameViewButton:Enable();
                        end
                        CT_RaidTrackerFrameViewButton:SetText("View Loot");
                        CT_RaidTrackerFrameNoteButton:Disable();
                        CT_RaidTrackerFrameDeleteButton:Disable();
                elseif ( CT_RaidTrackerFrame.type == "playeritems" ) then
                        CT_RaidTrackerFrameViewButton:SetText("View Raids");
                        CT_RaidTrackerFrameNoteButton:Disable();
                        CT_RaidTrackerFrameDeleteButton:Disable();
                        if ( not hasItem ) then
                                CT_RaidTrackerFrame.type = "player";
                                CT_RaidTracker_Update();
                                CT_RaidTracker_UpdateView();
                        end
                elseif ( CT_RaidTrackerFrame.type == "itemhistory" ) then
                        CT_RaidTrackerFrameNoteButton:Disable();
                        CT_RaidTrackerFrameDeleteButton:Disable();
                        CT_RaidTrackerFrameViewButton:Disable();
                end
        else
                CT_EmptyRaidTrackerFrame:Show();
                CT_RaidTrackerDetailScrollFramePlayers:Hide();
                CT_RaidTrackerDetailScrollFrameItems:Hide();
                CT_RaidTrackerDetailScrollFramePlayer:Hide();
                CT_RaidTrackerFrameNoteButton:Disable();
                CT_RaidTrackerFrameDeleteButton:Disable();
                CT_RaidTrackerFrameViewButton:Disable();
        end

        local numRaids = getn(CT_RaidTracker_RaidLog);
        local numEntries = numRaids;

        -- Update Quest Count
        CT_RaidTrackerQuestCount:SetText(format(CT_RAIDTRACKER_RAIDS, numRaids));

        -- ScrollFrame update
        FauxScrollFrame_Update(CT_RaidTrackerListScrollFrame, numEntries, 6, 16, nil, nil, nil, CT_RaidTrackerHighlightFrame, 293, 316 );
        
        -- Update the quest listing
        CT_RaidTrackerHighlightFrame:Hide();
        for i=1, 6, 1 do
                local title = getglobal("CT_RaidTrackerTitle" .. i);
                local normaltext = getglobal("CT_RaidTrackerTitle" .. i .. "NormalText");
                local highlighttext = getglobal("CT_RaidTrackerTitle" .. i .. "HighlightText");
                local disabledtext = getglobal("CT_RaidTrackerTitle" .. i .. "DisabledText");
                local highlight = getglobal("CT_RaidTrackerTitle" .. i .. "Highlight");

                local index = i + FauxScrollFrame_GetOffset(CT_RaidTrackerListScrollFrame); 
                if ( index <= numEntries ) then
                        local raidTitle = CT_RaidTracker_GetRaidTitle(index);
                        local raidTag = CT_RaidTracker_RaidLog[index]["note"];
                        if ( not raidTag ) then
                                raidTag = "";
                        else
                                raidTag = " (" .. raidTag .. ")";
                        end
                        if ( raidTitle ) then
                                title:SetText(raidTitle .. raidTag);
                        else
                                title:SetText("");
                        end
                        title:Show();
                        -- Place the highlight and lock the highlight state
                        if ( CT_RaidTrackerFrame.selected and CT_RaidTrackerFrame.selected == index ) then
                                CT_RaidTrackerSkillHighlight:SetVertexColor(1, 1, 0);
                                CT_RaidTrackerHighlightFrame:SetPoint("TOPLEFT", "CT_RaidTrackerTitle"..i, "TOPLEFT", 0, 0);
                                CT_RaidTrackerHighlightFrame:Show();
                                title:LockHighlight();
                        else
                                title:UnlockHighlight();
                        end
                        
                else
                        title:Hide();
                end

        end
end

function CT_RaidTracker_SelectRaid(id)
        local raidid = id + FauxScrollFrame_GetOffset(CT_RaidTrackerListScrollFrame);
        CT_RaidTracker_GetPage();
        CT_RaidTrackerFrame.selected = raidid;
        if ( getn(CT_RaidTracker_RaidLog[raidid]["Loot"]) == 0 or ( CT_RaidTrackerFrame.type and CT_RaidTrackerFrame.type ~= "items" ) ) then
                CT_RaidTrackerFrame.type = "raids";
        end

        CT_RaidTracker_UpdateView();
        CT_RaidTracker_Update();
end

function CT_RaidTracker_ShowInfo(player)
        CT_RaidTracker_GetPage();

        CT_RaidTrackerFrame.type = "player";
        CT_RaidTrackerFrame.player = player;
        CT_RaidTrackerFrame.selected = nil;
        
        CT_RaidTracker_Update();
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_GetItemType(link)
        local types = {
                ["Head"] = 1,
                ["Neck"] = 1,
                ["Shoulder"] = 1,
                ["Back"] = 1,
                ["Chest"] = 1,
                ["Shirt"] = 1,
                ["Tabard"] = 1,
                ["Wrist"] = 1,
                ["Two-Hand"] = 1,
                ["One-Hand"] = 1,
                ["Main Hand"] = 1,

                ["Off Hand"] = 1,
                ["Held In Off-hand"] = 1,
                ["Gun"] = 1,
                ["Bow"] = 1,
                ["Wand"] = 1,
                ["Projectile"] = 1,
                ["Thrown"] = 1,
                ["Hands"] = 1,
                ["Waist"] = 1,
                ["Legs"] = 1,
                ["Feet"] = 1,
                ["Finger"] = 1,
                ["Trinket"] = 1
        };

        local special = {
                ["Fist Weapon"] = 1,
                ["Dagger"] = 1,
                ["Shield"] = 1,
                ["Sword"] = 1,
                ["Axe"] = 1,
                ["Polearm"] = 1,
                ["Mace"] = 1,
                ["Staff"] = 1
        };
        for i = 1, 30, 1 do
                getglobal("CT_RTTooltipTextLeft" .. i):SetText("");
                getglobal("CT_RTTooltipTextLeft" .. i):Hide();
                getglobal("CT_RTTooltipTextRight" .. i):SetText("");
                getglobal("CT_RTTooltipTextRight" .. i):Hide();
        end
        CT_RTTooltip:SetHyperlink(link);
        for i = 2, min(CT_RTTooltip:NumLines(), 5), 1 do
                local textleft = getglobal("CT_RTTooltipTextLeft" .. i);
                local textright = getglobal("CT_RTTooltipTextRight" .. i);
                if ( textleft and types[textleft:GetText()] ) then
                        if ( ( textleft:GetText() == "Off Hand" or textleft:GetText() == "Main Hand" or textleft:GetText() == "One-Hand" or textleft:GetText() == "Two-Hand" ) and strlen(textright:GetText()) > 0 ) then
                                if ( special[textright:GetText()] ) then
                                        if ( textleft:GetText() == "Two-Hand" ) then
                                                return "Two-Hand-" .. textright:GetText();
                                        else
                                                return "Special-" .. textright:GetText();
                                        end
                                else
                                        return textleft:GetText().."-Other";
                                end
                        else
                                return textleft:GetText();
                        end
                elseif ( textright and types[textright:GetText()] ) then
                        return textright:GetText();
                end
        end
        return "Other";
end

function CT_RaidTracker_Delete(id, type, typeid)
        if ( type == "raid" ) then
                table.remove(CT_RaidTracker_RaidLog, id);
                if ( id == CT_RaidTracker_GetCurrentRaid ) then
                        CT_RaidTracker_GetCurrentRaid = nil;
                end
                if ( CT_RaidTrackerFrame.selected == id ) then
                        CT_RaidTrackerFrame.selected = CT_RaidTrackerFrame.selected - 1;
                        if ( CT_RaidTrackerFrame.selected < 1 ) then
                                CT_RaidTrackerFrame.selected = 1;
                        end
                        CT_RaidTrackerFrame.type = "raids";
                end
        elseif ( type == "item" ) then
                table.remove(CT_RaidTracker_RaidLog[id]["Loot"], typeid);
        elseif ( type == "player" ) then
                for key, val in CT_RaidTracker_RaidLog[id]["Join"] do
                        if ( val["player"] == typeid ) then
                                CT_RaidTracker_RaidLog[id]["Join"][key] = nil;
                        end
                end
                for key, val in CT_RaidTracker_RaidLog[id]["Leave"] do
                        if ( val["player"] == typeid ) then
                                CT_RaidTracker_RaidLog[id]["Leave"][key] = nil;
                        end
                end
        end
        CT_RaidTracker_Update();
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_Sort(tbl, method, way)
        if ( way == "asc" ) then
                table.sort(
                        tbl,
                        function(a1, a2)
                                return a1[method] < a2[method];
                        end
                );
        else
                table.sort(
                        tbl,
                        function(a1, a2)
                                return a1[method] > a2[method];
                        end
                );
        end
        return tbl;
end

function CT_RaidTracker_SortPlayerRaids(id)
        if ( CT_RaidTrackerFrame.type == "itemhistory" ) then
                local table = { "name", "looter" };

                if ( CT_RaidTracker_SortOptions["itemhistorymethod"] == table[id] ) then
                        if ( CT_RaidTracker_SortOptions["itemhistoryway"] == "asc" ) then
                                CT_RaidTracker_SortOptions["itemhistoryway"] = "desc";
                        else
                                CT_RaidTracker_SortOptions["itemhistoryway"] = "asc";
                        end
                else
                        CT_RaidTracker_SortOptions["itemhistoryway"] = "asc";
                        CT_RaidTracker_SortOptions["itemhistorymethod"] = table[id];
                end
        else            
                if ( CT_RaidTracker_SortOptions["playerraidway"] == "asc" ) then
                        CT_RaidTracker_SortOptions["playerraidway"] = "desc";
                else
                        CT_RaidTracker_SortOptions["playerraidway"] = "asc";
                end
        end
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_CompareItems(a1, a2)
        -- This function could probably be better, but I can't think of any better way while still maintaining functionality

        local filter, method, way = CT_RaidTracker_SortOptions["itemfilter"], CT_RaidTracker_SortOptions["itemmethod"], CT_RaidTracker_SortOptions["itemway"];
        if ( CT_RaidTrackerFrame.type == "playeritems" ) then
                filter, method, way = CT_RaidTracker_SortOptions["playeritemfilter"], CT_RaidTracker_SortOptions["playeritemmethod"], CT_RaidTracker_SortOptions["playeritemway"];
        end

        -- Check to see if it matches the rarity requirements
        if ( not CT_RaidTracker_RarityTable[a1["item"]["c"]] or CT_RaidTracker_RarityTable[a1["item"]["c"]] < filter ) then
                return false;
        elseif ( CT_RaidTracker_RarityTable[a2["item"]["c"]] < filter ) then
                return true;
        end

        if ( method == "name" ) then
                local c1, c2 = a1["item"]["name"], a2["item"]["name"];
                if ( c1 == c2 ) then
                        c1, c2 = a1["player"], a2["player"];
                end
                if ( way == "asc" ) then
                        return c1 < c2;
                else
                        return c1 > c2;
                end
        elseif ( method == "looter" ) then
                local c1, c2 = a1["player"], a2["player"];
                if ( c1 == c2 ) then
                        c1, c2 = CT_RaidTracker_RarityTable[a2["item"]["c"]], CT_RaidTracker_RarityTable[a1["item"]["c"]];
                        if ( c1 == c2 ) then
                                c1, c2 = a1["item"]["name"], a2["item"]["name"];
                        end
                end
                if ( way == "asc" ) then
                        return c1 < c2;
                else
                        return c1 > c2;
                end
        elseif ( method == "looted" ) then
                if ( way == "asc" ) then
                        return CT_RaidTracker_GetTime(a1["time"]) < CT_RaidTracker_GetTime(a2["time"]);
                else
                        return CT_RaidTracker_GetTime(a1["time"]) > CT_RaidTracker_GetTime(a2["time"]);
                end
        else
                local c1, c2 = CT_RaidTracker_RarityTable[a1["item"]["c"]], CT_RaidTracker_RarityTable[a2["item"]["c"]];
                if ( c1 == c2 ) then
                        c1, c2 = a1["item"]["name"], a2["item"]["name"];
                        if ( c1 == c2 ) then
                                c1, c2 = a1["player"], a2["player"];
                        else
                                return c1 < c2;
                        end
                end
                if ( way == "asc" ) then
                        return c1 < c2;
                else
                        return c1 > c2;
                end
        end
end

function CT_RaidTracker_SortItem(tbl, method, way)

                table.sort(
                        tbl,
                        CT_RaidTracker_CompareItems
                );

        return tbl;
end

function CT_RaidTracker_SortItemBy(id)
        local table = { "name", "looted", "looter", "rarity" };
        local prefix = "";
        if ( CT_RaidTrackerFrame.type == "playeritems" ) then
                prefix = "player";
        end
        if ( CT_RaidTracker_SortOptions[prefix.."itemmethod"] == table[id] ) then
                if ( CT_RaidTracker_SortOptions[prefix.."itemway"] == "asc" ) then
                        CT_RaidTracker_SortOptions[prefix.."itemway"] = "desc";
                else
                        CT_RaidTracker_SortOptions[prefix.."itemway"] = "asc";
                end
        else
                CT_RaidTracker_SortOptions[prefix.."itemmethod"] = table[id];
                CT_RaidTracker_SortOptions[prefix.."itemway"] = "asc";
        end
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_SortBy(id)
        local table = { "name", "join", "leave" };
        if ( CT_RaidTracker_SortOptions["method"] == table[id] ) then
                if ( CT_RaidTracker_SortOptions["way"] == "asc" ) then
                        CT_RaidTracker_SortOptions["way"] = "desc";
                else
                        CT_RaidTracker_SortOptions["way"] = "asc";
                end
        else
                CT_RaidTracker_SortOptions["method"] = table[id];
                if ( table[id] ~= "leave" ) then
                        CT_RaidTracker_SortOptions["way"] = "asc";
                else
                        CT_RaidTracker_SortOptions["way"] = "desc";
                end
        end
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_UpdateView()
        if ( CT_EmptyRaidTrackerFrame:IsVisible() ) then
                return;
        end
        local raidid = CT_RaidTrackerFrame.selected;
        local num = 1;
        while ( getglobal("CT_RaidTrackerItem" .. num) ) do
                getglobal("CT_RaidTrackerItem" .. num):Hide();
                num = num + 1;
        end
        if ( CT_RaidTrackerFrame.type == "raids" or not CT_RaidTrackerFrame.type ) then
                CT_RaidTrackerDetailScrollFramePlayers:Show();
                CT_RaidTrackerDetailScrollFramePlayer:Hide();
                CT_RaidTrackerDetailScrollFrameItems:Hide();
                local players, str, num = { }, "", 0;
                if ( CT_RaidTracker_RaidLog[raidid] ) then

                        local playerIndexes = { };
                        for key, val in CT_RaidTracker_RaidLog[raidid]["Join"] do
                                if ( val["player"] ) then
                                        local id = playerIndexes[val["player"]];
                                        local time = CT_RaidTracker_GetTime(val["time"]);
                                        if ( not id or time < players[id]["join"] ) then
                                                
                                                if ( playerIndexes[val["player"]] ) then
                                                        players[id] = {
                                                                ["join"] = time,
                                                                ["name"] = val["player"]
                                                        };
                                                else
                                                        tinsert(players, {
                                                                ["join"] = time,
                                                                ["name"] = val["player"]
                                                        });
                                                        playerIndexes[val["player"]] = getn(players);
                                                end
                                        end
                                        id = playerIndexes[val["player"]];
                                        if ( not players[id]["lastjoin"] or players[id]["lastjoin"] < time ) then
                                                players[id]["lastjoin"] = time;
                                        end
                                end
                        end
                        for key, val in CT_RaidTracker_RaidLog[raidid]["Leave"] do
                                local id = playerIndexes[val["player"]];
                                local time = CT_RaidTracker_GetTime(val["time"]);
                                if ( id ) then
                                        if ( ( not players[id]["leave"] or time > players[id]["leave"] ) and time >= players[id]["lastjoin"] ) then
                                                players[id]["leave"] = time;
                                        end
                                end
                        end
                        for k, v in players do
                                if ( not v["leave"] ) then
                                        -- Very ugly hack, I know :(
                                        players[k]["leave"] = 99999999999;
                                end
                        end
                        players = CT_RaidTracker_Sort(players, CT_RaidTracker_SortOptions["method"], CT_RaidTracker_SortOptions["way"]);
                        num = 0;
                        for key, val in players do
                                num = num + 1;
                                local name = getglobal("CT_RaidTrackerPlayerLine" .. num .. "Name");
                                local number = getglobal("CT_RaidTrackerPlayerLine" .. num .. "Number");
                                local join = getglobal("CT_RaidTrackerPlayerLine" .. num .. "Join");
                                local leave = getglobal("CT_RaidTrackerPlayerLine" .. num .. "Leave");
                                if ( name ) then
                                        getglobal("CT_RaidTrackerPlayerLine" .. num):Show();
                                        name:SetText(val["name"]);
                                        local iNumber = num;
                                        if ( iNumber < 10 ) then
                                                iNumber = "  " .. iNumber;
                                        end
                                        number:SetText(iNumber);
                                        join:SetText(date("%I:%M%p", val["join"]));
                                        if ( val["leave"] == 99999999999 ) then
                                                leave:SetText("");
                                        else
                                                leave:SetText(date("%I:%M%p", val["leave"]));
                                        end
                                end
                                
                        end
                        for i = num+1, 100, 1 do
                                getglobal("CT_RaidTrackerPlayerLine" .. i):Hide();
                        end
                end
                CT_RaidTrackerRaidText:SetText(str);
                CT_RaidTrackerParticipantsText:SetText("Participants (" .. num .. "):");
                CT_RaidTrackerDetailScrollFramePlayers:UpdateScrollChildRect();
        elseif ( CT_RaidTrackerFrame.type == "items" ) then
                CT_RaidTrackerDetailScrollFramePlayers:Hide();
                CT_RaidTrackerDetailScrollFramePlayer:Hide();
                CT_RaidTrackerDetailScrollFrameItems:Show();
                local numItems, numHidden = 0, 0;
                if ( CT_RaidTracker_RaidLog[raidid] ) then
                        local loot = CT_RaidTracker_SortItem(CT_RaidTracker_RaidLog[raidid]["Loot"], CT_RaidTracker_SortOptions["itemmethod"], CT_RaidTracker_SortOptions["itemway"]);
                        for key, val in loot do
                                local _, _, lootTime = string.find(val["time"], " (%d+:%d+:%d+)$");
                                if ( lootTime ) then
                                        local found;
                                        local i = 1;
                                        if ( not found ) then
                                                if ( CT_RaidTracker_RarityTable[val["item"]["c"]] >= CT_RaidTracker_SortOptions["itemfilter"] ) then
                                                        numItems = numItems + 1;
                                                        if ( getglobal("CT_RaidTrackerItem" .. numItems) ) then
                                                                getglobal("CT_RaidTrackerItem" .. numItems).raidid = CT_RaidTrackerFrame.selected;
                                                                getglobal("CT_RaidTrackerItem" .. numItems).itemid = numItems;
                                                                getglobal("CT_RaidTrackerItem" .. numItems).itemname = val["item"]["name"];
                                                                getglobal("CT_RaidTrackerItem" .. numItems):Show();
                                                                if ( val["item"]["count"] and val["item"]["count"] > 1 ) then
                                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "Count"):Show();
                                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "Count"):SetText(val["item"]["count"]);
                                                                else
                                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "Count"):Hide();
                                                                end
                                                                if ( val["item"]["type"] and CT_RaidTracker_ItemTextures[val["item"]["type"]] ) then
                                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "IconTexture"):SetTexture("Interface\\Icons\\" .. CT_RaidTracker_ItemTextures[val["item"]["type"]]);
                                                                else
                                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "IconTexture"):SetTexture("Interface\\Icons\\" .. CT_RaidTracker_ItemTextures["Other"]);
                                                                end
                                                                local color = val["item"]["c"];
                                                                if ( color == "ff1eff00" ) then
                                                                        color = "11009900";
                                                                end
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "Description"):SetText("|c" .. color .. val["item"]["name"] .. "|r\nLooted by: " .. val["player"]);
        
                                                                if ( val["note"] ) then
                                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "NoteNormalTexture"):SetVertexColor(1, 1, 1);
                                                                else
                                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "NoteNormalTexture"):SetVertexColor(0.5, 0.5, 0.5);
                                                                end
                                                        end
                                                else
                                                        numHidden = numHidden + 1;
                                                end
                                        end
                                end
                        end
                end
                for i = numItems+1, 255, 1 do
                        getglobal("CT_RaidTrackerItem" .. i):Hide();
                end
                if ( numHidden == 0 ) then
                        CT_RaidTrackerItemsText:SetText("Items (" .. numItems .. "):");
                else
                        CT_RaidTrackerItemsText:SetText("Items (" .. numItems .. "/" .. numHidden + numItems .. ")");
                end
                UIDropDownMenu_SetSelectedID(CT_RaidTrackerRarityDropDown, CT_RaidTracker_SortOptions["itemfilter"]);
                local colors = {
                        "|c001eff00Uncommon|r",
                        "|c000070ddRare|r",
                        "|c00a335eeEpic|r",
                        "|c00ff8000Legendary"
                };
                        
                CT_RaidTrackerRarityDropDownText:SetText(colors[CT_RaidTracker_SortOptions["itemfilter"]]);
                CT_RaidTrackerDetailScrollFrameItems:UpdateScrollChildRect();
        elseif ( CT_RaidTrackerFrame.type == "player" ) then
                CT_RaidTrackerDetailScrollFramePlayers:Hide();
                CT_RaidTrackerDetailScrollFramePlayer:Show();
                CT_RaidTrackerDetailScrollFrameItems:Hide();
                CT_RaidTrackerPlayerRaidTabLooter:Hide();
                CT_RaidTrackerPlayerRaidTab1:SetWidth(300);
                CT_RaidTrackerPlayerRaidTab1Middle:SetWidth(290);
                local name = CT_RaidTrackerFrame.player;

                local raids = { };
                for k, v in CT_RaidTracker_RaidLog do
                        local isInRaid;
                        for key, val in v["Join"] do
                                if ( val["player"] == name ) then
                                        tinsert(raids, { k, v });
                                        break;
                                end
                        end
                end
                
                table.sort(
                        raids,
                        function(a1, a2)
                                if ( CT_RaidTracker_SortOptions["playerraidway"] == "asc" ) then
                                        return CT_RaidTracker_GetTime(a1[2]["key"]) < CT_RaidTracker_GetTime(a2[2]["key"]);
                                else
                                        return CT_RaidTracker_GetTime(a1[2]["key"]) > CT_RaidTracker_GetTime(a2[2]["key"]);
                                end
                        end
                );

                for k, v in raids do
                        local raid = getglobal("CT_RaidTrackerPlayerRaid" .. k);
                        raid.raidid = v[1];
                        raid.playername = name;
                        raid.raidtitle = CT_RaidTracker_GetRaidTitle(v[1], 1);

                        local iNumber = getn(CT_RaidTracker_RaidLog)-v[1]+1;
                        if ( iNumber < 10 ) then
                                iNumber = "  " .. iNumber;
                        end

                        getglobal(raid:GetName() .. "MouseOverLeft"):Hide();
                        getglobal(raid:GetName() .. "MouseOverRight"):Hide();

                        getglobal(raid:GetName() .. "HitAreaLeft"):Hide();
                        getglobal(raid:GetName() .. "HitAreaRight"):Hide();
                        getglobal(raid:GetName() .. "HitArea"):Show();
                        getglobal(raid:GetName() .. "Note"):Hide();
                        getglobal(raid:GetName() .. "NoteButton"):Show();
                        getglobal(raid:GetName() .. "DeleteButton"):Show();
                        getglobal(raid:GetName() .. "DeleteText"):Show();

                        getglobal(raid:GetName() .. "Number"):SetText(iNumber);
                        getglobal(raid:GetName() .. "Name"):SetWidth(200);
                        getglobal(raid:GetName() .. "Name"):SetText(CT_RaidTracker_GetRaidTitle(v[1], 1));

                        if ( v[2]["Notes"][name] ) then
                                getglobal(raid:GetName() .. "NoteButtonNormalTexture"):SetVertexColor(1, 1, 1);
                        else
                                getglobal(raid:GetName() .. "NoteButtonNormalTexture"):SetVertexColor(0.5, 0.5, 0.5);
                        end
                        raid:Show();
                end
                for i = getn(raids)+1, 255, 1 do
                        getglobal("CT_RaidTrackerPlayerRaid" .. i):Hide();
                end
                CT_RaidTrackerPlayerText:SetText(name .. "'s Raids (" .. getn(raids) .. "):");
                CT_RaidTrackerDetailScrollFramePlayer:UpdateScrollChildRect();
        elseif ( CT_RaidTrackerFrame.type == "itemhistory" ) then
                CT_RaidTrackerDetailScrollFramePlayers:Hide();
                CT_RaidTrackerDetailScrollFramePlayer:Show();
                CT_RaidTrackerDetailScrollFrameItems:Hide();
                CT_RaidTrackerPlayerRaidTabLooter:Show();
                CT_RaidTrackerPlayerRaidTab1:SetWidth(163);
                CT_RaidTrackerPlayerRaidTab1Middle:SetWidth(155);

                local name, totalItems = CT_RaidTrackerFrame.itemname, 0;

                local items = { };
                for k, v in CT_RaidTracker_RaidLog do
                        for key, val in v["Loot"] do
                                if ( val["item"]["name"] == name ) then
                                        tinsert(items, { k, v, val });
                                        if ( val["item"]["count"] ) then
                                                totalItems = totalItems + val["item"]["count"];
                                        else
                                                totalItems = totalItems + 1;
                                        end
                                end
                        end
                end
                
                table.sort(
                        items,
                        function(a1, a2)
                                if ( CT_RaidTracker_SortOptions["itemhistorymethod"] == "looter" ) then
                                        if ( CT_RaidTracker_SortOptions["itemhistoryway"] == "asc" ) then
                                                return a1[3]["player"] < a2[3]["player"];
                                        else
                                                return a1[3]["player"] > a2[3]["player"];
                                        end
                                else
                                        if ( CT_RaidTracker_SortOptions["itemhistoryway"] == "asc" ) then
                                                return CT_RaidTracker_GetTime(a1[2]["key"]) < CT_RaidTracker_GetTime(a2[2]["key"]);
                                        else
                                                return CT_RaidTracker_GetTime(a1[2]["key"]) > CT_RaidTracker_GetTime(a2[2]["key"]);
                                        end
                                end
                        end
                );

                for k, v in items do
                        local raid = getglobal("CT_RaidTrackerPlayerRaid" .. k);
                        raid.raidid = v[1];

                        local iNumber = getn(CT_RaidTracker_RaidLog)-v[1]+1;
                        if ( iNumber < 10 ) then
                                iNumber = "  " .. iNumber;
                        end
                        getglobal(raid:GetName() .. "MouseOver"):Hide();

                        getglobal(raid:GetName() .. "HitAreaLeft"):Show();
                        getglobal(raid:GetName() .. "HitAreaRight"):Show();
                        getglobal(raid:GetName() .. "HitArea"):Hide();

                        getglobal(raid:GetName() .. "NoteButton"):Hide();
                        getglobal(raid:GetName() .. "Note"):Show();
                        getglobal(raid:GetName() .. "DeleteButton"):Hide();
                        getglobal(raid:GetName() .. "DeleteText"):Hide();

                        getglobal(raid:GetName() .. "Number"):SetText(iNumber);
                        getglobal(raid:GetName() .. "Name"):SetWidth(130);
                        getglobal(raid:GetName() .. "Name"):SetText(CT_RaidTracker_GetRaidTitle(v[1], 1));
                        getglobal(raid:GetName() .. "Note"):SetText(v[3]["player"]);
                        raid:Show();
                end
                for i = getn(items)+1, 255, 1 do
                        getglobal("CT_RaidTrackerPlayerRaid" .. i):Hide();
                end
                CT_RaidTrackerPlayerText:SetText(name .. " (" .. getn(items) .. "/" .. totalItems .. "):");
                CT_RaidTrackerDetailScrollFramePlayer:UpdateScrollChildRect();

        elseif ( CT_RaidTrackerFrame.type == "playeritems" ) then
                CT_RaidTrackerDetailScrollFramePlayers:Hide();
                CT_RaidTrackerDetailScrollFramePlayer:Hide();
                CT_RaidTrackerDetailScrollFrameItems:Show();
                local name = CT_RaidTrackerFrame.player;

                local loot = { };
                for k, v in CT_RaidTracker_RaidLog do
                        for key, val in v["Loot"] do
                                if ( val["player"] == name ) then
                                        tinsert(
                                                loot,
                                                {
                                                        ["note"] = val["note"],
                                                        ["player"] = val["player"],
                                                        ["time"] = val["time"],
                                                        ["item"] = val["item"],
                                                        ["ids"] = { k, key }
                                                }
                                        );
                                end
                        end
                end

                local numItems, numHidden = 0, 0;
                loot = CT_RaidTracker_SortItem(loot, CT_RaidTracker_SortOptions["playeritemmethod"], CT_RaidTracker_SortOptions["playeritemway"]);
                for key, val in loot do
                        local _, _, lootTime = string.find(val["time"], " (%d+:%d+:%d+)$");
                        if ( lootTime ) then
                                local found;
                                local i = 1;
                                if ( not found ) then
                                        if ( CT_RaidTracker_RarityTable[val["item"]["c"]] >= CT_RaidTracker_SortOptions["playeritemfilter"] ) then
                                                numItems = numItems + 1;
                                                if ( getglobal("CT_RaidTrackerItem" .. numItems) ) then
                                                        getglobal("CT_RaidTrackerItem" .. numItems).raidid = val["ids"][1];
                                                        getglobal("CT_RaidTrackerItem" .. numItems).itemid = val["ids"][2];
                                                        getglobal("CT_RaidTrackerItem" .. numItems).itemname = val["item"]["name"];

                                                        getglobal("CT_RaidTrackerItem" .. numItems):Show();
                                                        if ( val["item"]["count"] and val["item"]["count"] > 1 ) then
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "Count"):Show();
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "Count"):SetText(val["item"]["count"]);
                                                        else
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "Count"):Hide();
                                                        end
                                                        if ( val["item"]["type"] and CT_RaidTracker_ItemTextures[val["item"]["type"]] ) then
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "IconTexture"):SetTexture("Interface\\Icons\\" .. CT_RaidTracker_ItemTextures[val["item"]["type"]]);
                                                        else
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "IconTexture"):SetTexture("Interface\\Icons\\" .. CT_RaidTracker_ItemTextures["Other"]);
                                                        end
                                                        local color = val["item"]["c"];
                                                        if ( color == "ff1eff00" ) then
                                                                color = "11009900";
                                                        end
                                                        getglobal("CT_RaidTrackerItem" .. numItems .. "Description"):SetText("|c" .. color .. val["item"]["name"] .. "|r\nLooted " .. CT_RaidTracker_GetRaidTitle(val["ids"][1], 1));

                                                        if ( val["note"] ) then
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "NoteNormalTexture"):SetVertexColor(1, 1, 1);
                                                        else
                                                                getglobal("CT_RaidTrackerItem" .. numItems .. "NoteNormalTexture"):SetVertexColor(0.5, 0.5, 0.5);
                                                        end
                                                end
                                        else
                                                numHidden = numHidden + 1;
                                        end
                                end
                        end
                end
                for i = numItems+1, 255, 1 do
                        getglobal("CT_RaidTrackerItem" .. i):Hide();
                end
                if ( numHidden == 0 ) then
                        CT_RaidTrackerItemsText:SetText(name .. "'s Loot (" .. numItems .. "):");
                else
                        CT_RaidTrackerItemsText:SetText(name .. "'s Loot (" .. numItems .. "/" .. numHidden + numItems .. "):");
                end

                UIDropDownMenu_SetSelectedID(CT_RaidTrackerRarityDropDown, CT_RaidTracker_SortOptions["playeritemfilter"]);
                local colors = {
                        "|c001eff00Uncommon|r",
                        "|c000070ddRare|r",
                        "|c00a335eeEpic|r",
                        "|c00ff8000Legendary"
                };
                        
                CT_RaidTrackerRarityDropDownText:SetText(colors[CT_RaidTracker_SortOptions["playeritemfilter"]]);
                CT_RaidTrackerDetailScrollFrameItems:UpdateScrollChildRect();
        end
end

function CT_RaidTracker_ColorToRGB(str)
        str = strlower(strsub(str, 3));
        local tbl = { };
        tbl[1], tbl[2], tbl[3], tbl[4], tbl[5], tbl[6] = strsub(str, 1, 1), strsub(str, 2, 2), strsub(str, 3, 3), strsub(str, 4, 4), strsub(str, 5, 5), strsub(str, 6, 6);
        
        local highvals = { ["a"] = 10, ["b"] = 11, ["c"] = 12, ["d"] = 13, ["e"] = 14, ["f"] = 15 };
        for k, v in tbl do
                if ( highvals[v] ) then
                        tbl[k] = highvals[v];
                elseif ( tonumber(v) ) then
                        tbl[k] = tonumber(v);
                end
        end
        local r, g, b = (tbl[1]*16+tbl[2])/255, (tbl[3]*16+tbl[4])/255, (tbl[5]*16+tbl[6])/255;
        if ( not r or r > 1 or r < 0 ) then
                r = 1;
        end
        if ( not g or g > 1 or g < 0 ) then
                g = 1;
        end
        if ( not b or b > 1 or b < 0 ) then
                b = 1;
        end
        return r, g, b;
end

function CT_RaidTracker_GetColorString(str)
        if ( not str ) then
                return 1, 1, 1;
        end
        local playerClass = UnitClass("player");
        local playerLevel = UnitLevel("player");
        local classArmor = {
                ["Warrior"] = { ["Cloth"] = 1, ["Leather"] = 1, ["Mail"] = 1, ["Plate"] = 40 },
                ["Paladin"] = { ["Cloth"] = 1, ["Leather"] = 1, ["Mail"] = 1, ["Plate"] = 40 },
                ["Shaman"] = { ["Cloth"] = 1, ["Leather"] = 1, ["Mail"] = 40, ["Plate"] = 61 },
                ["Hunter"] = { ["Cloth"] = 1, ["Leather"] = 1, ["Mail"] = 40, ["Plate"] = 61 },
                ["Rogue"] = { ["Cloth"] = 1, ["Leather"] = 1, ["Mail"] = 61, ["Plate"] = 61 },
                ["Druid"] = { ["Cloth"] = 1, ["Leather"] = 1, ["Mail"] = 61, ["Plate"] = 61 },
                ["Warlock"] = { ["Cloth"] = 1, ["Leather"] = 61, ["Mail"] = 61, ["Plate"] = 61 },
                ["Mage"] = { ["Cloth"] = 1, ["Leather"] = 61, ["Mail"] = 61, ["Plate"] = 61 },
                ["Priest"] = { ["Cloth"] = 1, ["Leather"] = 61, ["Mail"] = 61, ["Plate"] = 61 },
                ["Warlock"] = { ["Cloth"] = 1, ["Leather"] = 61, ["Mail"] = 61, ["Plate"] = 61 }
        };
        
        
        -- Equip:
        if ( string.find(str, "^Equip: ") ) then
                return 0, 1, 0;
                
        -- Use:
        elseif ( string.find(str, "^Use: ") ) then
                return 0, 1, 0;
                
        -- Chance on hit:
        elseif ( string.find(str, "^Chance on hit:") ) then
                return 0, 1, 0;
                
        -- Sets
        elseif ( string.find(str, "^.+ %(%d+/%d+%)$") ) then
                return 1, 0.82, 0, 1;
        
        -- Durability 0/X
        elseif ( string.find(str, "^Durability 0 / %d+$") ) then
                return 1, 0.15, 0.15;
                
        -- Wrong class
        elseif ( string.find(str, "^Classes: ") and not string.find(str, "^Classes: .*" .. playerClass) ) then
                return 1, 0.15, 0.15;
                
        -- Made by
        elseif ( string.find(str, "^<Made by .+>$") ) then
                return 0, 1, 0;
        end     
        
        -- Armor type
        if ( classArmor[playerClass][str] and classArmor[playerClass][str] > playerLevel ) then
                return 1, 0.15, 0.15;
        end
        
        -- Low level
        local iStart, iEnd, level = string.find(str, "^Requires Level (%d+)$");
        if ( level and tonumber(level) > playerLevel ) then
                return 1, 0.15, 0.15;
        end
        return 1, 1, 1;
end

function CT_RaidTrackerItem_SetHyperlink()
        local raidid = this.raidid;
        local lootid = this.itemid;
        if ( CT_RaidTracker_RaidLog[raidid] and CT_RaidTracker_RaidLog[raidid]["Loot"][lootid] ) then
                local item = CT_RaidTracker_RaidLog[raidid]["Loot"][lootid]["item"];
                for i = 1, 30, 1 do
                        getglobal("CT_RTTooltipTextLeft" .. i):SetText("");
                        getglobal("CT_RTTooltipTextLeft" .. i):Hide();
                        getglobal("CT_RTTooltipTextRight" .. i):SetText("");
                        getglobal("CT_RTTooltipTextRight" .. i):Hide();
                end
                if ( not item["tooltip"] ) then
                        local tTooltip = { };
                        CT_RTTooltip:SetHyperlink("item:" .. item["id"]);
                        for i = 1, CT_RTTooltip:NumLines(), 1 do
                                local tl, tr;
                                if ( getglobal("CT_RTTooltipTextLeft" .. i):IsVisible() ) then
                                        tl = getglobal("CT_RTTooltipTextLeft" .. i):GetText();
                                end
                                if ( getglobal("CT_RTTooltipTextRight" .. i):IsVisible() ) then
                                        tr = getglobal("CT_RTTooltipTextRight" .. i):GetText();
                                end
                                tinsert(tTooltip, { ["left"] = tl, ["right"] = tr });
                        end
                        CT_RaidTracker_RaidLog[raidid]["Loot"][lootid]["item"]["tooltip"] = tTooltip;
                        item["tooltip"] = tTooltip;
                end
                for i = 1, 30, 1 do
                        getglobal("CT_RTTooltipTextLeft" .. i):SetText("");
                        getglobal("CT_RTTooltipTextLeft" .. i):Hide();
                        getglobal("CT_RTTooltipTextRight" .. i):SetText("");
                        getglobal("CT_RTTooltipTextRight" .. i):Hide();
                end
                CT_RTTooltip:SetOwner(this, "ANCHOR_RIGHT");
                
                local hasShownSet;
                for k, v in item["tooltip"] do
                        local rl, gl, bl, rr, gr, br;
                        if ( k == 1 ) then
                                rl, gl, bl = CT_RaidTracker_ColorToRGB(item["c"]);
                        end
                        if ( v["right"] ) then
                                rl, gl, bl, hasShownSet = CT_RaidTracker_GetColorString(v["left"]);
                                rr, gr, br = CT_RaidTracker_GetColorString(v["right"]);
                                CT_RTTooltip:AddDoubleLine(v["left"], v["right"], rl, gl, bl, rr, gr, br);
                        else
                                if ( hasShownSet ) then
                                        CT_RTTooltip:AddLine(v["left"], 0.5, 0.5, 0.5); 
                                else
                                        if ( not rl and not gl and not bl ) then
                                                rl, gl, bl, hasShownSet = CT_RaidTracker_GetColorString(v["left"]);
                                        end
                                        CT_RTTooltip:AddLine(v["left"], rl, gl, bl);
                                end
                        end
                end
                CT_RTTooltip:Show();
                return;
        end
end

function CT_RaidTrackerItem_GetChatHyperlink()
        local raidid = this.raidid;
        local lootid = this.itemid;
        if ( IsShiftKeyDown() and ChatFrameEditBox:IsVisible() and CT_RaidTracker_RaidLog[raidid] and CT_RaidTracker_RaidLog[raidid]["Loot"][lootid] ) then
                local item = CT_RaidTracker_RaidLog[raidid]["Loot"][lootid]["item"];
                ChatFrameEditBox:Insert("|c" .. item.c .. "|Hitem:" .. item.id .. "|h[" .. item.name .. "]|h|r");
        end
end

CT_RaidTracker_RaidLog = { };
CT_RaidTracker_GetCurrentRaid = nil;

-- Debug flag

CT_RaidTracker_DebugFlag = nil;

-- Debug function(s)

function CT_RaidTracker_Debug(...)
        if ( CT_RaidTracker_DebugFlag ) then
                local sDebug = "#";
                for i = 1, arg.n, 1 do
                        if ( arg[i] ) then
                                sDebug = sDebug .. arg[i] .. "#";
                        end
                end
                DEFAULT_CHAT_FRAME:AddMessage(sDebug, 1, 0.5, 0);
        end
end
                

-- OnFoo functions

function CT_RaidTracker_OnLoad()
        CT_RaidTrackerTitleText:SetText("CT_RaidTracker " .. CT_RaidTracker_Version);
        -- Register events
        this:RegisterEvent("CHAT_MSG_LOOT");
        this:RegisterEvent("CHAT_MSG_SYSTEM");
        this:RegisterEvent("RAID_ROSTER_UPDATE");
        this:RegisterEvent("PLAYER_ENTERING_WORLD");
        this:RegisterEvent("VARIABLES_LOADED");
end

function CT_RaidTracker_OnEvent(event)
        if ( CT_RaidTracker_UpdateFrame.time and CT_RaidTracker_UpdateFrame.time <= 2 ) then
                tinsert(CT_RaidTracker_Events, event);
                return;
        end
        if ( event == "RAID_ROSTER_UPDATE" or event == "PLAYER_ENTERING_WORLD" ) then
                if ( GetNumRaidMembers() == 0 and event == "RAID_ROSTER_UPDATE" ) then
                        if ( CT_RaidTracker_GetCurrentRaid ) then
                                CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["raidEnd"] = CT_RaidTracker_Date();
                        end
                        CT_RaidTracker_GetCurrentRaid = nil;
                        CT_RaidTracker_Debug("Left raid.");
                        CT_RaidTracker_Offline = { };
                elseif ( not CT_RaidTracker_GetCurrentRaid and GetNumRaidMembers() > 0 and event == "RAID_ROSTER_UPDATE" ) then
                        local sDate = CT_RaidTracker_Date();
                        tinsert(CT_RaidTracker_RaidLog, 1, { 
                                ["Loot"] = { },
                                ["Join"] = { },
                                ["Leave"] = { },
                                ["Notes"] = { },
                                ["key"] = sDate
                        });
                        CT_RaidTracker_SortRaidTable();
                        CT_RaidTracker_GetCurrentRaid = 1;
                        for i = 1, GetNumRaidMembers(), 1 do
                                tinsert(CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Join"],
                                        {
                                                ["player"] = UnitName("raid" .. i),
                                                ["time"] = sDate
                                        }
                                );
                                local name, rank, subgroup, level, class, fileName, zone, online = GetRaidRosterInfo(i);
                                if ( not online ) then
                                        tinsert(CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Leave"],
                                                {
                                                        ["player"] = UnitName("raid" .. i),
                                                        ["time"] = sDate
                                                }
                                        );
                                end
                        end
                        CT_RaidTracker_Debug("Joined new raid at " .. sDate);
                        CT_RaidTracker_Update();
                        CT_RaidTracker_UpdateView();
                end
                if ( not CT_RaidTracker_GetCurrentRaid ) then
                        return;
                end
                local updated;
                for i = 1, GetNumRaidMembers(), 1 do
                        local name, online = UnitName("raid" .. i), UnitIsConnected("raid" .. i);
                        if ( name ) then
                                if ( online ~= CT_RaidTracker_Online[name] ) then
                                        -- Status isn't updated
                                        if ( not CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid] ) then
                                                CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid] = { 
                                                        ["Loot"] = { },
                                                        ["Join"] = { },
                                                        ["Leave"] = { },
                                                        ["Notes"] = { }
                                                };
                                        end
                                        if ( not online ) then
                                                tinsert(CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Leave"],
                                                        {
                                                                ["player"] = name,
                                                                ["time"] = CT_RaidTracker_Date()
                                                        }
                                                );
                                                CT_RaidTracker_Debug("OFFLINE", name);
                                        else
                                                tinsert(CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Join"],
                                                        {
                                                                ["player"] = name,
                                                                ["time"] = CT_RaidTracker_Date()
                                                        }
                                                );
                                                CT_RaidTracker_Debug("ONLINE", name);
                                        end
                                        updated = 1;
                                end
                                CT_RaidTracker_Online[name] = online;
                        end
                end
                if ( updated ) then
                        CT_RaidTracker_Update();
                        CT_RaidTracker_UpdateView();
                end
        elseif ( event == "CHAT_MSG_LOOT" and CT_RaidTracker_GetCurrentRaid ) then
                local sPlayer, sLink;
                local iStart, iEnd, sPlayerName, sItem = string.find(arg1, "([^%s]+) receives loot: (.+)%.");
                if ( sPlayerName ) then
                        sPlayer = sPlayerName;
                        sLink = sItem;
                else
                        local iStart, iEnd, sItem = string.find(arg1, "You receive loot: (.+)%.");
                        if ( sItem ) then
                                sPlayer = UnitName("player");
                                sLink = sItem;
                        end
                end
                
                -- Make sure there is a link
                if ( sLink and sPlayer ) then
                        local sColor, sItem, sName, tTooltip = CT_RaidTracker_GetItemInfo(sLink);
                        if ( sColor and sItem and sName and tTooltip and CT_RaidTracker_RarityTable[sColor] ) then
                                -- Insert into table
                                if ( not CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid] ) then
                                        CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid] = { 
                                                ["Loot"] = { },
                                                ["Join"] = { },
                                                ["Leave"] = { },
                                                ["Notes"] = { }
                                        };
                                end
                                local found;
                                for k, v in CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Loot"] do
                                        if ( v["item"]["name"] == sName and v["player"] == sPlayer ) then
                                                if ( v["item"]["count"] ) then
                                                        CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Loot"][k]["item"]["count"] = v["item"]["count"]+1;
                                                else
                                                        CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Loot"][k]["item"]["count"] = 1;
                                                end
                                                found = 1;
                                                break;
                                        end
                                end
                                if ( not found ) then
                                        tinsert(CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Loot"],
                                                {
                                                        ["player"] = sPlayer,
                                                        ["item"] = {                                            
                                                                ["c"] = sColor,
                                                                ["id"] = sItem,
                                                                ["tooltip"] = tTooltip,
                                                                ["name"] = sName,
                                                                ["count"] = 1,
                                                                ["type"] = CT_RaidTracker_GetItemType("item:"..sItem)
                                                        },
                                                        ["time"] = CT_RaidTracker_Date()
                                                }
                                        );
                                end
                                CT_RaidTracker_Debug(sPlayer, sColor, sItem, sName);
                                CT_RaidTracker_Update();
                                CT_RaidTracker_UpdateView();
                        end
                end
        elseif ( event == "CHAT_MSG_SYSTEM" and UnitName("player") and UnitName("player") ~= "Unknown Being" and CT_RaidTracker_GetCurrentRaid ) then
                local sDate = CT_RaidTracker_Date();
                local iStart, iEnd, sPlayer = string.find(arg1, "([^%s]+) has left the raid group");
                if ( sPlayer and sPlayer ~= UnitName("player") and UnitName("player") and UnitName("player") ~= "Unknown Entity" ) then
                        tinsert(CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Leave"],
                                {
                                        ["player"] = sPlayer,
                                        ["time"] = sDate
                                }
                        );
                        CT_RaidTracker_Debug(sPlayer, "LEFT");
                end
                local iStart, iEnd, sPlayer = string.find(arg1, "([^%s]+) has joined the raid group");
                if ( sPlayer and sPlayer ~= UnitName("player") ) then
                        tinsert(CT_RaidTracker_RaidLog[CT_RaidTracker_GetCurrentRaid]["Join"],
                                {
                                        ["player"] = sPlayer,
                                        ["time"] = sDate
                                }
                        );
                        CT_RaidTracker_Debug(sPlayer, "JOIN");
                end
                CT_RaidTracker_UpdateView();
                CT_RaidTracker_Update();
        elseif ( event == "VARIABLES_LOADED" ) then
                CT_RaidTracker_ConvertFormat();
        end
end

-- Item functions

function CT_RaidTracker_GetItemInfo(sItem)
        -- Thanks to Telo for the following regular expression
        local iStart, iEnd, sColor, sItemName, sName = string.find(sItem, "|c(%x+)|Hitem:(%d+:%d+:%d+:%d+)|h%[(.-)%]|h|r");
        if ( sColor and sItemName and sName ) then
                local tTooltip = { };
                for i = 1, 30, 1 do
                        getglobal("CT_RTTooltipTextLeft" .. i):SetText("");
                        getglobal("CT_RTTooltipTextLeft" .. i):Hide();
                        getglobal("CT_RTTooltipTextRight" .. i):SetText("");
                        getglobal("CT_RTTooltipTextRight" .. i):Hide();
                end
                CT_RTTooltip:SetHyperlink("item:" .. sItemName);
                for i = 1, CT_RTTooltip:NumLines(), 1 do
                        local tl, tr;
                        if ( getglobal("CT_RTTooltipTextLeft" .. i):IsVisible() ) then
                                tl = getglobal("CT_RTTooltipTextLeft" .. i):GetText();
                        end
                        if ( getglobal("CT_RTTooltipTextRight" .. i):IsVisible() ) then
                                tr = getglobal("CT_RTTooltipTextRight" .. i):GetText();
                        end
                        tinsert(tTooltip, { ["left"] = tl, ["right"] = tr });
                end
                return sColor, sItemName, sName, tTooltip;
        end
end

SlashCmdList["RAIDTRACKER"] = function(msg)
        ShowUIPanel(CT_RaidTrackerFrame);
end

SLASH_RAIDTRACKER1 = "/raidtracker";
SLASH_RAIDTRACKER2 = "/rt";

function CT_RaidTracker_Print(msg, r, g, b)
        if ( CT_Print ) then
                CT_Print(msg, r, g, b);
        else
                DEFAULT_CHAT_FRAME:AddMessage(msg, r, g, b);
        end
end

function CT_RaidTracker_RarityDropDown_OnLoad()
        UIDropDownMenu_Initialize(this, CT_RaidTracker_RarityDropDown_Initialize);
        --UIDropDownMenu_SetWidth(130);
        UIDropDownMenu_SetSelectedID(CT_RaidTrackerRarityDropDown, 1);
end

-- Green = 1eff00
-- Blue = 0070dd
-- Purple = a335ee
-- Orange = ff8000

function CT_RaidTracker_RarityDropDown_Initialize()
        local info = {};
        info.text = "|c001eff00Uncommon|r";
        info.func = CT_RaidTracker_RarityDropDown_OnClick;
        UIDropDownMenu_AddButton(info);

        info = {};
        info.text = "|c000070ddRare|r";
        info.func = CT_RaidTracker_RarityDropDown_OnClick;
        UIDropDownMenu_AddButton(info);

        info = {};
        info.text = "|c00a335eeEpic|r";
        info.func = CT_RaidTracker_RarityDropDown_OnClick;
        UIDropDownMenu_AddButton(info);

        info = {};
        info.text = "|c00ff8000Legendary|r";
        info.func = CT_RaidTracker_RarityDropDown_OnClick;
        UIDropDownMenu_AddButton(info);
end


function CT_RaidTracker_RarityDropDown_OnClick()
        UIDropDownMenu_SetSelectedID(CT_RaidTrackerRarityDropDown, this:GetID());
        if ( CT_RaidTrackerFrame.type == "items" ) then
                CT_RaidTracker_SortOptions["itemfilter"] = this:GetID();
        else
                CT_RaidTracker_SortOptions["playeritemfilter"] = this:GetID();
        end
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_SelectItem(name)
        CT_RaidTracker_GetPage();
        CT_RaidTrackerFrame.type = "itemhistory";
        CT_RaidTrackerFrame.itemname = name;
        CT_RaidTrackerFrame.selected = nil;
        CT_RaidTracker_Update();
        CT_RaidTracker_UpdateView();
end

function CT_RaidTracker_GetPage()
        if ( CT_RaidTrackerFrame.type or CT_RaidTrackerFrame.itemname or CT_RaidTrackerFrame.selected or CT_RaidTrackerFrame.player ) then

                tinsert(CT_RaidTracker_LastPage,
                        {
                                ["type"] = CT_RaidTrackerFrame.type,
                                ["itemname"] = CT_RaidTrackerFrame.itemname,
                                ["selected"] = CT_RaidTrackerFrame.selected,
                                ["player"] = CT_RaidTrackerFrame.player
                        }
                );
        end

        if ( getn(CT_RaidTracker_LastPage) > 0 ) then
                CT_RaidTrackerFrameBackButton:Enable();
        else
                CT_RaidTrackerFrameBackButton:Disable();
        end
end

function CT_RaidTracker_GoBack()
        local t = table.remove(CT_RaidTracker_LastPage);

        if ( t ) then
                CT_RaidTrackerFrame.type = t["type"];
                CT_RaidTrackerFrame.itemname = t["itemname"];
                CT_RaidTrackerFrame.selected = t["selected"];
                CT_RaidTrackerFrame.player = t["player"];
                CT_RaidTracker_Update();
                CT_RaidTracker_UpdateView();
        end
        if ( getn(CT_RaidTracker_LastPage) > 0 ) then
                CT_RaidTrackerFrameBackButton:Enable();
        else
                CT_RaidTrackerFrameBackButton:Disable();
        end
end

function CT_RaidTracker_ConvertFormat()
        -- Called because of old format used during development

        for k, v in CT_RaidTracker_RaidLog do
                if ( not v["Notes"] ) then
                        CT_RaidTracker_RaidLog[k]["Notes"] = { };
                end
        end
end

if ( CT_RegisterMod ) then
        CT_RaidTracker_DisplayWindow = function()
                ShowUIPanel(CT_RaidTrackerFrame);
        end
        CT_RegisterMod("Raid Tracker", "Display window", 5, "Interface\\Icons\\INV_Chest_Chain_05", "Displays the Raid Tracker window, which tracks raid loot & attendance.", "switch", "", CT_RaidTracker_DisplayWindow);
else
        CT_RaidTracker_Print("<CTMod> CT_RaidTracker loaded. Type /rt to show the RaidTracker window.", 1, 1, 0);
end

function CT_RaidTracker_FixZero(num)
        if ( num < 10 ) then
                return "0" .. num;
        else
                return num;
        end
end

function CT_RaidTracker_Date()
        local t = date("*t");

        return CT_RaidTracker_FixZero(t.month) .. "/" .. CT_RaidTracker_FixZero(t.day) .. "/" .. strsub(t.year, 3) .. " " .. CT_RaidTracker_FixZero(t.hour) .. ":" .. CT_RaidTracker_FixZero(t.min) .. ":" .. CT_RaidTracker_FixZero(t.sec);
end

function CT_RaidTrackerUpdateFrame_OnUpdate(elapsed)
        if ( this.time ) then
                this.time = this.time + elapsed;
                if ( this.time > 2 ) then
                        this.time = nil;
                        for k, v in CT_RaidTracker_Events do
                                CT_RaidTracker_OnEvent(v);
                        end
                end
        end
end

function CT_RaidTracker_SelectRaidUpdate()
        local numEntries = getn(CT_RaidTracker_RaidLog);

        FauxScrollFrame_Update(CT_RaidTracker_SelectRaidFrameScrollFrame, numEntries, 20, 20);

        for i = 1, 20, 1 do
                local button = getglobal("CT_RaidTracker_SelectRaidFrameRaid" .. i);
                local index = i + FauxScrollFrame_GetOffset(CT_RaidTracker_SelectRaidFrameScrollFrame);
                if ( index <= numEntries ) then
                        if ( numEntries <= 20 ) then
                                button:SetWidth(260);
                        else
                                button:SetWidth(245);
                        end
                        button:Show();
                        getglobal(button:GetName() .. "Name"):SetText(CT_RaidTracker_RaidLog[index].key);
                        --getglobal(button:GetName() .. "Info"):SetText(CT_RADurability_Shown[index][2]);
                else
                        button:Hide();
                end
        end

end

Generated by GNU Enscript 1.6.5.90.