local CURRENT_STATE, CURRENT_EVENT, IS_STANDARD, MATCHING, SENDING, CURRENT_TABLE, CURRENT_SUPERTABLE = "none", "", true, "all", "always", {}, {};
local STATE_FRAMES, MATCH_FRAMES, TYPE_FRAMES, RANDOM_FRAMES = {}, {}, {}, {};
local CREATE_BUTTON, DONE_BUTTON;

local STANDARD_EVENTS = {
    ["Player"] = {
        ["Begin Casting"] = "Sent when you begin casting a spell.  %1: Spell Name",
        ["Finish Casting"] = "Sent when you finish casting a spell.  %1: Spell Name",
        ["Item Usage"] = "Sent when you use an item.  %1: Item Name",
        ["Spell Damage"] = "Sent when a spell or ability does damage.  %1: Spell Name; %2: Target; %3: Amount",
        ["Spell Crit"] = "Sent when a spell or ability crits.  %1: Spell Name; %2: Target; %3: Amount",
        ["Heal"] = "Sent when you heal someone.  %1: Spell Name; %2: Target; %3: Amount",
        ["Heal Crit"] = "Sent when you crit heal someone.  %1: Spell Name; %2: Target; %3: Amount",
        ["Spell Failed"] = "Sent when your spellcast fails.  %1: Spell Name; %2: Reason",
        ["Buff Gain"] = "Sent when you gain a buff.  %1: Buff Name",
        ["Debuff Gain"] = "Sent when you gain a debuff.  %1: Debuff Name",
        ["Buff Fade"] = "Sent when a buff fades from you.  %1: Buff Name",
        ["Debuff Fade"] = "Sent when a debuff fades from you.  %1: Debuff Name",
        ["Spell Active"] = "Sent when a spell or ability becomes available for use (e.g. Overpower).  %1: Spell Name",
    },
    ["Timers"] = {
        ["DoTimer Begin Timer"] = "Sent when a DoTimer timer is made.  %1: Timer Name; %2: Target",
        ["DoTimer Break Early"] = "Sent when a DoTimer timer breaks early.  %1: Timer Name; %2: Target",
        ["DoTimer End Timer"] = "Sent when a DoTimer timer ends.  %1: Timer Name; %2: Target",
        ["Cooldowns Begin Timer"] = "Sent when a Cooldowns timer begins.  %1: Timer Name",
        ["Cooldowns End Timer"] = "Sent when a Cooldowns timer ends.  %1: Timer Name",
    },
    ["Others"] = {
        ["Grouped Buff Gain"] = "Sent when someone you're grouped with gains a buff.  %1: Aura name; %2: Unit Name",
        ["Grouped Buff Fade"] = "Sent when someone you're grouped with loses a buff.  %1: Aura name; %2: Unit Name",
        ["Grouped Debuff Gain"] = "Sent when someone you're grouped with gains a debuff.  %1: Aura name; %2: Unit Name",
        ["Grouped Debuff Fade"] = "Sent when someone you're grouped with loses a debuff.  %1: Aura name; %2: Unit Name",
        ["Enemy Buff Gain"] = "Sent when an enemy gains a buff.  Doesn't fire if it's your target.  %1: Aura name; %2: Unit Name",
        ["Enemy Debuff Gain"] = "Sent when an enemy gains a debuff.  Doesn't fire if it's your target.  %1: Aura name; %2: Unit Name",
        ["Enemy Buff Fade"] = "Sent when an enemy loses a buff.  Doesn't fire if it's your target.  %1: Aura name; %2: Unit Name",
        ["Enemy Debuff Fade"] = "Sent when an enemy loses a debuff.  Doesn't fire if it's your target.  %1: Aura name; %2: Unit Name",
        ["Enemy Target Buff Gain"] = "Sent when your enemy target gains a buff.  %1: Aura name; %2: Unit Name",
        ["Enemy Target Debuff Gain"] = "Sent when your enemy target gains a debuff.  %1: Aura name; %2: Unit Name",
        ["Enemy Target Buff Fade"] = "Sent when your enemy target loses a buff.  %1: Aura name; %2: Unit Name",
        ["Enemy Target Debuff Fade"] = "Sent when your enemy target loses a debuff.  %1: Aura name; %2: Unit Name",
        ["Enemy Begin Casting"] = "Sent when an enemy begins casting a spell.  Doesn't fire if it's your target.  %1: Spell Name; %2: Unit Name",
        ["Enemy Target Begin Casting"] = "Sent when your enemy target begins casting a spell.  %1: Spell Name; %2: Unit Name",
        ["Enemy Player Begin Casting"] = "Sent when an enemy player begins casting a spell.  Doesn't fire if it's your target.  Fires in addition to Enemy Begin Casting.  %1: Spell Name; %2: Unit Name",
        ["Enemy Mob Begin Casting"] = "Sent when an enemy mob begins casting a spell.  Doesn't fire if it's your target.  Fires in addition to Enemy Begin Casting.  %1: Spell Name; %2: Unit Name",
    },
};
local OTHER_EVENTS = {
    ["Aggro Gain"] = "Sent when your current target switches aggro from someone else to you.",
    ["Aggro Loss"] = "Sent when your current target switches aggro from you to someone else.",
    ["DoTimer Time Remaining"] = "Sent every second for each of your DoTimer timers.  %1: Timer Name; %2: Time Remaining",
    ["Cooldowns Time Remaining"] = "Sent every second for each of your Cooldowns timers.  %1: Timer Name; %2: Time Remaining",
    ["PlayerAuras Time Remaining"] = "Sent every second for each of your PlayerAuras timers.  %1: %1: Timer Name; %2: Time Remaining",
    ["Combat Log"] = "Sent when your combat log gets a new entry.  Your match string determines the arguments.",
    ["Chat Log"] = "Sent when your chat log gets a new entry.  Your match string determines the arguments.",
    ["Health"] = "Sent when your health changes.  %1: Current Health",
    ["Mana"] = "Sent when your mana/rage/energy changes.  %1: Current Mana",
    ["Buff Missing"] = "Sent when you don't have specified buffs.  They are checked every 30 seconds.  %1: Buff Name",
    ["Item Cooldown Up"] = "Sent when specified items aren't on cooldown.  They are checked every 30 seconds.  %1: Item Name",
    ["Spell Cooldown Up"] = "Sent when specified items aren't on cooldown.  They are checked every 30 seconds.  %1: Spell Name",
};

local NOTIFICATIONS_TYPES = {
    ["text"] = "Output text to your chat log.",
    ["alert"] = "Create an alert message in the middle of the screen.",
    ["sct"] = "Send a message through SCT, MikSBT, or Blizzard Floating Combat Text (BFCT must be enabled)",
    ["chat"] = "Send a chat message.",
    ["flash"] = "Make the screen flash.",
    ["timer"] = "Create a timer.",
    ["sound"] = "Play a sound.",
};

local chat_types = {
    "say",
    "party",
    "raid",
    "auto",
    "whisper",
    "raid_warning",
    "emote",
};

local flash_colors = {
    "Blue",
    "Green",
    "Orange",
    "Purple",
    "Red",
    "Yellow",
};

local function insertBlank(level)
    level = level or UIDROPDOWNMENU_MENU_LEVEL;
    local info = UIDropDownMenu_CreateInfo();
    info.notCheckable = 1;
    info.text = " ";
    info.isTitle = 1;
    UIDropDownMenu_AddButton(info, level);
end

local function scanTablesForEmpty()
    local self = Notifications;
    local hasEvents = false;
    for event, matches in pairs(self:Get("events")) do
        hasEvents = true;
        local IS_STANDARD = not OTHER_EVENTS[event];
        local hasSubCats = false;
        if IS_STANDARD then
            for _, matching in ipairs({"all", "partial", "exact"}) do
                if matches[matching] then
                    hasSubCats = true;
                    if matching == "all" then
                        local m = matches[matching];
                        local hasSending = false;
                        for _, sending in ipairs({"always", "random"}) do
                            if m[sending] then
                                hasSending = true;
                                if #m[sending] == 0 then
                                    m[sending] = nil;
                                    scanTablesForEmpty();
                                end
                            end
                        end
                        if not hasSending then
                            matches[matching] = nil;
                            scanTablesForEmpty();
                        end
                    else
                        if #matches[matching] == 0 then
                            matches[matching] = nil;
                            scanTablesForEmpty();
                        else
                            for i, m in ipairs(matches[matching]) do
                                local hasSending = false;
                                for _, sending in ipairs({"always", "random"}) do
                                    if m[sending] then
                                        hasSending = true;
                                        if #m[sending] == 0 then
                                            m[sending] = nil;
                                            scanTablesForEmpty();
                                        end
                                    end
                                end
                                if not hasSending then
                                    table.remove(matches[matching], i);
                                    scanTablesForEmpty();
                                end
                            end
                        end
                    end
                end
            end
        else
            if #matches > 0 then
                hasSubCats = true;
                for i, m in ipairs(matches) do
                    local hasSending = false;
                    for _, sending in ipairs({"always", "random"}) do
                        if m[sending] then
                            hasSending = true;
                            if #m[sending] == 0 then
                                m[sending] = nil;
                                scanTablesForEmpty();
                            end
                        end
                    end
                    if not hasSending then
                        table.remove(matches, i);
                        scanTablesForEmpty();
                    end
                end
            end
        end
        if not hasSubCats then
            self:Set("events", event, nil);
            scanTablesForEmpty();
        end
    end
    
    if not hasEvents then
        self:Set("events", nil);
    end
end

local function dropDownCreate()
    CURRENT_STATE = "none";
    for frame in pairs(STATE_FRAMES) do
        frame:Update();
    end
    local info;
    if UIDROPDOWNMENU_MENU_LEVEL == 1 then
        for name, events in AsheylaLib:Alphabetize(STANDARD_EVENTS) do
            info = UIDropDownMenu_CreateInfo();
            info.text = name;
            info.hasArrow = true;
            info.value = events;
            info.notCheckable = true;
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
        
        info = UIDropDownMenu_CreateInfo();
        info.text = "Misc";
        info.hasArrow = true;
        info.value = OTHER_EVENTS;
        info.notCheckable = true;
        UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
    elseif UIDROPDOWNMENU_MENU_LEVEL == 2 then
        local events = UIDROPDOWNMENU_MENU_VALUE;
        for name, tooltip in AsheylaLib:Alphabetize(events) do
            info = UIDropDownMenu_CreateInfo();
            info.text = name;
            info.tooltipTitle = "Description";
            info.tooltipText = tooltip;
            info.notCheckable = true;
            info.func = function()
                CURRENT_STATE = "create";
                CURRENT_EVENT = name;
                CURRENT_TABLE = {};
                CURRENT_SUPERTABLE = {};
                IS_STANDARD = (not OTHER_EVENTS[name]);
                MATCHING = "all";
                SENDING = "always";
                for frame in pairs(STATE_FRAMES) do
                    frame:Update();
                end
                CloseDropDownMenus();
            end
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
    end
end

function dropDownManage()
    CURRENT_STATE = "none";
    for frame in pairs(STATE_FRAMES) do
        frame:Update();
    end
    local info;
    if UIDROPDOWNMENU_MENU_LEVEL == 1 then -- events
        for name, events in AsheylaLib:Alphabetize(Notifications:Get("events")) do
            info = UIDropDownMenu_CreateInfo();
            info.text = name;
            info.notCheckable = true;
            info.hasArrow = true;
            info.value = name;
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
        
        insertBlank();
        info = UIDropDownMenu_CreateInfo();
        info.text = "|cffff0000Delete All";
        info.notCheckable = 1;
        info.func = function()
            Notifications:Set("events", nil);
            CloseDropDownMenus();
        end
        UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
    elseif UIDROPDOWNMENU_MENU_LEVEL == 2 then --gateway to supertables
        CURRENT_EVENT = UIDROPDOWNMENU_MENU_VALUE;
        IS_STANDARD = (not OTHER_EVENTS[UIDROPDOWNMENU_MENU_VALUE]);
        if IS_STANDARD then
            local entries = Notifications:Get("events", UIDROPDOWNMENU_MENU_VALUE);
            if entries.all then
                info = UIDropDownMenu_CreateInfo();
                info.text = "All";
                info.notCheckable = true;
                info.hasArrow = true;
                info.value = "all";
                UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
            end
            if entries.exact then
                info = UIDropDownMenu_CreateInfo();
                info.text = "Exact";
                info.notCheckable = true;
                info.hasArrow = true;
                info.value = "exact";
                UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
            end
            if entries.partial then
                info = UIDropDownMenu_CreateInfo();
                info.text = "Partial";
                info.notCheckable = true;
                info.hasArrow = true;
                info.value = "partial";
                UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
            end
        else
            info = UIDropDownMenu_CreateInfo();
            info.text = "All Entries";
            info.notCheckable = true;
            info.hasArrow = true;
            info.value = Notifications:Get("events", UIDROPDOWNMENU_MENU_VALUE);
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
        
        insertBlank();
        info = UIDropDownMenu_CreateInfo();
        info.text = "|cffff0000Delete All";
        info.notCheckable = 1;
        local c = CURRENT_EVENT;
        info.func = function()
            Notifications:Set("events", c, nil);
            scanTablesForEmpty();
            CloseDropDownMenus();
        end
        UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
    elseif UIDROPDOWNMENU_MENU_LEVEL == 3 then -- supertables
        MATCHING = UIDROPDOWNMENU_MENU_VALUE;
        local t;
        if IS_STANDARD then
            t = Notifications:Get("events", CURRENT_EVENT, MATCHING);
        else
            t = Notifications:Get("events", CURRENT_EVENT);
        end
        if string.find(CURRENT_EVENT, "Aggro") or (IS_STANDARD and MATCHING == "all") then
            info = UIDropDownMenu_CreateInfo();
            info.text = "All Entries";
            info.notCheckable = true;
            info.hasArrow = true;
            info.value = 1;
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        else
            local needs_comp2 = string.find(CURRENT_EVENT, "Time Remaining");
            for i, superTable in ipairs(t) do
                info = UIDropDownMenu_CreateInfo();
                info.text = superTable.comp;
                if needs_comp2 then
                    info.text = info.text .. " (" .. superTable.comp2 .. ")";
                end
                info.notCheckable = true;
                info.hasArrow = true;
                info.value = i;
                UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
            end
        end
        
        if IS_STANDARD then
            insertBlank();
            info = UIDropDownMenu_CreateInfo();
            info.text = "|cffff0000Delete All";
            info.notCheckable = 1;
            local c, m = CURRENT_EVENT, MATCHING;
            info.func = function()
                Notifications:Set("events", c, m, nil);
                scanTablesForEmpty();
                CloseDropDownMenus();
            end
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
    elseif UIDROPDOWNMENU_MENU_LEVEL == 4 then --gateway to tables
        if IS_STANDARD then
            if MATCHING == "all" then
                CURRENT_SUPERTABLE = Notifications:Get("events", CURRENT_EVENT, MATCHING);
                UIDROPDOWNMENU_MENU_VALUE = nil;
            else
                CURRENT_SUPERTABLE = Notifications:Get("events", CURRENT_EVENT, MATCHING)[UIDROPDOWNMENU_MENU_VALUE];
            end
        else
            CURRENT_SUPERTABLE = Notifications:Get("events", CURRENT_EVENT)[UIDROPDOWNMENU_MENU_VALUE];
        end
        if CURRENT_SUPERTABLE.always then
            info = UIDropDownMenu_CreateInfo();
            info.text = "Always";
            info.notCheckable = true;
            info.hasArrow = true;
            info.value = "always";
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
        if CURRENT_SUPERTABLE.random then
            info = UIDropDownMenu_CreateInfo();
            info.text = "Random";
            info.notCheckable = true;
            info.hasArrow = true;
            info.value = "random";
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
        
        if UIDROPDOWNMENU_MENU_VALUE then
            insertBlank();
            info = UIDropDownMenu_CreateInfo();
            info.text = "|cffff0000Delete All";
            info.notCheckable = 1;
            local c, m, u = CURRENT_EVENT, MATCHING, UIDROPDOWNMENU_MENU_VALUE;
            if IS_STANDARD then
                info.func = function()
                    local t = Notifications:Get("events", c, m);
                    table.remove(t, u);
                    scanTablesForEmpty();
                    CloseDropDownMenus();
                end
            else
                info.func = function()
                    local t = Notifications:Get("events", c);
                    table.remove(t, u);
                    scanTablesForEmpty();
                    CloseDropDownMenus();
                end
            end
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
    elseif UIDROPDOWNMENU_MENU_LEVEL == 5 then --tables
        SENDING = UIDROPDOWNMENU_MENU_VALUE;
        for i, entry in ipairs(CURRENT_SUPERTABLE[SENDING]) do
            info = UIDropDownMenu_CreateInfo();
            info.text = entry.name;
            info.notCheckable = true;
            info.hasArrow = true;
            info.value = i;
            UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        end
        
        insertBlank();
        info = UIDropDownMenu_CreateInfo();
        info.text = "|cffff0000Delete All";
        info.notCheckable = 1;
        local c, s = CURRENT_SUPERTABLE, SENDING;
        info.func = function()
            c[s] = nil;
            scanTablesForEmpty();
            CloseDropDownMenus();
        end
        UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
    elseif UIDROPDOWNMENU_MENU_LEVEL == 6 then
        local entry = CURRENT_SUPERTABLE[SENDING][UIDROPDOWNMENU_MENU_VALUE];
        info = UIDropDownMenu_CreateInfo();
        info.text = "Edit";
        info.notCheckable = true;
        info.func = function()
            CURRENT_TABLE = entry;
            CURRENT_STATE = "edit";
            for frame in pairs(STATE_FRAMES) do
                frame:Update();
            end
            scanTablesForEmpty();
            CloseDropDownMenus();
        end
        UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
        
        insertBlank();
        info = UIDropDownMenu_CreateInfo();
        info.text = "|cffff0000Delete";
        info.notCheckable = 1;
        local c, s, u = CURRENT_SUPERTABLE, SENDING, UIDROPDOWNMENU_MENU_VALUE;
        info.func = function()
            table.remove(c[s], u);
            scanTablesForEmpty();
            CloseDropDownMenus();
        end
        UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
    end
end

local optionsTable = {
    { -- section 1
        { -- column 1
            { -- row
                {
                    title = "Enabled",
                    type = "checkButton",
                    tooltipText = "Enables or disables the addon.",
                    setting = "enabled",
                },
                {
                    title = "New Event",
                    type = "dropDown", 
                    tooltipText = "Select an event from the dropdown to make a new notification.",
                    func = dropDownCreate,
                },
                {
                    title = "Manage Events",
                    type = "dropDown", 
                    tooltipText = "Manage your current notifications.  You can edit or delete them.",
                    func = dropDownManage,
                },
                {
                    title = "Timer Setting",
                    type = "dropDown",
                    tooltipText = "Select the timer setting you want to apply to timers.",
                    func = function()
                        local setting = "timerSetting";
                        local info;
                        for name, settings in pairs(TimerLib:Get("timerSettings")) do
                            info = UIDropDownMenu_CreateInfo();
                            info.text = name;
                            info.checked = name == Notifications:Get(setting);
                            info.func = function() 
                                Notifications:Set(setting, name);
                                CloseDropDownMenus(); 
                            end
                            UIDropDownMenu_AddButton(info);
                        end
                    
                        info = UIDropDownMenu_CreateInfo();
                        info.text = "None";
                        info.tooltipTitle = "Description";
                        info.tooltipText = "If you select 'None', the default for the anchor will be used instead.";
                        info.checked = Notifications:Get(setting) == nil;
                        info.func = function() 
                            Notifications:Set(setting, nil);
                            CloseDropDownMenus(); 
                        end
                        UIDropDownMenu_AddButton(info);
                    end,
                },
            },
        },
    },
    { -- section 2
        { -- column 1
            {
                type = "text",
                text = "(This is the event being managed)",
                scripts = {
                    OnShow = function(self) -- state watcher code
                        --self.text:SetText(...);
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    self:Show();
                                    self.text:SetText(CURRENT_EVENT);
                                end
                            end
                            STATE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
        },
    },
    { -- section 3
        { -- column 1
            {
                title = "Notification Name",
                type = "editBoxString",
                tooltipText = "Type here the name you want associated with this notification.  You will use this name when managing this notification later.",
                scripts = {
                    OnEditFocusGained = function(self) 
                        self:SetText(CURRENT_TABLE.name);
                        self:HighlightText(); 
                    end,
                    OnEditFocusLost = function(self)
                        local text = self:GetText();
                        CURRENT_TABLE.name = text;
                    end,
                    OnEscapePressed = function(self)
                        self:SetText(CURRENT_TABLE.name); 
                        self:SetCursorPosition(0);
            			self:ClearFocus();
            		end,
            		OnEnterPressed = function(self) 
                        self:ClearFocus();
            		end,
            		OnShow = function(self) -- state watcher code
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    self:Show();
                                    if not CURRENT_TABLE.name then
                                        CURRENT_TABLE.name = "Default Name";
                                    end
                                    self:SetText(self.title or ""); 
                                    self:SetCursorPosition(0);
                                end
                            end
                            STATE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Type",
                type = "dropDown",
                tooltipText = "Select the type of notification you want this to be.",
                func = function()
                    local info;
                    local curr = CURRENT_TABLE.type;
                    for name, tooltip in AsheylaLib:Alphabetize(NOTIFICATIONS_TYPES) do
                        info = UIDropDownMenu_CreateInfo();
                        info.text = name;
                        info.tooltipTitle = "Description";
                        info.tooltipText = tooltip;
                        info.checked = (name == curr);
                        info.func = function()
                            CURRENT_TABLE.type = name;
                            for frame in pairs(TYPE_FRAMES) do
                                frame:Update();
                            end
                        end
                        UIDropDownMenu_AddButton(info);
                    end
                end,
                scripts = {
                    OnShow = function(self)
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    self:Show();
                                    if not CURRENT_TABLE.type then
                                        CURRENT_TABLE.type = "text";
                                        for frame in pairs(TYPE_FRAMES) do
                                            frame:Update();
                                        end
                                    end
                                end
                            end
                            STATE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Match",
                type = "editBoxString",
                tooltipText = "changed based on state",
                scripts = {
                    OnEditFocusGained = function(self) 
                        self:SetText(CURRENT_SUPERTABLE.comp);
                        self:HighlightText(); 
                    end,
                    OnEditFocusLost = function(self)
                        local text = self:GetText();
                        CURRENT_SUPERTABLE.comp = text;
                        for frame in pairs(MATCH_FRAMES) do
                            frame:Update();
                        end
                    end,
                    OnEscapePressed = function(self)
                        self:SetText(CURRENT_SUPERTABLE.comp); 
                        self:SetCursorPosition(0);
            			self:ClearFocus();
            		end,
            		OnEnterPressed = function(self) 
                        self:ClearFocus();
            		end,
            		OnShow = function(self) -- state watcher code
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" or CURRENT_STATE == "edit" then
                                    self:Hide();
                                else
                                    local isShowing;
                                    if CURRENT_EVENT == "Health" or CURRENT_EVENT == "Mana" then
                                        self.tooltipText = "Enter here the amount of health or mana you want to trigger this notification.  Prefix your number with a '+' to fire when your health goes over this value, or a '-' for under.  Append a '%' to the number for it to be treated as a percent.";
                                        isShowing = true;
                                    elseif string.find(CURRENT_EVENT, "Time Remaining") then
                                        isShowing = true;
                                        self.tooltipText = "Enter here the name of the timer.  You can enter 'all' for all timers to match.  No partial matches.";
                                    elseif CURRENT_EVENT == "Buff Missing" then
                                        isShowing = true;
                                        self.tooltipText = "Enter here the name of the buff.";
                                    elseif string.find(CURRENT_EVENT, "Cooldown Up") then
                                        isShowing = true;
                                        self.tooltipText = "Enter here the name of the spell or item.";
                                    elseif CURRENT_EVENT == "Combat Log" or CURRENT_EVENT == "Chat Log" then
                                        isShowing = true;
                                        self.tooltipText = "Whatever you enter here will be compared to incoming chat or combat log messages.  You can use Lua string parsing regex to create return values.";
                                    else
                                        self.tooltipText = "When the event occurs, the event's 1st argument (%1) is compared to whatever you type here to see if this notification should be sent.  You can allow partial matches to be accepted by the checkbutton to the right.  Type 'all' (no quotes) for all arguments to be accepted.";
                                    end
                                    isShowing = isShowing or IS_STANDARD;
                                    if isShowing then
                                        self:Show();
                                        CURRENT_SUPERTABLE.comp = CURRENT_SUPERTABLE.comp or "all";
                                        self:SetText(self.title or ""); 
                                        self:SetCursorPosition(0);
                                        for frame in pairs(MATCH_FRAMES) do
                                            frame:Update();
                                        end
                                    else
                                        self:Hide();
                                    end
                                end
                            end
                            STATE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Time",
                type = "editBoxString",
                tooltipText = "This needs to change based on state.",
                scripts = {
                    OnEditFocusGained = function(self) 
                        self:SetText(Notifications:NumToText(self.table[self.index]));
                        self:HighlightText(); 
                    end,
                    OnEditFocusLost = function(self)
                        local text = self:GetText();
                        self.table[self.index] = Notifications:TextToNum(text);
                    end,
                    OnEscapePressed = function(self)
                        self:SetText(Notifications:NumToText(self.table[self.index]));
                        self:SetCursorPosition(0);
            			self:ClearFocus();
            		end,
            		OnEnterPressed = function(self) 
                        self:ClearFocus();
            		end,
            		OnShow = function(self) -- state watcher code
                        --self:SetText(self.title or ""); 
                        --self:SetCursorPosition(0);
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    if string.find(CURRENT_EVENT, "Time Remaining") then
                                        if CURRENT_STATE == "edit" then
                                            self:Hide();
                                            return;
                                        end
                                        self.table = CURRENT_SUPERTABLE;
                                        self.index = "comp2";
                                        if not CURRENT_SUPERTABLE.comp2 then
                                            CURRENT_SUPERTABLE.comp2 = 5;
                                        end
                                        self.tooltipText = "Enter here the amount of time remaining you want for this notification to fire.  Type it in a form like '5m 2s'.  Whole seconds only.";
                                        self.title = "Time Remaining";
                                    else
                                        self.table = CURRENT_TABLE;
                                        self.index = "delay";
                                        if not CURRENT_TABLE.delay then
                                            CURRENT_TABLE.delay = 0;
                                        end
                                        self.tooltipText = "Enter here how long of a delay you want before this notification fires.  Type it in a form like '5m 2s'.  Whole seconds only.";
                                        self.title = "Delay";
                                    end
                                    self:Show();
                                    self:SetText(self.title or ""); 
                                    self:SetCursorPosition(0);
                                end
                            end
                            STATE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "File",
                type = "editBoxString",
                tooltipText = "Type here the name of the sound file you want played.  This file should be found in DoTimer\\Core\\Files.",
                scripts = {
                    OnEditFocusGained = function(self) 
                        self:SetText(CURRENT_TABLE.file);
                        self:HighlightText(); 
                    end,
                    OnEditFocusLost = function(self)
                        local text = self:GetText();
                        CURRENT_TABLE.file = text;
                    end,
                    OnEscapePressed = function(self)
                        self:SetText(CURRENT_TABLE.file);
                        self:SetCursorPosition(0);
            			self:ClearFocus();
            		end,
            		OnEnterPressed = function(self) 
                        self:ClearFocus();
            		end,
            		OnShow = function(self) -- state watcher code
                        --self:SetText(self.title or ""); 
                        --self:SetCursorPosition(0);
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" or CURRENT_TABLE.type ~= "sound" then
                                    self:Hide();
                                else
                                    self:Show();
                                    if not CURRENT_TABLE.file then
                                        CURRENT_TABLE.file = "alert.wav";
                                    end
                                    self:SetText(self.title or ""); 
                                    self:SetCursorPosition(0);
                                end
                            end
                            STATE_FRAMES[self] = true;
                            TYPE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Duration",
                type = "editBoxString",
                tooltipText = "Enter here the duration for the timer.  Type it in a form like '5m 2s'.  Whole seconds only.",
                scripts = {
                    OnEditFocusGained = function(self) 
                        self:SetText(Notifications:NumToText(CURRENT_TABLE.duration));
                        self:HighlightText(); 
                    end,
                    OnEditFocusLost = function(self)
                        local text = self:GetText();
                        CURRENT_TABLE.duration = Notifications:TextToNum(text);
                    end,
                    OnEscapePressed = function(self)
                        self:SetText(Notifications:NumToText(CURRENT_TABLE.duration));
                        self:SetCursorPosition(0);
            			self:ClearFocus();
            		end,
            		OnEnterPressed = function(self) 
                        self:ClearFocus();
            		end,
            		OnShow = function(self) -- state watcher code
                        --self:SetText(self.title or ""); 
                        --self:SetCursorPosition(0);
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" or CURRENT_TABLE.type ~= "timer" then
                                    self:Hide();
                                else
                                    if not CURRENT_TABLE.duration then
                                        CURRENT_TABLE.duration = 5;
                                    end
                                    self:Show();
                                    self:SetText(self.title or ""); 
                                    self:SetCursorPosition(0);
                                end
                            end
                            STATE_FRAMES[self] = true;
                            TYPE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            "BREAK",
        },
        { -- column 2
            {
                title = "Message",
                type = "editBoxString",
                tooltipText = "Type here the message you want for this notification.  You can use %1, %2, etc. from the arguments from the event.",
                scripts = {
                    OnEditFocusGained = function(self) 
                        self:SetText(CURRENT_TABLE.msg);
                        self:HighlightText(); 
                    end,
                    OnEditFocusLost = function(self)
                        local text = self:GetText();
                        CURRENT_TABLE.msg = text;
                    end,
                    OnEscapePressed = function(self)
                        self:SetText(CURRENT_TABLE.msg);
                        self:SetCursorPosition(0);
            			self:ClearFocus();
            		end,
            		OnEnterPressed = function(self) 
                        self:ClearFocus();
            		end,
            		OnShow = function(self) -- state watcher code
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    local type = CURRENT_TABLE.type;
                                    if (type ~= "sound" and type ~= "flash") then
                                        self:Show();
                                        self:SetText(self.title or ""); 
                                        self:SetCursorPosition(0);
                                        if not CURRENT_TABLE.msg then
                                            CURRENT_TABLE.msg = "Default Msg!";
                                        end
                                    else
                                        self:Hide();
                                    end
                                end
                            end
                            STATE_FRAMES[self] = true;
                            TYPE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Color",
                type = "colorSelect",
                tooltipText = "Select the color for your notification.",
                scripts = {
                    OnClick = function(self)
                        ColorPickerFrame.func = function() 
                            local r, g, b = ColorPickerFrame:GetColorRGB();
                            getglobal(self:GetName() .. "NormalTexture"):SetVertexColor(r, g, b);
                            CURRENT_TABLE.color = {r = r, g = g, b = b};
                        end
                        local r, g, b = getglobal(self:GetName().."NormalTexture"):GetVertexColor();
                        ColorPickerFrame:SetColorRGB(r, g, b);
                        ColorPickerFrame.previousValues = {r = r, g = g, b = b};
                        ColorPickerFrame.cancelFunc = function(prev)
                            getglobal(self:GetName().."NormalTexture"):SetVertexColor(prev.r, prev.g, prev.b);
                        end
                        ShowUIPanel(ColorPickerFrame);
                    end,
                    OnShow = function(self)
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    local type = CURRENT_TABLE.type;
                                    if (type == "alert" or type == "text") then
                                        self:Show();
                                        if not CURRENT_TABLE.color then
                                            CURRENT_TABLE.color = {r = 1, g = 1, b = 1};
                                        end
                                        local color = CURRENT_TABLE.color;
                                        getglobal(self:GetName() .. "NormalTexture"):SetVertexColor(color.r, color.g, color.b);
                                    else
                                        self:Hide();
                                    end
                                end
                            end
                            STATE_FRAMES[self] = true;
                            TYPE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Color",
                type = "dropDown",
                tooltipText = "Select the color for the flash.",
                func = function()
                    local info;
                    local curr = CURRENT_TABLE.colorName;
                    for _, name in ipairs(flash_colors) do
                        info = UIDropDownMenu_CreateInfo();
                        info.text = name;
                        info.checked = (name == curr);
                        info.func = function()
                            CURRENT_TABLE.colorName = name;
                        end
                        UIDropDownMenu_AddButton(info);
                    end
                end,
                scripts = {
                    OnShow = function(self)
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    if CURRENT_TABLE.type == "flash" then
                                        self:Show();
                                        if not CURRENT_TABLE.colorName then
                                            CURRENT_TABLE.colorName = "Red";
                                        end
                                    else
                                        self:Hide();
                                    end
                                end
                            end
                            STATE_FRAMES[self] = true;
                            TYPE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Chat",
                type = "dropDown",
                tooltipText = "Select the chat channel for your message.",
                func = function()
                    local info;
                    local curr = CURRENT_TABLE.chatType;
                    for _, name in ipairs(flash_colors) do
                        info = UIDropDownMenu_CreateInfo();
                        info.text = name;
                        info.checked = (name == curr);
                        info.func = function()
                            CURRENT_TABLE.chatType = name;
                        end
                        UIDropDownMenu_AddButton(info);
                    end
                end,
                scripts = {
                    OnShow = function(self)
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    if CURRENT_TABLE.type == "chat" then
                                        self:Show();
                                        if not CURRENT_TABLE.chatType then
                                            CURRENT_TABLE.chatType = "auto";
                                        end
                                    else
                                        self:Hide();
                                    end
                                end
                            end
                            STATE_FRAMES[self] = true;
                            TYPE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Target",
                type = "editBoxString",
                tooltipText = "Type here the name of the target for your chat message.  You can use %1, %2, etc. from the arguments from the event.",
                scripts = {
                    OnEditFocusGained = function(self) 
                        self:SetText(CURRENT_TABLE.target);
                        self:HighlightText(); 
                    end,
                    OnEditFocusLost = function(self)
                        local text = self:GetText();
                        CURRENT_TABLE.target = text;
                    end,
                    OnEscapePressed = function(self)
                        self:SetText(CURRENT_TABLE.target);
                        self:SetCursorPosition(0);
            			self:ClearFocus();
            		end,
            		OnEnterPressed = function(self) 
                        self:ClearFocus();
            		end,
            		OnShow = function(self) -- state watcher code
                        --self:SetText(self.title or ""); 
                        --self:SetCursorPosition(0);
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" or CURRENT_TABLE.type ~= "chat" then
                                    self:Hide();
                                else
                                    self:Show();
                                    if not CURRENT_TABLE.target then
                                        CURRENT_TABLE.target = "%2";
                                    end
                                    self:SetText(self.title or ""); 
                                    self:SetCursorPosition(0);
                                end
                            end
                            STATE_FRAMES[self] = true;
                            TYPE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            "BREAK",
        },
        { -- column 3
            {
                title = "Random Chance",
                type = "slider",
                tooltipText = "Select here the percent chance that one of your random notifications will be sent.",
                minValue = 0,
                maxValue = 100,
                valueStep = 1,
                scripts = {
                    OnShow = function(self) 
                        --self.real = false;
                        --self:SetValue((self.Get and (self.Get(self.setting) or 0)) or self.module:Get(self.setting)); 
                        --self.real = true; 
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" or SENDING ~= "random" then
                                    self:Hide();
                                else
                                    self:Show();
                                    if not CURRENT_SUPERTABLE.rand then
                                        CURRENT_SUPERTABLE.rand = 100;
                                    end
                                    self:SetValue(CURRENT_SUPERTABLE.rand);
                                end
                            end
                            STATE_FRAMES[self] = true;
                            RANDOM_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
            		OnValueChanged = function(self)
            			local value = self:GetValue();
            			getglobal(this:GetName() .. "Value"):SetText(value);
            			CURRENT_SUPERTABLE.rand = value;
            		end,
                },
            },
            {
                title = "Random",
                type = "checkButton",
                tooltipText = "If checked, this notification will be sent randomly instead of all the time.  Notifications decides based on the 'Random Chance' setting whether or not to send exactly one of the notifications you set to 'Random' for this event.",
                scripts = {
                    OnShow = function(self) 
                        --local setting = self.Get and self.Get(self.setting) or self.module:Get(self.setting);
                        --self:SetChecked(setting and true or false); 
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    self:Show();
                                    if self:GetChecked() then
                                        SENDING = "random";
                                    else
                                        SENDING = "always";
                                    end
                                    if CURRENT_STATE == "edit" then
                                        if CURRENT_SUPERTABLE.always then
                                            for i, t in ipairs(CURRENT_SUPERTABLE.always) do
                                                if t == CURRENT_TABLE then
                                                    table.remove(CURRENT_SUPERTABLE.always, i);
                                                    break;
                                                end
                                            end
                                        end
                                        if CURRENT_SUPERTABLE.random then
                                            for i, t in ipairs(CURRENT_SUPERTABLE.random) do
                                                if t == CURRENT_TABLE then
                                                    table.remove(CURRENT_SUPERTABLE.random, i);
                                                    break;
                                                end
                                            end
                                        end
                                        if not CURRENT_SUPERTABLE[SENDING] then
                                            CURRENT_SUPERTABLE[SENDING] = {};
                                        end
                                        table.insert(CURRENT_SUPERTABLE[SENDING], CURRENT_TABLE);
                                    end
                                    for frame in pairs(RANDOM_FRAMES) do
                                        frame:Update();
                                    end
                                end
                            end
                            STATE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                    OnClick = function(self) 
                        self:Update();
                    end,
                },
            },
            {
                title = "Partial Matches",
                type = "checkButton",
                tooltipText = "If checked, the match you typed into the 'Match' edit box will be used as a partial match instead of an exact match.",
                scripts = {
                    OnShow = function(self) 
                        --local setting = self.Get and self.Get(self.setting) or self.module:Get(self.setting);
                        --self:SetChecked(setting and true or false); 
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" or CURRENT_STATE == "edit" or not IS_STANDARD then
                                    self:Hide();
                                else
                                    if CURRENT_SUPERTABLE.comp == "all" then
                                        MATCHING = "all";
                                        self:Hide();
                                    else
                                        self:Show();
                                        if self:GetChecked() then
                                            MATCHING = "partial";
                                        else
                                            MATCHING = "exact";
                                        end
                                    end
                                    
                                end
                            end
                            STATE_FRAMES[self] = true;
                            MATCH_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                    OnClick = function(self) 
                        self:Update();
                    end,
                },
            },
            "BREAK",
            {
                title = "Preview",
                type = "button",
                tooltipText = "Shows an example notification for the selected type.",
                func = function()
                    local type = CURRENT_TABLE.type;
                    if type == "sound" then
                        Notifications:PlaySound();
                    elseif type == "sct" then
                        Notifications:SCTAlert();
                    elseif type == "alert" then
                        Notifications:Alert();
                    elseif type == "text" then
                        Notifications:Text();
                    elseif type == "chat" then
                        Notifications:ChatMsg();
                    elseif type == "timer" then
                        Notifications:Timer();
                    elseif type == "flash" then
                        Notifications:Flash();
                    end
                end,
                scripts = {
                    OnShow = function(self)
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    self:Show();
                                end
                            end
                            STATE_FRAMES[self] = true;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "(change based on state)",
                type = "button",
                tooltipText = "(change based on state)",
                func = function()
                    CURRENT_STATE = "none";
                    for frame in pairs(STATE_FRAMES) do
                        frame:Update();
                    end
                end,
                scripts = {
                    OnShow = function(self)
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE == "none" then
                                    self:Hide();
                                else
                                    if CURRENT_STATE == "create" then
                                        self.title = "Cancel";
                                        self.tooltipText = "Cancels the creation of a new notification.";
                                    else
                                        self.title = "Done";
                                        self.tooltipText = "Click here when you're done editing.";
                                    end
                                    getglobal(self:GetName() .. "Text"):SetText(self.title);
                                    self:Show();
                                end
                            end
                            STATE_FRAMES[self] = true;
                            DONE_BUTTON = self;
                        end
                        self:Update();
                    end,
                },
            },
            {
                title = "Create!",
                type = "button",
                tooltipText = "Create this Notification!",
                func = function()
                    local t;
                    local needs_comp2 = string.find(CURRENT_EVENT, "Time Remaining");
                    if IS_STANDARD then
                        t = Notifications:Get("events", CURRENT_EVENT, MATCHING);
                        if not t then
                            t = {};
                            Notifications:Set("events", CURRENT_EVENT, MATCHING, t);
                        end
                    else
                        t = Notifications:Get("events", CURRENT_EVENT);
                        if not t then
                            t = {};
                            Notifications:Set("events", CURRENT_EVENT, t);
                        end
                    end
                    local realSuper;
                    if MATCHING == "all" and IS_STANDARD then
                        realSuper = t;
                    else
                        for i, entry in ipairs(t) do
                            if string.find(CURRENT_EVENT, "Aggro") or (entry.comp == CURRENT_SUPERTABLE.comp and ((not needs_comp2) or (entry.comp2 == CURRENT_SUPERTABLE.comp2))) then
                                realSuper = entry;
                                break;
                            end
                        end
                    end
                    if not realSuper then
                        realSuper = CURRENT_SUPERTABLE;
                        table.insert(t, CURRENT_SUPERTABLE);
                    end
                    realSuper.rand = SENDING == "random" and CURRENT_SUPERTABLE.rand or realSuper.rand;
                    t = realSuper[SENDING];
                    if not t then
                        t = {};
                        realSuper[SENDING] = t;
                    end
                    table.insert(realSuper[SENDING], CURRENT_TABLE);
                    CURRENT_STATE = "none";
                    for frame in pairs(STATE_FRAMES) do
                        frame:Update();
                    end
                end,
                scripts = {
                    OnShow = function(self)
                        if not self.loaded then
                            self.loaded = true;
                            self.Update = function(self)
                                if CURRENT_STATE ~= "create" then
                                    self:Hide();
                                else
                                    self:Show();
                                end
                            end
                            STATE_FRAMES[self] = true;
                            CREATE_BUTTON = self;
                        end
                        self:Update();
                    end,
                },
            },
        },
    },
};

local okayFunc = function()
    if CURRENT_STATE == "create" and CREATE_BUTTON then
        CREATE_BUTTON:Click();
    elseif CURRENT_STATE == "edit" and DONE_BUTTON then
        DONE_BUTTON:Click();
    end
end

local function createNGUI()
    if not AsheylaLib:InSimpleMode() then
        GUILib:SetGUIPanel("|c4fffffff|rNotifications", "main", Notifications, optionsTable, {okay = okayFunc});
    end
end
createNGUI();
GUILib:AddGUICreationScript(createNGUI);
