-------------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Options Tab Frames
-- Author: Mik
-------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------------

-- The name of the options frame.
local OPTIONS_FRAME_NAME = "MSBTFrameOptions";

-- The default font name.
local DEFAULT_FONT_NAME = "Default";


-------------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------------

-- Table to hold the current options for the profile dropdown.
local profileDropdownOptions = {};

-- Tables to hold trigger and suppression lists.
local triggersList = {};
local suppressionsList = {};


-------------------------------------------------------------------------------------
-- General Tab Frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the general tab frame.
-- **********************************************************************************
function MikSBTOpt.InitGeneralTabFrame()
 -- Setup the Enable checkbox.
 local key = "Tab1FrameEnableMSBTCheckbox";	MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.GeneralTabFrameCheckboxOnClick);
 MikSBTOpt.PopulateCheckbox(OPTIONS_FRAME_NAME .. key, not MSBTProfiles.GetSavedVariables().UserDisabled);

 -- Refresh the available profiles for the profile dropdown.
 MikSBTOpt.RefreshProfileDropdownOptions();

 -- Setup the profile dropdown.
 key = "Tab1FrameProfileDropdown";	MikSBTOpt.SetupDropdown(OPTIONS_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.ProfileDropdownOnClick, profileDropdownOptions);
 MikSBTOpt.PopulateDropdown(OPTIONS_FRAME_NAME .. key, MSBTProfiles.GetSavedVariablesPerChar().CurrentProfileName);

 -- Setup the profile manipulation buttons.
 key = "Tab1FrameCopyProfileButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.GeneralTabFrameButtonOnClick);
 key = "Tab1FrameDeleteProfileButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.GeneralTabFrameButtonOnClick);
 key = "Tab1FrameResetProfileButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.GeneralTabFrameButtonOnClick);

 -- Change the state of the profile buttons correctly.
 MikSBTOpt.EnableDisableProfileButtons();

 -- Setup the enable throttling, sticky crits, game damage, game healing, and enable sounds checkboxes.
 key = "Tab1FrameEnableThrottlingCheckbox";	MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.GeneralTabFrameCheckboxOnClick);
 key = "Tab1FrameStickyCritsCheckbox";		MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.GeneralTabFrameCheckboxOnClick);
 key = "Tab1FrameGameDamageCheckbox";		MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.GeneralTabFrameCheckboxOnClick);
 key = "Tab1FrameGameHealingCheckbox";		MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.GeneralTabFrameCheckboxOnClick);
 key = "Tab1FrameEnableSoundsCheckbox";		MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. key, MSBTLocale.CHECKBOXES[key].Label, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.GeneralTabFrameCheckboxOnClick);

 -- Setup the throttle time, and animation speed slider.
 key = "Tab1FrameThrottleTimeSlider";	MikSBTOpt.SetupSlider(OPTIONS_FRAME_NAME .. key, MSBTLocale.SLIDERS[key].Label, MSBTLocale.SLIDERS[key].Tooltip, 1, 3, 0.5, MikSBTOpt.GeneralTabFrameSliderOnValueChanged);
 key = "Tab1FrameAnimationSpeedSlider";	MikSBTOpt.SetupSlider(OPTIONS_FRAME_NAME .. key, MSBTLocale.SLIDERS[key].Label, MSBTLocale.SLIDERS[key].Tooltip, 50, 250, 10, MikSBTOpt.GeneralTabFrameSliderOnValueChanged);


 -- Setup the font settings, partial effects, and damage color buttons.
 key = "Tab1FrameMasterFontSettingsButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.GeneralTabFrameButtonOnClick);
 key = "Tab1FramePartialEffectsButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.GeneralTabFrameButtonOnClick);
 key = "Tab1FrameDamageColorsButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.GeneralTabFrameButtonOnClick);
end


-- **********************************************************************************
-- Populates the profile's options for the general tab.
-- **********************************************************************************
function MikSBTOpt.PopulateGeneralTabFrameProfileOptions()
 -- Populate the enable throttling, sticky crits, game damage, and enable sounds checkboxes.
 MikSBTOpt.PopulateCheckbox(OPTIONS_FRAME_NAME .. "Tab1FrameEnableThrottlingCheckbox", not MSBTProfiles.CurrentProfile.ThrottlingDisabled);
 MikSBTOpt.PopulateCheckbox(OPTIONS_FRAME_NAME .. "Tab1FrameStickyCritsCheckbox", not MSBTProfiles.CurrentProfile.StickyCritsDisabled);
 MikSBTOpt.PopulateCheckbox(OPTIONS_FRAME_NAME .. "Tab1FrameGameDamageCheckbox", not MSBTProfiles.CurrentProfile.GameDamageDisabled);
 MikSBTOpt.PopulateCheckbox(OPTIONS_FRAME_NAME .. "Tab1FrameGameHealingCheckbox", not MSBTProfiles.CurrentProfile.GameHealingDisabled); 
 MikSBTOpt.PopulateCheckbox(OPTIONS_FRAME_NAME .. "Tab1FrameEnableSoundsCheckbox", not MSBTProfiles.CurrentProfile.SoundsDisabled);

 -- Populate the throttle time, and animation speed sliders.
 MikSBTOpt.PopulateSlider(OPTIONS_FRAME_NAME .. "Tab1FrameThrottleTimeSlider", MSBTProfiles.CurrentProfile.ThrottleTime);
 MikSBTOpt.PopulateSlider(OPTIONS_FRAME_NAME .. "Tab1FrameAnimationSpeedSlider", MSBTProfiles.CurrentProfile.AnimationSpeed or 100);


 -- Show or hide the throttle time slider depending on if throttling is disabled or not.
 if (MSBTProfiles.CurrentProfile.ThrottlingDisabled) then
  getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameThrottleTimeSlider"):Hide();
 else
  getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameThrottleTimeSlider"):Show();
 end

end


-- **********************************************************************************
-- Handles checkbox clicks for the general tab frame.
-- **********************************************************************************
function MikSBTOpt.GeneralTabFrameCheckboxOnClick()
 -- Enable checkbox.
 if (string.find(this:GetName(), "EnableMSBTCheckbox")) then
  MSBTProfiles.SetOptionUserDisabled(not this:GetChecked() and true or nil);

 -- Sticky crits checkbox.
 elseif (string.find(this:GetName(), "StickyCritsCheckbox")) then
  MSBTProfiles.CurrentProfile.StickyCritsDisabled = not this:GetChecked() and true or nil;

 -- Game damage checkbox.
 elseif (string.find(this:GetName(), "GameDamageCheckbox")) then
  MSBTProfiles.SetOptionGameDamageDisabled(not this:GetChecked() and true or nil);

 -- Game healing checkbox.
 elseif (string.find(this:GetName(), "GameHealingCheckbox")) then
  MSBTProfiles.SetOptionGameHealingDisabled(not this:GetChecked() and true or nil);
 
 -- Enable sounds checkbox.
 elseif (string.find(this:GetName(), "EnableSoundsCheckbox")) then
  MSBTProfiles.CurrentProfile.SoundsDisabled = not this:GetChecked() and true or nil;

 -- Enable throttling checkbox.
 elseif (string.find(this:GetName(), "EnableThrottlingCheckbox")) then
  if (this:GetChecked()) then
   getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameThrottleTimeSlider"):Show();
  else
   getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameThrottleTimeSlider"):Hide();
  end

  MSBTProfiles.CurrentProfile.ThrottlingDisabled = not this:GetChecked() and true or nil;

 end
end


-- **********************************************************************************
-- Handles button clicks for the general tab frame.
-- **********************************************************************************
function MikSBTOpt.GeneralTabFrameButtonOnClick()
 -- Copy profile.
 if (string.find(this:GetName(), "CopyProfileButton")) then
  -- Create config table for detached input frame.
  local configTable = {};

  configTable.EditboxLabel = MSBTLocale.EDITBOXES["CopyProfileEditbox"].Label;
  configTable.EditboxTooltip = MSBTLocale.EDITBOXES["CopyProfileEditbox"].Tooltip;
  configTable.DefaultText = MSBTLocale.MSG_NEW_PROFILE;
  configTable.AnchorFrame = this;
  configTable.ValidateFunc = MikSBTOpt.ValidateProfileName;
  configTable.SaveFunc = MikSBTOpt.CopySelectedProfile;
  MikSBTOpt.ShowDetachedInputFrame(configTable);


 -- Delete profile.
 elseif (string.find(this:GetName(), "DeleteProfileButton")) then
  local selectedProfileName = UIDropDownMenu_GetSelectedValue(getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameProfileDropdown"));
  MSBTProfiles.DeleteProfile(selectedProfileName);
  MikSBTOpt.RefreshProfileDropdownOptions();
  UIDropDownMenu_SetSelectedValue(getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameProfileDropdown"), "Default");
  MikSBTOpt.EnableDisableProfileButtons();
  MikSBTOpt.PopulateProfileOptions();
  

 -- Reset profile.
 elseif (string.find(this:GetName(), "ResetProfileButton")) then
  -- Create config table for the acknowledge frame.
  local configTable = {};

  configTable.AnchorFrame = this;
  configTable.AcknowledgeFunc = MikSBTOpt.ResetProfileFunc;
  MikSBTOpt.ShowAcknowledgeFrame(configTable);

    
 -- Master font settings.
 elseif (string.find(this:GetName(), "MasterFontSettingsButton")) then
  -- Create config table for font config frame.
  local configTable = {};

  configTable.DefaultNormalFontName = MikSBTOpt.GetValidFontName(MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontName, false);
  configTable.DefaultNormalOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalOutlineIndex;
  configTable.DefaultNormalFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontSize;
  configTable.DefaultCritFontName = MikSBTOpt.GetValidFontName(MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontName, false);
  configTable.DefaultCritOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.CritOutlineIndex;
  configTable.DefaultCritFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontSize;
  configTable.Title = MSBTLocale.BUTTONS["Tab1FrameMasterFontSettingsButton"].Label;
  configTable.AnchorFrame = this;
  configTable.CanCrit = true;
  configTable.SaveFunc = MikSBTOpt.SaveMasterFontSettings;
  MikSBTOpt.ShowFontConfigFrame(configTable);

 -- Partial effects.
 elseif (string.find(this:GetName(), "PartialEffectsButton")) then
  MikSBTOpt.ShowPartialEffectsConfigFrame(this);

 -- Damage Colors.
 elseif (string.find(this:GetName(), "DamageColorsButton")) then
  MikSBTOpt.ShowDamageColorsConfigFrame(this);

 end
end


-- **********************************************************************************
-- Handles slider changes for the general tab frame.
-- **********************************************************************************
function MikSBTOpt.GeneralTabFrameSliderOnValueChanged()
 -- Throttle time.
 if (string.find(this:GetName(), "ThrottleTimeSlider")) then
  MSBTProfiles.CurrentProfile.ThrottleTime = this:GetValue();

 -- Animation step.
 elseif (string.find(this:GetName(), "AnimationSpeedSlider")) then
  MSBTProfiles.CurrentProfile.AnimationSpeed = this:GetValue();

 end
end


-- **********************************************************************************
-- Called when a new profile is selected.
-- **********************************************************************************
function MikSBTOpt.ProfileDropdownOnClick(frameName)
 -- Select the profile.
 local selectedProfileName = UIDropDownMenu_GetSelectedValue(getglobal(frameName));
 MSBTProfiles.SelectProfile(selectedProfileName);
 MikSBTOpt.EnableDisableProfileButtons();
 MikSBTOpt.PopulateProfileOptions();
end


-- **********************************************************************************
-- This function refreshes the list of profiles to show in the profile dropdown.
-- **********************************************************************************
function MikSBTOpt.RefreshProfileDropdownOptions()
 -- Erase the profile dropdown options.
 local numProfiles = #profileDropdownOptions;
 for x = numProfiles, 1, -1 do
  table.remove(profileDropdownOptions);
 end

 -- Populate the list of available profiles.
 for profileName in pairs(MSBTProfiles.GetSavedVariables().Profiles) do
  table.insert(profileDropdownOptions, profileName);
 end

 -- Sort the table.
 table.sort(profileDropdownOptions);
end


-- **********************************************************************************
-- This function will enable and disable the load and delete profile
-- buttons according to which profile is selected.
-- **********************************************************************************
function MikSBTOpt.EnableDisableProfileButtons()
 local profileDropdown = getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameProfileDropdown");
 local deleteProfileButton = getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameDeleteProfileButton");

 -- Enable the profile button manipulation buttons.
 deleteProfileButton:Enable();

 -- Check if the default profile is selected and disable the delete profile button.
 if (UIDropDownMenu_GetSelectedValue(profileDropdown) == "Default") then
  deleteProfileButton:Disable();
 end 
end


-- **********************************************************************************
-- Called by the acknowledge frame to reset the selected profile.
-- **********************************************************************************
function MikSBTOpt.ResetProfileFunc()
 local selectedProfileName = UIDropDownMenu_GetSelectedValue(getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameProfileDropdown"));
 MSBTProfiles.ResetProfile(selectedProfileName);  
 MikSBTOpt.PopulateProfileOptions();
end


-- **********************************************************************************
-- Validates if the passed profile name does not already exist.
-- **********************************************************************************
function MikSBTOpt.ValidateProfileName(profileName)
 if (not profileName or profileName == "") then
  return MSBTLocale.MSG_INVALID_PROFILE_NAME;
 end

 local profileExists = MSBTProfiles.ProfileExists(profileName);
 if (profileExists) then
  return MSBTLocale.MSG_PROFILE_ALREADY_EXISTS;
 end
end


-- **********************************************************************************
-- Called by the detached input frame with the name of a new profile to copy
-- the selected profile to.
-- **********************************************************************************
function MikSBTOpt.CopySelectedProfile(newProfileName)
 local selectedProfileName = UIDropDownMenu_GetSelectedValue(getglobal(OPTIONS_FRAME_NAME .. "Tab1FrameProfileDropdown"));
 MSBTProfiles.CopyProfile(selectedProfileName, newProfileName);
 MikSBTOpt.RefreshProfileDropdownOptions();
end


-- **********************************************************************************
-- Called by the font config frame with the new font settings.
-- **********************************************************************************
function MikSBTOpt.SaveMasterFontSettings(fontSettingsTable)
 MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontName = fontSettingsTable.NormalFontName;
 MSBTProfiles.CurrentProfile.MasterFontSettings.NormalOutlineIndex = fontSettingsTable.NormalOutlineIndex;
 MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontSize = fontSettingsTable.NormalFontSize;
 MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontName = fontSettingsTable.CritFontName;
 MSBTProfiles.CurrentProfile.MasterFontSettings.CritOutlineIndex = fontSettingsTable.CritOutlineIndex;
 MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontSize = fontSettingsTable.CritFontSize;
end


-------------------------------------------------------------------------------------
-- Scroll Area Tab Frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the scroll areas tab frame.
-- **********************************************************************************
function MikSBTOpt.InitScrollAreasTabFrame()
 -- Setup the help text.
 getglobal(OPTIONS_FRAME_NAME .. "Tab2FrameHelpText"):SetText(MSBTLocale.MSG_SCROLL_AREA_TAB_HELP);

 -- Setup the add scroll area and configure scroll areas buttons.
 local key = "Tab2FrameAddScrollAreaButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasTabFrameButtonOnClick);
 key = "Tab2FrameConfigScrollAreasButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasTabFrameButtonOnClick);

 -- Setup the scroll line buttons.
 for i = 1, 10 do
  local key = "EditScrollAreaNameButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab2FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasTabFrameButtonOnClick);
  key = "ScrollAreaFontSettingsButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab2FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasTabFrameButtonOnClick);
  key = "DeleteScrollAreaButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab2FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.ScrollAreasTabFrameButtonOnClick);
 end
end


-- **********************************************************************************
-- Updates the scroll frame for the scroll areas list.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasListUpdate()
 local totalItems = #MSBTProfiles.CurrentProfile.ScrollAreaSettings;

 local scrollFrame = getglobal(OPTIONS_FRAME_NAME .. "Tab2FrameScrollFrame");
 FauxScrollFrame_Update(scrollFrame, totalItems, 10, 25);
 local skipCount = FauxScrollFrame_GetOffset(scrollFrame);

 -- Loop through all of the scroll lines.
 local objScrollLine;
 for i = 1, 10 do
  -- Get the scroll line object.
  objScrollLine = getglobal(OPTIONS_FRAME_NAME .. "Tab2FrameScrollLine" .. i);

  -- Check if there is no data for the scroll line.
  if (i > totalItems) then
   objScrollLine:Hide();
  else
   objScrollLine:Show();

   objScrollLine.ScrollAreaIndex = i + skipCount;

   -- Disable the delete button if it's one of the default scroll areas.
   if (i + skipCount == 1 or i + skipCount == 2 or i + skipCount == 3) then
    getglobal(objScrollLine:GetName() .. "DeleteScrollAreaButton"):Disable();
   else
    getglobal(objScrollLine:GetName() .. "DeleteScrollAreaButton"):Enable();
   end

   local key = "EnableScrollAreaCheckbox";
   MikSBTOpt.SetupCheckbox(objScrollLine:GetName() .. key, MSBTProfiles.CurrentProfile.ScrollAreaSettings[i+skipCount].Name, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.ScrollAreasTabFrameCheckboxOnClick);
   MikSBTOpt.PopulateCheckbox(objScrollLine:GetName() .. key, not MSBTProfiles.CurrentProfile.ScrollAreaSettings[i+skipCount].Disabled);
  end
 end

end


-- **********************************************************************************
-- Handles button clicks for the scroll areas tab frame.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasTabFrameButtonOnClick()
 -- Add scroll area.
 if (string.find(this:GetName(), "AddScrollAreaButton")) then
  local newScrollArea = {};
  local highestNumber = 0;

  -- Finds the highest number in use for custom scroll areas that are using the default name.
  for _, scrollAreaSettings in ipairs(MSBTProfiles.CurrentProfile.ScrollAreaSettings) do
   local found, _, num = string.find(scrollAreaSettings.Name, MSBTLocale.MSG_CUSTOM_SCROLL_AREA .. " (%d+)");
   if (found and tonumber(num) > highestNumber) then
    highestNumber = tonumber(num);
   end
  end

  -- Set the new scroll area's name, add it to the list of scroll areas and update the
  -- scroll area list.
  newScrollArea.Name = MSBTLocale.MSG_CUSTOM_SCROLL_AREA .. " " .. (highestNumber + 1);
  table.insert(MSBTProfiles.CurrentProfile.ScrollAreaSettings, newScrollArea);
  MikSBTOpt.ScrollAreasListUpdate();


 -- Configure scroll areas.
 elseif (string.find(this:GetName(), "ConfigScrollAreasButton")) then
  MikSBTOpt.ShowScrollAreasConfigFrame();


 -- Edit scroll area name.
 elseif (string.find(this:GetName(), "EditScrollAreaNameButton")) then
  local scrollAreaIndex = this:GetParent().ScrollAreaIndex;

  -- Create config table for the detached input frame.
  local configTable = {};

  configTable.EditboxLabel = MSBTLocale.EDITBOXES["ScrollAreaNameEditbox"].Label;
  configTable.EditboxTooltip = MSBTLocale.EDITBOXES["ScrollAreaNameEditbox"].Tooltip;
  configTable.DefaultText = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].Name;
  configTable.AnchorFrame = this;
  configTable.ValidateFunc = MikSBTOpt.ValidateScrollAreaName;
  configTable.SaveFunc = MikSBTOpt.ChangeScrollAreaName;
  configTable.CustomArg1 = scrollAreaIndex;

  local found, _, lineNumber = string.find(this:GetName(), "ScrollLine(%d+)");
  if (found and tonumber(lineNumber) > 5) then
   configTable.AnchorPoint = "BOTTOMLEFT";
   configTable.RelativePoint = "TOPLEFT";
  end

  MikSBTOpt.ShowDetachedInputFrame(configTable);


 -- Font settings.
 elseif (string.find(this:GetName(), "ScrollAreaFontSettingsButton")) then
  local scrollAreaIndex = this:GetParent().ScrollAreaIndex;

  -- Create config table for font config frame.
  local configTable = {};

  configTable.DefaultNormalFontName = MikSBTOpt.GetValidFontName(MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].NormalFontName or MSBTDefaults.ScrollAreaSettings.NormalFontName, true)
  configTable.DefaultNormalOutlineIndex = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].NormalOutlineIndex or MSBTDefaults.ScrollAreaSettings.NormalOutlineIndex;
  configTable.DefaultNormalFontSize = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].NormalFontSize or MSBTDefaults.ScrollAreaSettings.NormalFontSize;
  configTable.DefaultCritFontName = MikSBTOpt.GetValidFontName(MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].CritFontName or MSBTDefaults.ScrollAreaSettings.CritFontName, true)
  configTable.DefaultCritOutlineIndex = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].CritOutlineIndex or MSBTDefaults.ScrollAreaSettings.CritOutlineIndex;
  configTable.DefaultCritFontSize = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].CritFontSize or MSBTDefaults.ScrollAreaSettings.CritFontSize;
  configTable.InheritedNormalFontName = MikSBTOpt.GetValidFontName(MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontName, false);
  configTable.InheritedNormalOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalOutlineIndex;
  configTable.InheritedNormalFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontSize;
  configTable.InheritedCritFontName = MikSBTOpt.GetValidFontName(MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontName, false);
  configTable.InheritedCritOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.CritOutlineIndex;
  configTable.InheritedCritFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontSize;

  configTable.Title = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].Name;
  configTable.AnchorFrame = this;
  configTable.CanInherit = true;
  configTable.CanCrit = true;
  configTable.SaveFunc = MikSBTOpt.SaveScrollAreaFontSettings;
  configTable.CustomArg1 = scrollAreaIndex;
  MikSBTOpt.ShowFontConfigFrame(configTable);


 -- Delete scroll area.
 elseif (string.find(this:GetName(), "DeleteScrollAreaButton")) then
   -- Create config table for the acknowledge frame.
  local configTable = {};

  configTable.AnchorFrame = this;
  configTable.AcknowledgeFunc = MikSBTOpt.DeleteScrollArea;
  configTable.CustomArg1 = this:GetParent().ScrollAreaIndex;
  MikSBTOpt.ShowAcknowledgeFrame(configTable);
 end
end


-- **********************************************************************************
-- Handles checkbox clicks for the scroll areas tab frame.
-- **********************************************************************************
function MikSBTOpt.ScrollAreasTabFrameCheckboxOnClick()
 -- Enable scroll area checkbox.
 if (string.find(this:GetName(), "EnableScrollAreaCheckbox")) then
  local scrollAreaIndex = this:GetParent().ScrollAreaIndex;
  MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].Disabled = not this:GetChecked() and true or nil;
 end
end


-- **********************************************************************************
-- Validates if the passed scroll area name does not already exist.
-- **********************************************************************************
function MikSBTOpt.ValidateScrollAreaName(scrollAreaName)
 if (not scrollAreaName or scrollAreaName == "") then
  return MSBTLocale.MSG_INVALID_SCROLL_AREA_NAME;
 end

 -- Loop through the scroll areas to see if the name already exists.
 for _, scrollAreaSettings in ipairs(MSBTProfiles.CurrentProfile.ScrollAreaSettings) do
  if (scrollAreaSettings.Name == scrollAreaName) then
   return MSBTLocale.MSG_SCROLL_AREA_ALREADY_EXISTS;
  end 
 end
end


-- **********************************************************************************
-- Called by the detached input frame with the name to change the passed scroll
-- area to.
-- **********************************************************************************
function MikSBTOpt.ChangeScrollAreaName(newScrollAreaName, scrollAreaIndex)
 MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex].Name = newScrollAreaName;
 MikSBTOpt.ScrollAreasListUpdate();
end


-- **********************************************************************************
-- Called by the font config frame with the new font settings.
-- **********************************************************************************
function MikSBTOpt.SaveScrollAreaFontSettings(fontSettingsTable, scrollAreaIndex)
 local scrollAreaSettings = MSBTProfiles.CurrentProfile.ScrollAreaSettings[scrollAreaIndex];

 scrollAreaSettings.NormalFontName = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalFontName, MSBTDefaults.ScrollAreaSettings.NormalFontName);
 scrollAreaSettings.NormalOutlineIndex = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalOutlineIndex, MSBTDefaults.ScrollAreaSettings.NormalOutlineIndex);
 scrollAreaSettings.NormalFontSize = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalFontSize, MSBTDefaults.ScrollAreaSettings.NormalFontSize);
 scrollAreaSettings.CritFontName = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritFontName, MSBTDefaults.ScrollAreaSettings.CritFontName);
 scrollAreaSettings.CritOutlineIndex = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritOutlineIndex, MSBTDefaults.ScrollAreaSettings.CritOutlineIndex);
 scrollAreaSettings.CritFontSize = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritFontSize, MSBTDefaults.ScrollAreaSettings.CritFontSize);
end


-- **********************************************************************************
-- Called by the acknowledge frame to delete the passed scroll area.
-- **********************************************************************************
function MikSBTOpt.DeleteScrollArea(scrollAreaIndex)
 -- Remove the scroll area from the scroll area settings table.
 table.remove(MSBTProfiles.CurrentProfile.ScrollAreaSettings, scrollAreaIndex);

 -- Loop through all of the event settings to remove all references to the deleted scroll
 -- area and to fix the indices of all the events that referenced a scroll area after the
 -- deleted one.
 for _, eventSettings in pairs(MSBTProfiles.CurrentProfile.EventSettings) do
  if (eventSettings.ScrollAreaIndex == scrollAreaIndex) then
   eventSettings.ScrollAreaIndex = nil;
  elseif (eventSettings.ScrollAreaIndex and eventSettings.ScrollAreaIndex > scrollAreaIndex) then
   eventSettings.ScrollAreaIndex = eventSettings.ScrollAreaIndex - 1;
  end
 end

 -- Do the same as above for triggers.
 for _, triggerData in pairs(MSBTProfiles.CurrentProfile.Triggers) do
  local eventSettings = triggerData.EventSettings;
  if (eventSettings.ScrollAreaIndex == scrollAreaIndex) then
   eventSettings.ScrollAreaIndex = nil;
  elseif (eventSettings.ScrollAreaIndex and eventSettings.ScrollAreaIndex > scrollAreaIndex) then
   eventSettings.ScrollAreaIndex = eventSettings.ScrollAreaIndex - 1;
  end
 end

 -- Update the scroll areas list.
 MikSBTOpt.ScrollAreasListUpdate();
end


-------------------------------------------------------------------------------------
-- Events Tab Frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the events types.
-- **********************************************************************************
function MikSBTOpt.InitEventTypes()
 -- Setup the event types for each event.
 local obj = MSBTLocale.INCOMING_EVENTS;
 obj[1].EventType = "INCOMING_DAMAGE";
 obj[2].EventType = "INCOMING_MISS";
 obj[3].EventType = "INCOMING_DODGE";
 obj[4].EventType = "INCOMING_PARRY";
 obj[5].EventType = "INCOMING_BLOCK";
 obj[6].EventType = "INCOMING_ABSORB";
 obj[7].EventType = "INCOMING_IMMUNE";
 obj[8].EventType = "INCOMING_SPELL_DAMAGE";
 obj[9].EventType = "INCOMING_SPELL_DOT";
 obj[10].EventType = "INCOMING_SPELL_MISS";
 obj[11].EventType = "INCOMING_SPELL_DODGE";
 obj[12].EventType = "INCOMING_SPELL_PARRY";
 obj[13].EventType = "INCOMING_SPELL_BLOCK";
 obj[14].EventType = "INCOMING_SPELL_RESIST";
 obj[15].EventType = "INCOMING_SPELL_ABSORB";
 obj[16].EventType = "INCOMING_SPELL_IMMUNE";
 obj[17].EventType = "INCOMING_SPELL_REFLECT";
 obj[18].EventType = "INCOMING_SPELL_INTERRUPT";
 obj[19].EventType = "INCOMING_HEAL";
 obj[20].EventType = "INCOMING_HOT";
 obj[21].EventType = "INCOMING_ENVIRONMENTAL";

 obj = MSBTLocale.OUTGOING_EVENTS;
 obj[1].EventType = "OUTGOING_DAMAGE";
 obj[2].EventType = "OUTGOING_MISS";
 obj[3].EventType = "OUTGOING_DODGE";
 obj[4].EventType = "OUTGOING_PARRY";
 obj[5].EventType = "OUTGOING_BLOCK";
 obj[6].EventType = "OUTGOING_ABSORB";
 obj[7].EventType = "OUTGOING_IMMUNE";
 obj[8].EventType = "OUTGOING_EVADE";
 obj[9].EventType = "OUTGOING_SPELL_DAMAGE";
 obj[10].EventType = "OUTGOING_SPELL_DOT";
 obj[11].EventType = "OUTGOING_SPELL_MISS";
 obj[12].EventType = "OUTGOING_SPELL_DODGE";
 obj[13].EventType = "OUTGOING_SPELL_PARRY";
 obj[14].EventType = "OUTGOING_SPELL_BLOCK";
 obj[15].EventType = "OUTGOING_SPELL_RESIST";
 obj[16].EventType = "OUTGOING_SPELL_ABSORB";
 obj[17].EventType = "OUTGOING_SPELL_IMMUNE";
 obj[18].EventType = "OUTGOING_SPELL_REFLECT";
 obj[19].EventType = "OUTGOING_SPELL_INTERRUPT";
 obj[20].EventType = "OUTGOING_SPELL_EVADE";
 obj[21].EventType = "OUTGOING_HEAL";
 obj[22].EventType = "OUTGOING_HOT";
 obj[23].EventType = "PET_DAMAGE";
 obj[24].EventType = "PET_MISS";
 obj[25].EventType = "PET_DODGE";
 obj[26].EventType = "PET_PARRY";
 obj[27].EventType = "PET_BLOCK";
 obj[28].EventType = "PET_ABSORB";
 obj[29].EventType = "PET_IMMUNE";
 obj[30].EventType = "PET_EVADE";
 obj[31].EventType = "PET_SPELL_DAMAGE";
 obj[32].EventType = "PET_SPELL_MISS";
 obj[33].EventType = "PET_SPELL_DODGE";
 obj[34].EventType = "PET_SPELL_PARRY";
 obj[35].EventType = "PET_SPELL_BLOCK";
 obj[36].EventType = "PET_SPELL_RESIST";
 obj[37].EventType = "PET_SPELL_ABSORB";
 obj[38].EventType = "PET_SPELL_IMMUNE";
 obj[39].EventType = "PET_SPELL_EVADE";

 obj = MSBTLocale.NOTIFICATION_EVENTS;
 obj[1].EventType = "NOTIFICATION_DEBUFF";
 obj[2].EventType = "NOTIFICATION_BUFF";
 obj[3].EventType = "NOTIFICATION_ITEM_BUFF";
 obj[4].EventType = "NOTIFICATION_DEBUFF_FADE";
 obj[5].EventType = "NOTIFICATION_BUFF_FADE";
 obj[6].EventType = "NOTIFICATION_ITEM_BUFF_FADE";
 obj[7].EventType = "NOTIFICATION_COMBAT_ENTER";
 obj[8].EventType = "NOTIFICATION_COMBAT_LEAVE";
 obj[9].EventType = "NOTIFICATION_POWER_GAIN";
 obj[10].EventType = "NOTIFICATION_POWER_LOSS";
 obj[11].EventType = "NOTIFICATION_CP_GAIN";
 obj[12].EventType = "NOTIFICATION_CP_FULL";
 obj[13].EventType = "NOTIFICATION_HONOR_GAIN";
 obj[14].EventType = "NOTIFICATION_REP_GAIN";
 obj[15].EventType = "NOTIFICATION_REP_LOSS";
 obj[16].EventType = "NOTIFICATION_SKILL_GAIN";
 obj[17].EventType = "NOTIFICATION_EXPERIENCE_GAIN";
 obj[18].EventType = "NOTIFICATION_PC_KILLING_BLOW";
 obj[19].EventType = "NOTIFICATION_NPC_KILLING_BLOW";
 obj[20].EventType = "NOTIFICATION_SOUL_SHARD_CREATED";
 obj[21].EventType = "NOTIFICATION_EXTRA_ATTACK";
end


-- **********************************************************************************
-- Initializes the events tab frame.
-- **********************************************************************************
function MikSBTOpt.InitEventsTabFrame()
 -- Initialize the event types.
 MikSBTOpt.InitEventTypes()

 -- Setup the help text.
 getglobal(OPTIONS_FRAME_NAME .. "Tab3FrameHelpText"):SetText(MSBTLocale.MSG_EVENTS_TAB_HELP);

 -- Populate the list of available event categories.
 local eventCategoryDropdownOptions = {};
 for eventCategoryIndex, eventCategoryName in ipairs(MSBTLocale.EVENT_CATEGORIES) do
  table.insert(eventCategoryDropdownOptions, {Name = eventCategoryName, Value = eventCategoryIndex});
 end

 -- Setup the event category dropdown.
 local key = "Tab3FrameEventCategoryDropdown";	MikSBTOpt.SetupDropdown(OPTIONS_FRAME_NAME .. key, MSBTLocale.DROPDOWNS[key].Label, MSBTLocale.DROPDOWNS[key].Tooltip, MikSBTOpt.EventsCategoryDropdownOnClick, eventCategoryDropdownOptions);
 MikSBTOpt.PopulateDropdown(OPTIONS_FRAME_NAME .. key, 1);

 -- Setup the scroll line buttons.
 for i = 1, 10 do
  local key = "EventSwatch";			MikSBTOpt.SetupColorSwatch(OPTIONS_FRAME_NAME .. "Tab3FrameScrollLine" .. i .. key, nil, MikSBTOpt.EventsTabFrameColorSwatchOnChange);
  key = "StickyEventCheckbox";		MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. "Tab3FrameScrollLine" .. i .. key, nil, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.EventsTabFrameCheckboxOnClick);
  key = "EventFontSettingsButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab3FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.EventsTabFrameButtonOnClick);
  key = "EventScrollAreaButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab3FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.EventsTabFrameButtonOnClick);
 end
end


-- **********************************************************************************
-- Updates the scroll frame for the events list.
-- **********************************************************************************
function MikSBTOpt.EventsListUpdate()
 -- Get the selected event category.
 local eventCategory = UIDropDownMenu_GetSelectedValue(getglobal(OPTIONS_FRAME_NAME .. "Tab3FrameEventCategoryDropdown"));

 -- Get the correct events list.
 local eventsList;
 if (eventCategory == 1) then
  eventsList = MSBTLocale.INCOMING_EVENTS;
 elseif (eventCategory == 2) then
  eventsList = MSBTLocale.OUTGOING_EVENTS;
 elseif (eventCategory == 3) then
  eventsList = MSBTLocale.NOTIFICATION_EVENTS;
 end

 -- Get the total number of events to list.
 local totalItems = #eventsList;

 local scrollFrame = getglobal(OPTIONS_FRAME_NAME .. "Tab3FrameScrollFrame");
 FauxScrollFrame_Update(scrollFrame, totalItems, 10, 25);
 local skipCount = FauxScrollFrame_GetOffset(scrollFrame);

 -- Loop through all of the scroll lines.
 local objScrollLine, eventSettings, colorTable;
 for i = 1, 10 do
  -- Get the scroll line object.
  objScrollLine = getglobal(OPTIONS_FRAME_NAME .. "Tab3FrameScrollLine" .. i);

  -- Check if there is no data for the scroll line.
  if (i > totalItems) then
   objScrollLine:Hide();
  else
   objScrollLine:Show();

   objScrollLine.EventType = eventsList[i + skipCount].EventType;
   eventSettings = MSBTProfiles.CurrentProfile.EventSettings[objScrollLine.EventType];

   colorTable = eventSettings.Color or MSBTDefaults.EventSettings.Color;
   MikSBTOpt.PopulateColorSwatch(objScrollLine:GetName() .. "EventSwatch", colorTable.r, colorTable.g, colorTable.b);

   key = "EnableEventCheckbox";
   MikSBTOpt.SetupCheckbox(objScrollLine:GetName() .. key, eventsList[i+skipCount].Label, eventsList[i+skipCount].Tooltips.EnableCheckbox, MikSBTOpt.EventsTabFrameCheckboxOnClick);
   MikSBTOpt.PopulateCheckbox(objScrollLine:GetName() .. key, not eventSettings.Disabled);

   key = "EditEventMessageButton";
   MikSBTOpt.SetupButton(objScrollLine:GetName() .. key, nil, MSBTLocale.BUTTONS[key].Tooltip .. MSBTLocale.MSG_EVENT_AVAILABLE_CODES_PREFIX .. eventsList[i+skipCount].Tooltips.Codes, MikSBTOpt.EventsTabFrameButtonOnClick);

   getglobal(objScrollLine:GetName() .. "Message"):SetText(eventSettings.Message);

   -- Only show and populate the sticky event checkbox for notification events.
   key = "StickyEventCheckbox";
   if (eventCategory == 3) then
    getglobal(objScrollLine:GetName() .. key):Show();
    MikSBTOpt.PopulateCheckbox(objScrollLine:GetName() .. key, eventSettings.AlwaysSticky);
   else
    getglobal(objScrollLine:GetName() .. key):Hide();
   end
  end
 end

end


-- **********************************************************************************
-- Called when the events category dropdown is clicked.
-- **********************************************************************************
function MikSBTOpt.EventsCategoryDropdownOnClick()
 -- Hide all of the detached frames.
 MikSBTOpt.HideDetachedFrames();

 -- Reset the scroll bar and offset.
 getglobal(OPTIONS_FRAME_NAME .. "Tab3FrameScrollFrameScrollBar"):SetValue(0);

 -- Update the events list.
 MikSBTOpt.EventsListUpdate();
end


-- **********************************************************************************
-- Called when a color swatch on the events tab frame changes.
-- **********************************************************************************
function MikSBTOpt.EventsTabFrameColorSwatchOnChange(colorSwatch)
 -- Check if it's one of the event color swatches.
 if (string.find(colorSwatch:GetName(), "EventSwatch")) then
  -- Update the event's profile.
  local eventSettings = MSBTProfiles.CurrentProfile.EventSettings[colorSwatch:GetParent().EventType];

  -- Nil out the color table if the color matches the default to save space.
  if (colorSwatch.r == MSBTDefaults.EventSettings.Color.r and colorSwatch.g == MSBTDefaults.EventSettings.Color.g and colorSwatch.b == MSBTDefaults.EventSettings.Color.b) then
   eventSettings.Color = nil;
  else
   -- Create a color table for the event if there already isn't one.
   if (not eventSettings.Color) then eventSettings.Color = {}; end
   eventSettings.Color.r = colorSwatch.r;
   eventSettings.Color.g = colorSwatch.g;
   eventSettings.Color.b = colorSwatch.b;
  end
 end
end


-- **********************************************************************************
-- Handles checkbox clicks for the events tab frame.
-- **********************************************************************************
function MikSBTOpt.EventsTabFrameCheckboxOnClick()
 -- Enable event checkbox.
 if (string.find(this:GetName(), "EnableEventCheckbox")) then
  local eventSettings = MSBTProfiles.CurrentProfile.EventSettings[this:GetParent().EventType];
  eventSettings.Disabled = not this:GetChecked() and true or nil;

 -- Always sticky event checkbox.
 elseif (string.find(this:GetName(), "StickyEventCheckbox")) then
  local eventSettings = MSBTProfiles.CurrentProfile.EventSettings[this:GetParent().EventType];
  eventSettings.AlwaysSticky = this:GetChecked() and true or nil;  
 end
end


-- **********************************************************************************
-- Handles button clicks for the events tab frame.
-- **********************************************************************************
function MikSBTOpt.EventsTabFrameButtonOnClick()
 -- Edit event message.
 if (string.find(this:GetName(), "EditEventMessageButton")) then
  local eventType = this:GetParent().EventType;

  -- Create config table for the detached input frame.
  local configTable = {};

  configTable.EditboxLabel = MSBTLocale.EDITBOXES["EventMessageEditbox"].Label;
  configTable.EditboxTooltip = MSBTLocale.EDITBOXES["EventMessageEditbox"].Tooltip;
  configTable.DefaultText = MSBTProfiles.CurrentProfile.EventSettings[eventType].Message;
  configTable.AnchorFrame = this;
  configTable.SaveFunc = MikSBTOpt.ChangeEventMessage;
  configTable.CustomArg1 = eventType;

  local found, _, lineNumber = string.find(this:GetName(), "ScrollLine(%d+)");
  if (found and tonumber(lineNumber) > 5) then
   configTable.AnchorPoint = "BOTTOMLEFT";
   configTable.RelativePoint = "TOPLEFT";
  end

  MikSBTOpt.ShowDetachedInputFrame(configTable);


 -- Event font settings button.
 elseif (string.find(this:GetName(), "FontSettingsButton")) then
  MikSBTOpt.ShowEventFontConfigFrame(this:GetParent().EventType);


 -- Event scroll area button.
 elseif (string.find(this:GetName(), "EventScrollAreaButton")) then
  local eventType = this:GetParent().EventType;

  -- Create config table for the scroll area selection.
  local configTable = {};

  configTable.Title = getglobal(this:GetParent():GetName() .. "EnableEventCheckboxText"):GetText();
  configTable.SelectedValue = MSBTProfiles.CurrentProfile.EventSettings[eventType].ScrollAreaIndex or MSBTDefaults.EventSettings.ScrollAreaIndex;
  configTable.AnchorFrame = this;
  configTable.SaveFunc = MikSBTOpt.ChangeEventScrollAreaIndex;
  configTable.CustomArg1 = eventType;
  MikSBTOpt.ShowScrollAreaSelectionFrame(configTable);
 end
end


-- **********************************************************************************
-- Called by the detached input frame with the message to change the passed event
-- type to.
-- **********************************************************************************
function MikSBTOpt.ChangeEventMessage(newMessage, eventType)
 MSBTProfiles.CurrentProfile.EventSettings[eventType].Message = newMessage;
 MikSBTOpt.EventsListUpdate();
end


-- **********************************************************************************
-- Show the font config for the passed event type.
-- **********************************************************************************
function MikSBTOpt.ShowEventFontConfigFrame(eventType)
  local eventSettings = MSBTProfiles.CurrentProfile.EventSettings[eventType];

  -- Create config table for font config frame.
  local configTable = {};

  configTable.DefaultNormalFontName = MikSBTOpt.GetValidFontName(eventSettings.NormalFontName or MSBTDefaults.EventSettings.NormalFontName, true)
  configTable.DefaultNormalOutlineIndex = eventSettings.NormalOutlineIndex or MSBTDefaults.EventSettings.NormalOutlineIndex;
  configTable.DefaultNormalFontSize = eventSettings.NormalFontSize or MSBTDefaults.EventSettings.NormalFontSize;
  configTable.DefaultCritFontName = MikSBTOpt.GetValidFontName(eventSettings.CritFontName or MSBTDefaults.EventSettings.CritFontName, true)
  configTable.DefaultCritOutlineIndex = eventSettings.CritOutlineIndex or MSBTDefaults.EventSettings.CritOutlineIndex;
  configTable.DefaultCritFontSize = eventSettings.CritFontSize or MSBTDefaults.EventSettings.CritFontSize;

  local scrollAreaSettings = MSBTProfiles.CurrentProfile.ScrollAreaSettings[eventSettings.ScrollAreaIndex or MSBTDefaults.EventSettings.ScrollAreaIndex];

  local inheritedNormalFontName = scrollAreaSettings.NormalFontName or MSBTDefaults.ScrollAreaSettings.NormalFontSettings;
  if (inheritedNormalFontName == 0) then
   inheritedNormalFontName = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontName;
  end
  configTable.InheritedNormalFontName = MikSBTOpt.GetValidFontName(inheritedNormalFontName, false);

  local inheritedNormalOutlineIndex = scrollAreaSettings.NormalOutlineIndex or MSBTDefaults.ScrollAreaSettings.NormalOutlineIndex;
  if (inheritedNormalOutlineIndex == 0) then
   inheritedNormalOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalOutlineIndex;
  end
  configTable.InheritedNormalOutlineIndex = inheritedNormalOutlineIndex;

  local inheritedNormalFontSize = scrollAreaSettings.NormalFontSize or MSBTDefaults.ScrollAreaSettings.NormalFontSize;
  if (inheritedNormalFontSize == 0) then
   inheritedNormalFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontSize;
  end
  configTable.InheritedNormalFontSize = inheritedNormalFontSize;


  local inheritedCritFontName = scrollAreaSettings.CritFontName or MSBTDefaults.ScrollAreaSettings.CritFontSettings;
  if (inheritedCritFontName == 0) then
   inheritedCritFontName = MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontName;
  end
  configTable.InheritedCritFontName = MikSBTOpt.GetValidFontName(inheritedCritFontName, false);

  local inheritedCritOutlineIndex = scrollAreaSettings.CritOutlineIndex or MSBTDefaults.ScrollAreaSettings.CritOutlineIndex;
  if (inheritedCritOutlineIndex == 0) then
   inheritedCritOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.CritOutlineIndex;
  end
  configTable.InheritedCritOutlineIndex = inheritedCritOutlineIndex;

  local inheritedCritFontSize = scrollAreaSettings.CritFontSize or MSBTDefaults.ScrollAreaSettings.CritFontSize;
  if (inheritedCritFontSize == 0) then
   inheritedCritFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontSize;
  end
  configTable.InheritedCritFontSize = inheritedCritFontSize;

  configTable.Title = getglobal(this:GetParent():GetName() .. "EnableEventCheckboxText"):GetText();
  configTable.AnchorFrame = this;
  configTable.CanInherit = true;
  configTable.CanCrit = eventSettings.CanCrit;
  configTable.SaveFunc = MikSBTOpt.SaveEventFontSettings;
  configTable.CustomArg1 = eventType;
  MikSBTOpt.ShowFontConfigFrame(configTable);
end


-- **********************************************************************************
-- Called by the font config frame with the new font settings.
-- **********************************************************************************
function MikSBTOpt.SaveEventFontSettings(fontSettingsTable, eventType)
 local eventSettings = MSBTProfiles.CurrentProfile.EventSettings[eventType];

 eventSettings.NormalFontName = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalFontName, MSBTDefaults.EventSettings.NormalFontName);
 eventSettings.NormalOutlineIndex = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalOutlineIndex, MSBTDefaults.EventSettings.NormalOutlineIndex);
 eventSettings.NormalFontSize = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalFontSize, MSBTDefaults.EventSettings.NormalFontSize);
 eventSettings.CritFontName = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritFontName, MSBTDefaults.EventSettings.CritFontName);
 eventSettings.CritOutlineIndex = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritOutlineIndex, MSBTDefaults.EventSettings.CritOutlineIndex);
 eventSettings.CritFontSize = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritFontSize, MSBTDefaults.EventSettings.CritFontSize);
end


-- **********************************************************************************
-- Called by the scrolla area selection frame with the new scroll area index
-- settings.
-- **********************************************************************************
function MikSBTOpt.ChangeEventScrollAreaIndex(newScrollAreaIndex, eventType)
 MSBTProfiles.CurrentProfile.EventSettings[eventType].ScrollAreaIndex = newScrollAreaIndex;
end


-------------------------------------------------------------------------------------
-- Triggers Tab Frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the scroll areas tab frame.
-- **********************************************************************************
function MikSBTOpt.InitTriggersTabFrame()
 -- Setup the help text.
 getglobal(OPTIONS_FRAME_NAME .. "Tab4FrameHelpText"):SetText(MSBTLocale.MSG_TRIGGERS_TAB_HELP);

 -- Setup the add scroll area and configure scroll areas buttons.
 local key = "Tab4FrameAddTriggerButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggersTabFrameButtonOnClick);

 -- Setup the scroll line buttons.
 for i = 1, 10 do
  local key = "TriggerSwatch";		MikSBTOpt.SetupColorSwatch(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MikSBTOpt.TriggersTabFrameColorSwatchOnChange);
  key = "EditTriggerMessageButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggersTabFrameButtonOnClick);
  key = "StickyTriggerCheckbox";		MikSBTOpt.SetupCheckbox(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.TriggersTabFrameCheckboxOnClick);
  key = "TriggerSettingsButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggersTabFrameButtonOnClick);
  key = "TriggerFontSettingsButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggersTabFrameButtonOnClick);
  key = "TriggerScrollAreaButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggersTabFrameButtonOnClick);
  key = "TriggerSoundSettingsButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggersTabFrameButtonOnClick);
  key = "DeleteTriggerButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.TriggersTabFrameButtonOnClick);
 end
end


-- **********************************************************************************
-- Refreshes the list of triggers.
-- **********************************************************************************
function MikSBTOpt.RefreshTriggersList()
 -- Clear the triggers list.
 local numTriggers = #triggersList;
 for x = numTriggers, 1, -1 do
  table.remove(triggersList);
 end

 -- Populate the triggers list.
 for triggerKey in pairs(MSBTProfiles.CurrentProfile.Triggers) do
  table.insert(triggersList, triggerKey);
 end

 -- Sort the triggers.
 table.sort(triggersList);
end


-- **********************************************************************************
-- Updates the scroll frame for the triggers list.
-- **********************************************************************************
function MikSBTOpt.TriggersListUpdate()
 local totalItems = #triggersList;

 local scrollFrame = getglobal(OPTIONS_FRAME_NAME .. "Tab4FrameScrollFrame");
 FauxScrollFrame_Update(scrollFrame, totalItems, 10, 25);
 local skipCount = FauxScrollFrame_GetOffset(scrollFrame);

 -- Loop through all of the scroll lines.
 local objScrollLine;
 for i = 1, 10 do
  -- Get the scroll line object.
  objScrollLine = getglobal(OPTIONS_FRAME_NAME .. "Tab4FrameScrollLine" .. i);

  -- Check if there is no data for the scroll line.
  if (i > totalItems) then
   objScrollLine:Hide();
  else
   objScrollLine:Show();

   objScrollLine.TriggerKey = triggersList[i+skipCount];
   local eventSettings = MSBTProfiles.CurrentProfile.Triggers[objScrollLine.TriggerKey].EventSettings;

   colorTable = eventSettings.Color or MSBTDefaults.EventSettings.Color;
   MikSBTOpt.PopulateColorSwatch(objScrollLine:GetName() .. "TriggerSwatch", colorTable.r, colorTable.g, colorTable.b);


   local key = "EnableTriggerCheckbox";
   MikSBTOpt.SetupCheckbox(objScrollLine:GetName() .. key, eventSettings.Message, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.TriggersTabFrameCheckboxOnClick);
   MikSBTOpt.PopulateCheckbox(objScrollLine:GetName() .. key, not eventSettings.Disabled);

   local key = "StickyTriggerCheckbox";
   MikSBTOpt.PopulateCheckbox(objScrollLine:GetName() .. key, eventSettings.AlwaysSticky);
  end
 end
end


-- **********************************************************************************
-- Called when a color swatch on the triggers tab frame changes.
-- **********************************************************************************
function MikSBTOpt.TriggersTabFrameColorSwatchOnChange(colorSwatch)
 -- Check if it's one of the trigger color swatches.
 if (string.find(colorSwatch:GetName(), "TriggerSwatch")) then
  local eventSettings = MSBTProfiles.CurrentProfile.Triggers[colorSwatch:GetParent().TriggerKey].EventSettings;

  -- Nil out the color table if the color matches the default to save space.
  if (colorSwatch.r == MSBTDefaults.EventSettings.Color.r and colorSwatch.g == MSBTDefaults.EventSettings.Color.g and colorSwatch.b == MSBTDefaults.EventSettings.Color.b) then
   eventSettings.Color = nil;
  else
   -- Create a color table for the event if there already isn't one.
   if (not eventSettings.Color) then eventSettings.Color = {}; end
   eventSettings.Color.r = colorSwatch.r;
   eventSettings.Color.g = colorSwatch.g;
   eventSettings.Color.b = colorSwatch.b;
  end
 end
end


-- **********************************************************************************
-- Handles checkbox clicks for the triggers tab frame.
-- **********************************************************************************
function MikSBTOpt.TriggersTabFrameCheckboxOnClick()
 -- Enable trigger checkbox.
 if (string.find(this:GetName(), "EnableTriggerCheckbox")) then
  local eventSettings = MSBTProfiles.CurrentProfile.Triggers[this:GetParent().TriggerKey].EventSettings;
  eventSettings.Disabled = not this:GetChecked() and true or nil;

  -- Reregister all of the triggers to update the changes.
  MSBTTriggers.RegisterAllTriggers();

 -- Always sticky trigger checkbox.
 elseif (string.find(this:GetName(), "StickyTriggerCheckbox")) then
  local eventSettings = MSBTProfiles.CurrentProfile.Triggers[this:GetParent().TriggerKey].EventSettings;
  eventSettings.AlwaysSticky = this:GetChecked() and true or nil;  
 end
end


-- **********************************************************************************
-- Handles button clicks for the triggers tab frame.
-- **********************************************************************************
function MikSBTOpt.TriggersTabFrameButtonOnClick()
 -- Add trigger message.
 if (string.find(this:GetName(), "AddTriggerButton")) then
  -- Hide all detached frames.
  MikSBTOpt.HideDetachedFrames();

  -- Add a new custom trigger.
  MikSBTOpt.AddTrigger();


 -- Edit trigger message.
 elseif (string.find(this:GetName(), "EditTriggerMessageButton")) then
  local triggerKey = this:GetParent().TriggerKey;

  -- Create config table for the detached input frame.
  local configTable = {};

  configTable.EditboxLabel = MSBTLocale.EDITBOXES["TriggerMessageEditbox"].Label;
  configTable.EditboxTooltip = MSBTLocale.EDITBOXES["TriggerMessageEditbox"].Tooltip;
  configTable.DefaultText = MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings.Message;
  configTable.AnchorFrame = this;
  configTable.SaveFunc = MikSBTOpt.ChangeTriggerMessage;
  configTable.CustomArg1 = triggerKey;

  local found, _, lineNumber = string.find(this:GetName(), "ScrollLine(%d+)");
  if (found and tonumber(lineNumber) > 5) then
   configTable.AnchorPoint = "BOTTOMLEFT";
   configTable.RelativePoint = "TOPLEFT";
  end

  MikSBTOpt.ShowDetachedInputFrame(configTable);


 -- Trigger settings button.
 elseif (string.find(this:GetName(), "TriggerSettingsButton")) then
  MikSBTOpt.ShowTriggerConfigFrame(this:GetParent().TriggerKey);


 -- Trigger font settings button.
 elseif (string.find(this:GetName(), "FontSettingsButton")) then
  MikSBTOpt.ShowTriggerFontConfigFrame(this:GetParent().TriggerKey);


 -- Trigger scroll area button.
 elseif (string.find(this:GetName(), "TriggerScrollAreaButton")) then
  local triggerKey = this:GetParent().TriggerKey;

  -- Create config table for the scroll area selection.
  local configTable = {};

  configTable.Title = getglobal(this:GetParent():GetName() .. "EnableTriggerCheckboxText"):GetText();
  configTable.SelectedValue = MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings.ScrollAreaIndex or MSBTDefaults.EventSettings.ScrollAreaIndex;
  configTable.AnchorFrame = this;
  configTable.SaveFunc = MikSBTOpt.ChangeTriggerScrollAreaIndex;
  configTable.CustomArg1 = triggerKey;
  MikSBTOpt.ShowScrollAreaSelectionFrame(configTable);


 -- Trigger sound settings button.
 elseif (string.find(this:GetName(), "TriggerSoundSettingsButton")) then
  local triggerKey = this:GetParent().TriggerKey;

  -- Create config table for the detached input frame.
  local configTable = {};

  configTable.EditboxLabel = MSBTLocale.EDITBOXES["TriggerSoundFileEditbox"].Label;
  configTable.EditboxTooltip = MSBTLocale.EDITBOXES["TriggerSoundFileEditbox"].Tooltip;
  configTable.DefaultText = MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings.SoundFile or "";
  configTable.AnchorPoint = "TOPRIGHT";
  configTable.AnchorFrame = this;
  configTable.RelativePoint = "BOTTOMRIGHT";
  configTable.SaveFunc = MikSBTOpt.ChangeTriggerSoundFile;
  configTable.CustomArg1 = triggerKey;

  local found, _, lineNumber = string.find(this:GetName(), "ScrollLine(%d+)");
  if (found and tonumber(lineNumber) > 5) then
   configTable.AnchorPoint = "BOTTOMRIGHT";
   configTable.RelativePoint = "TOPRIGHT";
  end

  MikSBTOpt.ShowDetachedInputFrame(configTable);


 -- Delete trigger button.
 elseif (string.find(this:GetName(), "DeleteTriggerButton")) then
   -- Create config table for the acknowledge frame.
  local configTable = {};

  configTable.AnchorFrame = this;
  configTable.AcknowledgeFunc = MikSBTOpt.DeleteTrigger;
  configTable.CustomArg1 = this:GetParent().TriggerKey;
  MikSBTOpt.ShowAcknowledgeFrame(configTable);

 end
end


-- **********************************************************************************
-- Called by the detached input frame with the message to change the passed trigger
-- key to.
-- **********************************************************************************
function MikSBTOpt.ChangeTriggerMessage(newMessage, triggerKey)
 MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings.Message = newMessage;
 MikSBTOpt.TriggersListUpdate();
end


-- **********************************************************************************
-- Show the font config for the passed event type.
-- **********************************************************************************
function MikSBTOpt.ShowTriggerFontConfigFrame(triggerKey)
  local eventSettings = MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings;

  -- Create config table for font config frame.
  local configTable = {};

  configTable.DefaultNormalFontName = MikSBTOpt.GetValidFontName(eventSettings.NormalFontName or MSBTDefaults.EventSettings.NormalFontName, true)
  configTable.DefaultNormalOutlineIndex = eventSettings.NormalOutlineIndex or MSBTDefaults.EventSettings.NormalOutlineIndex;
  configTable.DefaultNormalFontSize = eventSettings.NormalFontSize or MSBTDefaults.EventSettings.NormalFontSize;
  configTable.DefaultCritFontName = MikSBTOpt.GetValidFontName(eventSettings.CritFontName or MSBTDefaults.EventSettings.CritFontName, true)
  configTable.DefaultCritOutlineIndex = eventSettings.CritOutlineIndex or MSBTDefaults.EventSettings.CritOutlineIndex;
  configTable.DefaultCritFontSize = eventSettings.CritFontSize or MSBTDefaults.EventSettings.CritFontSize;

  local scrollAreaSettings = MSBTProfiles.CurrentProfile.ScrollAreaSettings[eventSettings.ScrollAreaIndex or MSBTDefaults.EventSettings.ScrollAreaIndex];

  local inheritedNormalFontName = scrollAreaSettings.NormalFontName or MSBTDefaults.ScrollAreaSettings.NormalFontSettings;
  if (inheritedNormalFontName == 0) then
   inheritedNormalFontName = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontName;
  end
  configTable.InheritedNormalFontName = MikSBTOpt.GetValidFontName(inheritedNormalFontName, false);

  local inheritedNormalOutlineIndex = scrollAreaSettings.NormalOutlineIndex or MSBTDefaults.ScrollAreaSettings.NormalOutlineIndex;
  if (inheritedNormalOutlineIndex == 0) then
   inheritedNormalOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalOutlineIndex;
  end
  configTable.InheritedNormalOutlineIndex = inheritedNormalOutlineIndex;

  local inheritedNormalFontSize = scrollAreaSettings.NormalFontSize or MSBTDefaults.ScrollAreaSettings.NormalFontSize;
  if (inheritedNormalFontSize == 0) then
   inheritedNormalFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.NormalFontSize;
  end
  configTable.InheritedNormalFontSize = inheritedNormalFontSize;


  local inheritedCritFontName = scrollAreaSettings.CritFontName or MSBTDefaults.ScrollAreaSettings.CritFontSettings;
  if (inheritedCritFontName == 0) then
   inheritedCritFontName = MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontName;
  end
  configTable.InheritedCritFontName = MikSBTOpt.GetValidFontName(inheritedCritFontName, false);

  local inheritedCritOutlineIndex = scrollAreaSettings.CritOutlineIndex or MSBTDefaults.ScrollAreaSettings.CritOutlineIndex;
  if (inheritedCritOutlineIndex == 0) then
   inheritedCritOutlineIndex = MSBTProfiles.CurrentProfile.MasterFontSettings.CritOutlineIndex;
  end
  configTable.InheritedCritOutlineIndex = inheritedCritOutlineIndex;

  local inheritedCritFontSize = scrollAreaSettings.CritFontSize or MSBTDefaults.ScrollAreaSettings.CritFontSize;
  if (inheritedCritFontSize == 0) then
   inheritedCritFontSize = MSBTProfiles.CurrentProfile.MasterFontSettings.CritFontSize;
  end
  configTable.InheritedCritFontSize = inheritedCritFontSize;

  configTable.Title = getglobal(this:GetParent():GetName() .. "EnableTriggerCheckboxText"):GetText();
  configTable.AnchorFrame = this;
  configTable.CanInherit = true;
  configTable.CanCrit = eventSettings.CanCrit;
  configTable.SaveFunc = MikSBTOpt.SaveTriggerFontSettings;
  configTable.CustomArg1 = triggerKey;
  MikSBTOpt.ShowFontConfigFrame(configTable);
end


-- **********************************************************************************
-- Called by the font config frame with the new font settings.
-- **********************************************************************************
function MikSBTOpt.SaveTriggerFontSettings(fontSettingsTable, triggerKey)
 local eventSettings = MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings;

 eventSettings.NormalFontName = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalFontName, MSBTDefaults.EventSettings.NormalFontName);
 eventSettings.NormalOutlineIndex = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalOutlineIndex, MSBTDefaults.EventSettings.NormalOutlineIndex);
 eventSettings.NormalFontSize = MikSBTOpt.GetPrunedValue(fontSettingsTable.NormalFontSize, MSBTDefaults.EventSettings.NormalFontSize);
 eventSettings.CritFontName = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritFontName, MSBTDefaults.EventSettings.CritFontName);
 eventSettings.CritOutlineIndex = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritOutlineIndex, MSBTDefaults.EventSettings.CritOutlineIndex);
 eventSettings.CritFontSize = MikSBTOpt.GetPrunedValue(fontSettingsTable.CritFontSize, MSBTDefaults.EventSettings.CritFontSize);
end


-- **********************************************************************************
-- Called by the scroll area selection frame with the new scroll area index
-- settings.
-- **********************************************************************************
function MikSBTOpt.ChangeTriggerScrollAreaIndex(newScrollAreaIndex, triggerKey)
 MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings.ScrollAreaIndex = newScrollAreaIndex;
end


-- **********************************************************************************
-- Called by the detached input frame with the sound file to change the passed trigger
-- key to.
-- **********************************************************************************
function MikSBTOpt.ChangeTriggerSoundFile(newSoundFile, triggerKey)
 if (newSoundfile ~= "") then
  MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings.SoundFile = newSoundFile;
 else
  MSBTProfiles.CurrentProfile.Triggers[triggerKey].EventSettings.SoundFile = nil;
 end
end


-- **********************************************************************************
-- Called by the acknowledge frame to delete the passed trigger.
-- **********************************************************************************
function MikSBTOpt.DeleteTrigger(triggerKey)
 -- Remove the trigger.
 MSBTProfiles.CurrentProfile.Triggers[triggerKey] = nil;

 -- Reregister the triggers to update the changes and then refresh the triggers list and
 -- update the scroll area to reflect the changes.
 MSBTTriggers.RegisterAllTriggers();
 MikSBTOpt.RefreshTriggersList();
 MikSBTOpt.TriggersListUpdate();
end


-- **********************************************************************************
-- Adds a new trigger.
-- **********************************************************************************
function MikSBTOpt.AddTrigger()
 -- Hold the next available custom trigger number.
 local nextTriggerNum = 0;

 -- Loop until an available slot is found.
 while (true) do
  -- Increment to the next trigger number.
  nextTriggerNum = nextTriggerNum + 1;

  -- Check if the custom trigger doesn't already exist and break out of the loop.
  if (not MSBTProfiles.CurrentProfile.Triggers["MSBT_CUSTOMTRIGGER_" .. nextTriggerNum]) then
   break;
  end
 end

 -- Create the new trigger.
 MSBTProfiles.CurrentProfile.Triggers["MSBT_CUSTOMTRIGGER_" .. nextTriggerNum] = {
  EventSettings = {
   Message			= MSBTLocale.MSG_NEW_TRIGGER,
  },
  TriggerSettings = {
   MainConditions = {},
  },
 };

 -- Reregister the triggers to update the changes and then refresh the triggers list and
 -- update the scroll area to reflect the changes.
 MSBTTriggers.RegisterAllTriggers();
 MikSBTOpt.RefreshTriggersList();
 MikSBTOpt.TriggersListUpdate();
end


-------------------------------------------------------------------------------------
-- Suppressions Tab Frame functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Initializes the suppressions tab frame.
-- **********************************************************************************
function MikSBTOpt.InitSuppressionsTabFrame()
 -- Setup the help text.
 getglobal(OPTIONS_FRAME_NAME .. "Tab5FrameHelpText"):SetText(MSBTLocale.MSG_SUPPRESSIONS_TAB_HELP);

 -- Setup the add scroll suppression button.
 local key = "Tab5FrameAddSuppressionButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. key, MSBTLocale.BUTTONS[key].Label, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.SuppressionsTabFrameButtonOnClick);

 -- Setup the scroll line buttons.
 for i = 1, 10 do
  local key = "EditSuppressionButton";	MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab5FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.SuppressionsTabFrameButtonOnClick);
  key = "DeleteSuppressionButton";		MikSBTOpt.SetupButton(OPTIONS_FRAME_NAME .. "Tab5FrameScrollLine" .. i .. key, nil, MSBTLocale.BUTTONS[key].Tooltip, MikSBTOpt.SuppressionsTabFrameButtonOnClick);
 end
end


-- **********************************************************************************
-- Refreshes the list of suppressions.
-- **********************************************************************************
function MikSBTOpt.RefreshSuppressionsList()
 -- Clear the suppressions list.
 local numSuppressions = #suppressionsList;
 for x = numSuppressions, 1, -1 do
  table.remove(suppressionsList);
 end

 -- Populate the suppresions list.
 for suppressionKey in pairs(MSBTProfiles.CurrentProfile.Suppressions) do
  table.insert(suppressionsList, suppressionKey);
 end

 -- Sort the suppressions.
 table.sort(suppressionsList);
end


-- **********************************************************************************
-- Updates the scroll frame for the suppressions list.
-- **********************************************************************************
function MikSBTOpt.SuppressionsListUpdate()
 local totalItems = #suppressionsList;

 local scrollFrame = getglobal(OPTIONS_FRAME_NAME .. "Tab5FrameScrollFrame");
 FauxScrollFrame_Update(scrollFrame, totalItems, 10, 25);
 local skipCount = FauxScrollFrame_GetOffset(scrollFrame);

 -- Loop through all of the scroll lines.
 local objScrollLine;
 for i = 1, 10 do
  -- Get the scroll line object.
  objScrollLine = getglobal(OPTIONS_FRAME_NAME .. "Tab5FrameScrollLine" .. i);

  -- Check if there is no data for the scroll line.
  if (i > totalItems) then
   objScrollLine:Hide();
  else
   objScrollLine:Show();

   objScrollLine.SuppressionKey = suppressionsList[i+skipCount];
   local suppressionSettings = MSBTProfiles.CurrentProfile.Suppressions[objScrollLine.SuppressionKey];

   local key = "EnableSuppressionCheckbox";
   MikSBTOpt.SetupCheckbox(objScrollLine:GetName() .. key, suppressionSettings.SearchPattern, MSBTLocale.CHECKBOXES[key].Tooltip, MikSBTOpt.SuppressionsTabFrameCheckboxOnClick);
   MikSBTOpt.PopulateCheckbox(objScrollLine:GetName() .. key, not suppressionSettings.Disabled);
  end
 end

end


-- **********************************************************************************
-- Handles checkbox clicks for the suppressions tab frame.
-- **********************************************************************************
function MikSBTOpt.SuppressionsTabFrameCheckboxOnClick()
 -- Enable suppression checkbox.
 if (string.find(this:GetName(), "EnableSuppressionCheckbox")) then
  MSBTProfiles.CurrentProfile.Suppressions[this:GetParent().SuppressionKey].Disabled = not this:GetChecked() and true or nil;

  -- Rehash all of the suppressions to update the changes.
  MSBTSuppressions.HashSuppressions();
 end
end


-- **********************************************************************************
-- Handles button clicks for the suppressions tab frame.
-- **********************************************************************************
function MikSBTOpt.SuppressionsTabFrameButtonOnClick()
 -- Add suppression.
 if (string.find(this:GetName(), "AddSuppressionButton")) then
  -- Hide all detached frames.
  MikSBTOpt.HideDetachedFrames();

  -- Add a new suppression.
  MikSBTOpt.AddSuppression();


 -- Edit suppression.
 elseif (string.find(this:GetName(), "EditSuppressionButton")) then
  local suppressionKey = this:GetParent().SuppressionKey;

  -- Create config table for the detached input frame.
  local configTable = {};

  configTable.EditboxLabel = MSBTLocale.EDITBOXES["SuppressionEditbox"].Label;
  configTable.EditboxTooltip = MSBTLocale.EDITBOXES["SuppressionEditbox"].Tooltip;
  configTable.DefaultText = MSBTProfiles.CurrentProfile.Suppressions[suppressionKey].SearchPattern;
  configTable.AnchorFrame = this;
  configTable.SaveFunc = MikSBTOpt.ChangeSuppressionSearchPattern;
  configTable.CustomArg1 = suppressionKey;

  local found, _, lineNumber = string.find(this:GetName(), "ScrollLine(%d+)");
  if (found and tonumber(lineNumber) > 5) then
   configTable.AnchorPoint = "BOTTOMLEFT";
   configTable.RelativePoint = "TOPLEFT";
  end

  MikSBTOpt.ShowDetachedInputFrame(configTable);


 -- Delete suppression button.
 elseif (string.find(this:GetName(), "DeleteSuppressionButton")) then
   -- Create config table for the acknowledge frame.
  local configTable = {};

  configTable.AnchorFrame = this;
  configTable.AcknowledgeFunc = MikSBTOpt.DeleteSuppression;
  configTable.CustomArg1 = this:GetParent().SuppressionKey;
  MikSBTOpt.ShowAcknowledgeFrame(configTable);

 end
end


-- **********************************************************************************
-- Adds a new suppression.
-- **********************************************************************************
function MikSBTOpt.AddSuppression()
 -- Hold the next available custom suppression number.
 local nextSuppressionNum = 0;

 -- Loop until an available slot is found.
 while (true) do
  -- Increment to the next suppression number.
  nextSuppressionNum = nextSuppressionNum + 1;

  -- Check if the custom suppression doesn't already exist and break out of the loop.
  if (not MSBTProfiles.CurrentProfile.Suppressions["MSBT_CUSTOMSUPPRESSION_" .. nextSuppressionNum]) then
   break;
  end
 end

 -- Create the new suppression.
 MSBTProfiles.CurrentProfile.Suppressions["MSBT_CUSTOMSUPPRESSION_" .. nextSuppressionNum] = {
  SearchPattern = MSBTLocale.MSG_NEW_SUPPRESSION;
 };

 -- Rehash the suppressions to update the changes and then refresh the suppressions list and
 -- update the scroll area to reflect the changes.
 MSBTSuppressions.HashSuppressions();
 MikSBTOpt.RefreshSuppressionsList();
 MikSBTOpt.SuppressionsListUpdate();
end


-- **********************************************************************************
-- Called by the detached input frame with the message to change the passed trigger
-- key to.
-- **********************************************************************************
function MikSBTOpt.ChangeSuppressionSearchPattern(newSearchPattern, suppressionKey)
 MSBTProfiles.CurrentProfile.Suppressions[suppressionKey].SearchPattern = newSearchPattern;
 MSBTSuppressions.HashSuppressions();
 MikSBTOpt.SuppressionsListUpdate();
end


-- **********************************************************************************
-- Called by the acknowledge frame to delete the passed suppression.
-- **********************************************************************************
function MikSBTOpt.DeleteSuppression(suppressionKey)
 -- Remove the suppression.
 MSBTProfiles.CurrentProfile.Suppressions[suppressionKey] = nil;

 -- Rehash the suppressions to update the changes and then refresh the suppressions list and
 -- update the scroll area to reflect the changes.
 MSBTSuppressions.HashSuppressions();
 MikSBTOpt.RefreshSuppressionsList();
 MikSBTOpt.SuppressionsListUpdate();
end


-------------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------------

-- **********************************************************************************
-- Returns the passed value if it is not the same as the default value, and nil if
-- it is
-- **********************************************************************************
function MikSBTOpt.GetPrunedValue(value, defaultValue)
 -- Return the passed value if it is different than the passed default value.
 if (value ~= defaultValue) then
  return value;
 end

 -- Return nil since the value matches the default.
 return nil;
end


-- **********************************************************************************
-- Returns the passed font name if it's valid otherwise returns the default font
-- name or 0 (inherit) if the canInherit flag is set.
-- **********************************************************************************
function MikSBTOpt.GetValidFontName(fontName, canInherit)
 if (not MikSBT.GetRegisteredFonts()[fontName]) then
  if (canInherit) then
   return 0;
  else
   return DEFAULT_FONT_NAME;
  end
 end

 return fontName;
end


-- **********************************************************************************
-- Initializes all of the tab frames.
-- **********************************************************************************
function MikSBTOpt.InitTabFrames()
 MikSBTOpt.InitGeneralTabFrame();
 MikSBTOpt.InitScrollAreasTabFrame();
 MikSBTOpt.InitEventsTabFrame();
 MikSBTOpt.InitTriggersTabFrame();
 MikSBTOpt.InitSuppressionsTabFrame();
end
