--[[
Titan [CritLine]

CritLine Concept by Sordit
Titan Conversion until version 0.3.7 by Uggh
Continued Development from 0.3.7 by FALLI

VERSION HISTORY:
Titan [CritLine] v0.4.0b
-fix some database issues

Titan [CritLine] v0.4.0a
-fix an issue that sometimes the database creation was not complete

Titan [CritLine] v0.4.0
-add an option to use the Titan Button with SHIFT key
-add a special mob filter (thanks to gogusrl) that filter out these mobs in existing records and future
 can turned on or off in the options dialog, if you do this, the old values were saved into the database
-add a new saved value (missed attacks), for future use

Titan [CritLine] v0.3.9b
-fix the bug that the critical splash message not showed correctly
-fix the issue the heals with the addon selfcast (or similar) not be counted 

Titan [CritLine] v0.3.9a
-add the help text for the options
-add some french translation, thanks to Feu
-fix a bug with the button, that highest filtered attacks shown on the button
-add a new message for criticals for the splash screen

Titan [CritLine] v0.3.9
-add an option to show all hits in the tooltip (only absolute hits, no misses)
-add a post records to channel function
-add to options panel when you click on the CL button should it be open the settings or post the data in the channel
-change the level adjustment setting to a slider, the default trivial setting in pvp by blizz is 10 level difference
-add a function for help text for each option, but I need translators for french (important)
-resize dynamically the filter options window

Titan [CritLine] v0.3.8
-add a filter option for the tooltip
-fix a few minor bugs

Titan [CritLine] v0.3.7d
-fix a bug with french translation
-made it compatible to game version 1.8.0

Titan [CritLine] v0.3.7c
-changed the combat log messages and add the new ones, for game version 1.7.0, add the new msgs to the code
-add crit percentage to tooltip, add checkbox for this to options frame
-override the original germann translation mistake for normal magic hits
-override the french translation with brackets '()' thanks to Franael

Titan [CritLine] v0.3.7
-Fixed an bug with DE and FR clients.

Titan [CritLine] v0.3.6
-Fixed an bug with DE client.

Titan [CritLine] v0.3.5
-Fixed an bug with DE clients crits not working.
-Fixed a bug with french text on the settings menu.

Titan [CritLine] v0.3.4
-Fixed an error with the French clients recording one hit as a Crit and Normal hit.
-Settings menu translated to French and German.
-Changed default for Level Adjustment to be off.

Titan [CritLine] v0.3.3
-Attempts to repair saved data information.
-Fixed an issue with French clients not recording hits.

Titan [CritLine] v0.3.2
-Fixed an issue with German clients not recording hits.
-Added Right-Click menu to toggle Icon/Text.
-Added better error handling and error recovery.

Titan [CritLine] v0.3.1
-Added command to rebuild data structure.
-Change archive format to .zip.

Titan [CritLine] v0.3
-Added level range filter.
-Added attack type to splash screen message (e.g. 'New Ambush Record!')
-Cleaned up summary tooltip.
-Added healing spells.

Titan [CritLine] v0.2
-Added settings menu
-Added Detailed summary for high damage attacks (ToolTip)
-Toggle for ScreenShot on new damage records.
-Toggle for counting PvP damage only.
-Toggle for sound
-Toggle Splash Screen

Titan [CritLine] v0.1
-Initial Release
]]

DEBUG = false; -- for internal testing only, left it to false !

--[[ global addon variables ]]
TITAN_CRITLINE_ID =  "CritLine";
TITAN_CRITLINE_VERSION = " v0.4.0b";
TITAN_CRITLINE_BUTTON_LABEL = "CL: ";
TITAN_CRITLINE_BUTTON_ICON = "Interface\\AddOns\\TitanCritLine\\TitanCritLine";
TITAN_CRITLINE_BUTTON_TEXT = "%s/%s";

HEADER_TEXT_COLOR  = "|cffffffff";
SUBHEADER_TEXT_COLOR  = "|cffCEA208";
BODY_TEXT_COLOR  = "|cffffffff";
HINT_TEXT_COLOR  = "|cff00ff00";

TCL_REALM = "";
TitanCritLine_PlayerRealmName = ""; -- only stored for compability reasons

TCL_MOBFILTER = {};

DAMAGE_TYPE_NONHEAL = "0";
DAMAGE_TYPE_HEAL =  "1";

--[[ functions for the setup dialog ]]
function tcl_DisplaySettings()
	TitanCritLine_SettingsFrame_HeaderText:SetText(TITAN_CRITLINE_ID.." "..TITAN_CRITLINE_MENU_SETTINGS);
	TitanCritLine_SettingsFrame_Option1Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_SPLASH_TEXT));
	TitanCritLine_SettingsFrame_Option1.HelpText = TITAN_CRITLINE_OPTION_SPLASH_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SPLASH"] == "1" ) then
		TitanCritLine_SettingsFrame_Option1:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option2Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_PLAYSOUNDS_TEXT));
	TitanCritLine_SettingsFrame_Option2.HelpText = TITAN_CRITLINE_OPTION_PLAYSOUNDS_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PLAYSOUND"] == "1" ) then
		TitanCritLine_SettingsFrame_Option2:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option3Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_PVPONLY_TEXT));
	TitanCritLine_SettingsFrame_Option3.HelpText = TITAN_CRITLINE_OPTION_PVPONLY_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PVPONLY"] == "1" ) then
		TitanCritLine_SettingsFrame_Option3:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option4Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_SCREENCAP_TEXT));
	TitanCritLine_SettingsFrame_Option4.HelpText = TITAN_CRITLINE_OPTION_SCREENCAP_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SNAPSHOT"] == "1" ) then
		TitanCritLine_SettingsFrame_Option4:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option7Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_SHOW_CRIT_TEXT));
	TitanCritLine_SettingsFrame_Option7.HelpText = TITAN_CRITLINE_OPTION_SHOW_CRIT_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] == "1" ) then
		TitanCritLine_SettingsFrame_Option7:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option8Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_SHOWHITS_TEXT));
	TitanCritLine_SettingsFrame_Option8.HelpText = TITAN_CRITLINE_OPTION_SHOWHITS_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] == "1" ) then
		TitanCritLine_SettingsFrame_Option8:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option5Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_ONCLICK_TEXT));
	TitanCritLine_SettingsFrame_Option5.HelpText = TITAN_CRITLINE_OPTION_ONCLICK_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] == "1" ) then
		TitanCritLine_SettingsFrame_Option5:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option9Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_SHIFT_ONCLICK_TEXT));
	TitanCritLine_SettingsFrame_Option9.HelpText = TITAN_CRITLINE_OPTION_SHIFT_ONCLICK_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] == "1" ) then
		TitanCritLine_SettingsFrame_Option9:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Option6Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_FILTER_HEALING_TEXT));
	TitanCritLine_SettingsFrame_Option6.HelpText = TITAN_CRITLINE_OPTION_FILTER_HEALING_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] == "1" ) then
		TitanCritLine_SettingsFrame_Option6:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Slider1:SetValue(tonumber(TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"]));
	TitanCritLine_SettingsFrame_Slider1Text1:SetText(TITAN_CRITLINE_OPTION_LVLADJ_TEXT);
	TitanCritLine_SettingsFrame_Slider1.HelpText = TITAN_CRITLINE_OPTION_LVLADJ_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"] == "0" ) then
		TitanCritLine_SettingsFrame_Slider1Text2:SetText("Off");
	else
		TitanCritLine_SettingsFrame_Slider1Text2:SetText(TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"]);
	end
	TitanCritLine_SettingsFrame_Option10Text:SetText(COLOR(SUBHEADER_TEXT_COLOR, TITAN_CRITLINE_OPTION_MOBFILTER_TEXT));
	TitanCritLine_SettingsFrame_Option10.HelpText = TITAN_CRITLINE_OPTION_MOBFILTER_HELPTEXT;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] == "1" ) then
		TitanCritLine_SettingsFrame_Option10:SetChecked(true);
	end
	TitanCritLine_SettingsFrame_Slider1:Show();
	TitanCritLine_SettingsFrame:Show();
end

function tcl_SettingsOptionButton_OnClick(arg1)
	if ( arg1 == 1 ) then
		tcl_ToggleSplash();
	elseif ( arg1 == 2 ) then
		tcl_ToggleSound();
	elseif ( arg1 == 3 ) then
		tcl_TogglePvP();
	elseif ( arg1 == 4 ) then
		tcl_ToggleScreenShots();
	elseif ( arg1 == 5 ) then
		tcl_ToggleOnClick();
	elseif ( arg1 == 6 ) then
		tcl_ToggleHealing();
	elseif ( arg1 == 7 ) then
		tcl_ToggleShowCrit();
	elseif ( arg1 == 8 ) then
		tcl_ToggleShowHits();
	elseif ( arg1 == 9 ) then
		tcl_ToggleShiftOnClick();
	elseif ( arg1 == 10 ) then
		tcl_ToggleMobFilter();
	end
	TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
end

function tcl_SettingsOptionButton_OnEnter(button)
	GameTooltip:SetOwner(button, "ANCHOR_NONE");
	GameTooltip:SetPoint("TOPLEFT", button:GetName(), "BOTTOMLEFT", -10, -4);
	GameTooltip:SetText(button.HelpText);
	GameTooltip:Show();
end

function tcl_SettingsOptionButton_OnLeave()
	GameTooltip:Hide();
end

function tcl_SettingsSlider_OnValueChanged()
	local lvladj = TitanCritLine_SettingsFrame_Slider1:GetValue();
	if ( lvladj == 0 ) then
		TitanCritLine_SettingsFrame_Slider1Text2:SetText("Off");
	else
		TitanCritLine_SettingsFrame_Slider1Text2:SetText(tostring(lvladj));
	end
	TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"] = tostring(lvladj);
	tcl_DEBUG(TITAN_CRITLINE_ID.." level adjustment set to "..tostring(lvladj));
end

function tcl_ToggleShowHits()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." show all hits is on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] = "0";
		tcl_DEBUG(TITAN_CRITLINE_ID.." show all hits is off");
	end
end

function tcl_ToggleOnClick()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] = "1";
		TitanCritLine_SettingsFrame_Option9:Enable();
		tcl_DEBUG(TITAN_CRITLINE_ID.." post to chat on click is on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] = "0";
		TitanCritLine_SettingsFrame_Option9:Disable();
		tcl_DEBUG(TITAN_CRITLINE_ID.." post to chat on click is off");
	end
end

function tcl_ToggleShiftOnClick()
	if ( TitanCritLine_SettingsFrame_Option9:IsEnabled() ) then
		if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] == "0" ) then
			TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] = "1";
			tcl_DEBUG(TITAN_CRITLINE_ID.." post to chat on SHIFT click is on");
		else
			TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] = "0";
			tcl_DEBUG(TITAN_CRITLINE_ID.." post to chat on SHIFT click is off");
		end
	end
end

function tcl_ToggleScreenShots()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SNAPSHOT"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SNAPSHOT"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." screen shots on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SNAPSHOT"] = "0";
		tcl_DEBUG(TITAN_CRITLINE_ID.." screen shots off");
	end
end

function tcl_ToggleSound()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PLAYSOUND"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PLAYSOUND"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." sound on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PLAYSOUND"] = "0";
		tcl_DEBUG(TITAN_CRITLINE_ID.." sound off");
	end
end

function tcl_TogglePvP()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PVPONLY"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PVPONLY"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." pvponly on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PVPONLY"] = "0";
		tcl_DEBUG(TITAN_CRITLINE_ID.." pvponly off");
	end
end

function tcl_ToggleSplash()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SPLASH"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SPLASH"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." splash on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SPLASH"] = "0";
		info.checked = 0;
		tcl_DEBUG(TITAN_CRITLINE_ID.." splash off");
	end
end

function tcl_ToggleHealing()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." filter healing on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] = "0";
		tcl_DEBUG(TITAN_CRITLINE_ID.." filter healing off");
	end
end

function tcl_ToggleShowCrit()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." show crit percentage on");
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] = "0";
		tcl_DEBUG(TITAN_CRITLINE_ID.." show crit percentage off");
	end
end

function tcl_ToggleMobFilter()
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] == "0" ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] = "1";
		tcl_DEBUG(TITAN_CRITLINE_ID.." filter mobs on");
		tcl_DeleteAllRecordsWithMobsInFilter();
	else
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] = "0";
		tcl_DEBUG(TITAN_CRITLINE_ID.." filter mobs off");
		tcl_RestoreAllRecordsWithMobsInFilter();
	end
end

function tcl_Reset()
	TCL_SETTINGS[TCL_REALM]["DATA"] = {};
	TitanPanelCritLineButtonText:SetText(TitanPanelCritLine_GetButtonText(0));
end

function tcl_ResetAll()
	TCL_SETTINGS = {};
	tcl_Initialize();
	TitanPanelCritLineButtonText:SetText(TitanPanelCritLine_GetButtonText(0));
end

function tcl_SettingsClose()
	if ( TitanCritLine_FilterFrame:IsVisible() ) then
		tcl_FilterClose();
	end
	TitanCritLine_SettingsFrame:Hide();
	TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
end

function tcl_Filter()
	if ( TitanCritLine_FilterFrame:IsVisible() ) then
		tcl_FilterClose();
	else
		local i = 1;
		for k,v in pairs(TCL_SETTINGS[TCL_REALM]["DATA"]) do
			tcl_DEBUG("create button no."..tostring(i).." for "..k);
			local button = getglobal("TitanCritLine_FilterFrame_Option"..tostring(i));
			local text = getglobal("TitanCritLine_FilterFrame_Option"..tostring(i).."Text");
			text:Show();
			text:SetText(k);
			button:Show();
			if (TCL_SETTINGS[TCL_REALM]["DATA"][k]["Filter"] == "1") then
				button:SetChecked(true);
			end
			i = i + 1;
			if ( i > 20 ) then
				do break end
			end
		end
		local height = i * 24 + 20;
		TitanCritLine_FilterFrame:SetHeight(height);
		TitanCritLine_FilterFrame:SetPoint("LEFT", "TitanCritLine_SettingsFrame", "RIGHT", 5, 0);
		TitanCritLine_FilterFrame:Show();
	end
end

function tcl_FilterOptionButton_OnClick(id)
	local button = getglobal("TitanCritLine_FilterFrame_Option"..tostring(id));
	local attacktype = getglobal("TitanCritLine_FilterFrame_Option"..tostring(id).."Text"):GetText();
	if ( button:GetChecked() ) then
		tcl_DEBUG(attacktype.." filter is on");
		TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["Filter"] = "1";
	else
		tcl_DEBUG(attacktype.." filter is off");
		TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["Filter"] = "0";
	end
	TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
end

function tcl_FilterClose()
	TitanCritLine_FilterFrame:Hide();
	for i = 1, 20, 1 do
		local button = getglobal("TitanCritLine_FilterFrame_Option"..tostring(i));
		local text = getglobal("TitanCritLine_FilterFrame_Option"..tostring(i).."Text");
		button:SetChecked(false);
		button:Hide();
		text:SetText(nil);
		text:Hide();
	end
	TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
end

function tcl_ManualUpdate()
	tcl_Update(TCL_SETTINGS["VERSION"]);
end

--[[ titan panel functions ]]
function TitanPanelRightClickMenu_PrepareCritLineMenu()
	local id = TITAN_CRITLINE_ID;
	TitanPanelRightClickMenu_AddTitle(TitanPlugins[id].menuText..TITAN_CRITLINE_VERSION);
	local info = {};
	info.text = TITAN_CRITLINE_MENU_SETTINGS;
	info.func = tcl_DisplaySettings;
	UIDropDownMenu_AddButton(info);
	TitanPanelRightClickMenu_AddSpacer();
	local info2 = {};
	info2.text = TITAN_CRITLINE_MENU_POSTGUILD;
	info2.func = tcl_PostToGuild;
	local info3 = {};
	info3.text = TITAN_CRITLINE_MENU_POSTPARTY;
	info3.func = tcl_PostToParty;
	local info4 = {};
	info4.text = TITAN_CRITLINE_MENU_POSTRAID;
	info4.func = tcl_PostToRaid;
	UIDropDownMenu_AddButton(info2);
	UIDropDownMenu_AddButton(info3);
	UIDropDownMenu_AddButton(info4);
	TitanPanelRightClickMenu_AddSpacer();
	TitanPanelRightClickMenu_AddToggleIcon(id);
	TitanPanelRightClickMenu_AddToggleLabelText(id);
	TitanPanelRightClickMenu_AddSpacer();
	TitanPanelRightClickMenu_AddCommand(TITAN_PANEL_MENU_HIDE, id, TITAN_PANEL_MENU_FUNC_HIDE);
end

function TitanPanelCritLine_GetButtonText(id)
	local buttonRichText = format(TITAN_CRITLINE_BUTTON_TEXT, COLOR(BODY_TEXT_COLOR, tcl_GetHighestDamage()), COLOR(BODY_TEXT_COLOR, tcl_GetHighestCrit()));
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] == "0") then
		buttonRichText = buttonRichText.." - "..format(TITAN_CRITLINE_BUTTON_TEXT, COLOR(BODY_TEXT_COLOR, tcl_GetHighestHeal()), COLOR(BODY_TEXT_COLOR, tcl_GetHighestHealCrit()));
	end
	tcl_DEBUG("TitanPanelCritLine_GetButtonText: "..TITAN_CRITLINE_BUTTON_LABEL..buttonRichText);
	return TITAN_CRITLINE_BUTTON_LABEL, buttonRichText;
end

--[[ addon functions ]]
function tcl_OnLoad()
	this.registry = { 
		id = TITAN_CRITLINE_ID,
		menuText = TITAN_CRITLINE_ID, 
		buttonTextFunction = "TitanPanelCritLine_GetButtonText", 
		tooltipTitle = TITAN_CRITLINE_ID.." "..TITAN_CRITLINE_TOOLTIP_HEADER.." "..TITAN_CRITLINE_VERSION,
		tooltipTextFunction = "tcl_GetSummaryRichText", 
		icon = TITAN_CRITLINE_BUTTON_ICON,
		iconWidth = 16,
		savedVariables = {
			ShowIcon = 1,
			ShowLabelText = 1,
		}
	};
	this:RegisterEvent("PLAYER_ENTERING_WORLD");
	this:RegisterEvent("CHAT_MSG_COMBAT_SELF_HITS");
	this:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE");
	this:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF");
	this:RegisterEvent("CHAT_MSG_COMBAT_SELF_MISSES");
	tcl_Msg(TITAN_CRITLINE_ID.." "..TITAN_CRITLINE_VERSION.." loaded.");
end

function tcl_OnUpdate(elapsed)
	
end

function tcl_OnEvent()
	tcl_DEBUG("Received Event: "..event);
	if (event == "PLAYER_ENTERING_WORLD") then
		if (TCL_SETTINGS == nil) then
			TCL_SETTINGS = {};
		end
		if (TCL_SETTINGS["VERSION"] == nil) then
			tcl_Update("UNKNOWN");
		elseif (TCL_SETTINGS["VERSION"] ~= TITAN_CRITLINE_VERSION) then
			tcl_Update(TCL_SETTINGS["VERSION"]);
		else
			tcl_Initialize();
		end
		tcl_CreateMobFilter();
		TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
		TitanPanelButton_UpdateTooltip();
	elseif (event == "CHAT_MSG_SPELL_SELF_BUFF") then
		if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] == "0") then
			for attacktype, creaturename, damage in string.gfind(arg1, HEAL_SPELL_CRIT_MSG) do
				tcl_RecordHit(attacktype, "CRIT", tonumber(damage), creaturename, DAMAGE_TYPE_HEAL);
				return;
			end
			for attacktype, creaturename, damage in string.gfind(arg1, HEAL_SPELL_HIT_MSG) do
				tcl_RecordHit(attacktype, "NORMAL", tonumber(damage), creaturename, DAMAGE_TYPE_HEAL);
				return;
			end
		end
	elseif (event == "CHAT_MSG_COMBAT_SELF_HITS") then
		for creaturename, damage in string.gfind(arg1, COMBAT_CRIT_MSG)do
			tcl_DEBUG("Crit Hit: "..creaturename.." for "..damage);
			tcl_RecordHit(NORMAL_HIT_TEXT, "CRIT", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
		for creaturename, damage, damagetype in string.gfind(arg1, COMBAT_CRIT_SCHOOL_MSG)do
			tcl_DEBUG("Crit School Hit: "..creaturename.." for "..damagetype.." "..damage);
			tcl_RecordHit(NORMAL_HIT_TEXT, "CRIT", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
		for creaturename, damage in string.gfind(arg1, COMBAT_HIT_MSG) do
			tcl_DEBUG("Regular Hit: "..creaturename.." for "..damage);
			tcl_RecordHit(NORMAL_HIT_TEXT, "NORMAL", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
		for creaturename, damage, damagetype in string.gfind(arg1, COMBAT_HIT_SCHOOL_MSG) do
			tcl_DEBUG("Regular School Hit: "..creaturename.." for "..damagetype.." "..damage);
			tcl_RecordHit(NORMAL_HIT_TEXT, "NORMAL", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
	elseif (event == "CHAT_MSG_SPELL_SELF_DAMAGE") then
		for attacktype, creaturename, damage in string.gfind(arg1, SPELL_CRIT_MSG) do
			tcl_DEBUG(attacktype.." Crit: "..creaturename.." for "..damage);
			tcl_RecordHit(attacktype, "CRIT", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
		for attacktype, creaturename, damage, damagetype in string.gfind(arg1, SPELL_CRIT_SCHOOL_MSG) do
			tcl_DEBUG(attacktype.." School Crit: "..creaturename.." for "..damagetype.." "..damage);
			tcl_RecordHit(attacktype, "CRIT", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
		for attacktype, creaturename, damage in string.gfind(arg1, SPELL_HIT_MSG) do
			tcl_DEBUG(attacktype.." Hit: "..creaturename.." for "..damage);
			tcl_RecordHit(attacktype, "NORMAL", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
		for attacktype, creaturename, damage, damagetype in string.gfind(arg1, SPELL_HIT_SCHOOL_MSG) do
			tcl_DEBUG(attacktype.." School Hit: "..creaturename.." for "..damagetype.." "..damage);
			tcl_RecordHit(attacktype, "NORMAL", tonumber(damage), creaturename, DAMAGE_TYPE_NONHEAL);
			return;
		end
		tcl_RecordMiss(arg1);
	elseif ( event == "CHAT_MSG_COMBAT_SELF_MISSES") then
		tcl_RecordMiss(arg1);
	end
end

function tcl_OnClick(button)
	if (button == "LeftButton") then
		if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] == "1" ) then
			if ( IsShiftKeyDown() ) then
				if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] == "0" ) then
					tcl_DisplaySettings();
				else
					tcl_PostMessage();
				end
			else
				return;
			end
		else
			if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] == "0" ) then
				tcl_DisplaySettings();
			else
				tcl_PostMessage();
			end
		end
	end
end

function tcl_Update(version)
	tcl_Msg("Updating "..TITAN_CRITLINE_ID.." from version "..version.." to version "..TITAN_CRITLINE_VERSION.." ...");
	-- set global variables
	TCL_REALM = GetCVar("realmName");
	tcl_Initialize();
	TCL_SETTINGS["VERSION"] = TITAN_CRITLINE_VERSION;
	-- check for old titan critline data
	if (TitanCritLineSettings == nil) then
		tcl_Msg("No old Titan Critline database found, creating new database for "..UnitName("player")..".");
	else
		TitanCritLine_PlayerRealmName = GetCVar("realmName").."."..UnitName("player");
		if (TitanCritLineSettings[TitanCritLine_PlayerRealmName] == nil) then
			tcl_Msg("Old Titan CritLine database found, but not for "..UnitName("player")..", creating new one.");
		else
			if ( table.getn(TCL_SETTINGS[TCL_REALM]["DATA"]) == nil or table.getn(TCL_SETTINGS[TCL_REALM]["DATA"]) == 0 ) then
				tcl_Msg("Updating old Titan CritLine data ...");
				for k,v in pairs(TitanCritLineSettings[TitanCritLine_PlayerRealmName]["SETTINGS"]) do
					TCL_SETTINGS[TCL_REALM]["SETTINGS"][k] = v;
				end
				for k,v in pairs(TitanCritLineSettings[TitanCritLine_PlayerRealmName]["DATA"]) do
					attacktype = k;
					TCL_SETTINGS[TCL_REALM]["DATA"][attacktype] = {};
					TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["Filter"] = "0";
					for k,v in pairs(TitanCritLineSettings[TitanCritLine_PlayerRealmName]["DATA"][attacktype]) do
						hittype = k;
						TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype] = {};
						for k,v in pairs(TitanCritLineSettings[TitanCritLine_PlayerRealmName]["DATA"][attacktype][hittype]) do
							TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype][k] = v;
						end
						if (TitanCritLineSettings[TitanCritLine_PlayerRealmName]["DATA"][attacktype][hittype]["Value"] == nil) then
							TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype]["Value"] = 0;
						end
					end
				end
				TitanCritLineSettings[TitanCritLine_PlayerRealmName] = nil;
			else
				tcl_Msg("New data was found, no update needed ...");
			end
		end
	end
	--add changes to database
	tcl_Msg("Updating main database ...");
	for k, v in pairs(TCL_SETTINGS[TCL_REALM]["DATA"]) do
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["Misses"] == nil ) then
			TCL_SETTINGS[TCL_REALM]["DATA"][k]["Misses"] = 0;
		end
	end
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] == nil ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] = "0";
	end
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] == nil ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] = "1";
	end
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] == nil ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] = "0";
	end
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] == nil ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] = "0";
	end
	-- update complete
	tcl_Msg("Update complete, read the UPDATE.TXT file in the addon directory!");
end

function tcl_Initialize()
	tcl_DEBUG("Initializing...");
	TCL_REALM = GetCVar("realmName");
	if (TCL_SETTINGS == nil) then
		TCL_SETTINGS = {};
	end
	if (TCL_SETTINGS["VERSION"] == nil) then
		TCL_SETTINGS["VERSION"] = TITAN_CRITLINE_VERSION;
	end
	if (TCL_SETTINGS[TCL_REALM] == nil) then
		TCL_SETTINGS[TCL_REALM] = {};
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"] = {};
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] = "1";
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"] = "0";
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SPLASH"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SPLASH"] = "1";
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PVPONLY"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PVPONLY"] = "0";
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PLAYSOUND"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PLAYSOUND"] = "1";
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SNAPSHOT"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SNAPSHOT"] = "0";
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] = "1";
	end
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] == nil ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] = "1";
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["ONCLICK"] = "1"
	end
	if (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] == nil) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHIFTONCLICK"] = "1";
	end
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] == nil ) then
		TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] = "1";
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"] == nil) then
		TCL_SETTINGS[TCL_REALM]["DATA"] = {};
	end
	tcl_DEBUG("Initialization Complete.");
end

function tcl_CreateMobFilter()
	tcl_DEBUG("Creating Mob Filter...");
	table.insert(TCL_MOBFILTER, TITAN_CRITLINE_MOBFILTER_01);
	table.insert(TCL_MOBFILTER, TITAN_CRITLINE_MOBFILTER_02);
	table.insert(TCL_MOBFILTER, TITAN_CRITLINE_MOBFILTER_03);
    table.insert(TCL_MOBFILTER, TITAN_CRITLINE_MOBFILTER_04);
    table.insert(TCL_MOBFILTER, TITAN_CRITLINE_MOBFILTER_05);
	tcl_DEBUG("Creation complete.");
end

function tcl_IsMobInFilter(mobname)
	local returnvalue = false;
	for k, v in pairs(TCL_MOBFILTER) do
		if ( v == mobname ) then
			tcl_DEBUG("Name of Mob ("..mobname..") is in Filter ...");
			returnvalue = true;
			do break end;
		end
	end
	tcl_DEBUG("Name of Mob ("..mobname..") is NOT in Filter ...");
	return returnvalue;
end

function tcl_DeleteAllRecordsWithMobsInFilter()
	tcl_DEBUG("Search for filtered mobs and delte them ...");
	for k, v in pairs(TCL_SETTINGS[TCL_REALM]["DATA"]) do
		attacktype = k;
		for k, v in pairs(TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]) do
			if ( k == "CRIT" or k == "NORMAL" ) then
				local hittype = k;
				if ( tcl_IsMobInFilter(TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype]["Target"]) ) then
					tcl_DEBUG("Mob found, backup stats ...");
					local filtered = "FILTER_"..hittype;
					local backup = "OLD_"..hittype;
					TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][filtered] = {};
					TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][filtered] = TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype];
					if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][backup] == nil ) then
						table.remove(TCL_SETTINGS[TCL_REALM]["DATA"][attacktype], hittype);
					else
						TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype] = TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][backup];
					end
				end
			end
		end
	end
	tcl_DEBUG("All filtered mobs deleted if found.");
	TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
end

function tcl_RestoreAllRecordsWithMobsInFilter()
	tcl_DEBUG("Restore all records with filtered mobs ...");
	for k, v in pairs(TCL_SETTINGS[TCL_REALM]["DATA"]) do
		attacktype = k;
		for k, v in pairs(TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]) do
			if ( k == "CRIT" or k == "NORMAL" ) then
				local hittype = k;
				if ( tcl_IsMobInFilter(TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype]["Target"]) ) then
					tcl_DEBUG("Mob found, restoring stats ...");
					local filtered = "FILTER_"..hittype;
					local backup = "OLD_"..hittype;
					if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][filtered] ~= nil ) then
						if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][backup] == nil ) then
							TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][backup] = {};
							TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][backup] = TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype];
						end
						TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][hittype] = TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][filtered];
					end
				end
			end
		end
	end
	tcl_DEBUG("All records with filtered mobs are restored.");
	TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
end

function tcl_RecordHit(AttackType, HitType, Damage, uname, IsHealing)
	local targetlvl = UnitLevel("target");
	local ulevel = false;
	if (targetlvl == nil) then 
		targetlvl = 0;
	end
	if (Damage == nil) then
		tcl_DEBUG("No Damage! exiting...");
		return;
	end
	if (uname == nil) then 
		uname = "??"; 
	end
	if (not UnitExists("target")) then
		if (IsHealing == DAMAGE_TYPE_HEAL) then
			uname = UnitName("player");
			ulevel = UnitLevel("player");
		else
			tcl_DEBUG("No Target! exiting...");
			return;
		end
	end
	if (IsHealing == nil) then
		tcl_DEBUG("IsHealing==nil! exiting...");
		return;
	end
	if ( (UnitIsPlayer("target") ~= 1) and (TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PVPONLY"] == "1") ) then
		tcl_DEBUG("Target !=player and PvPOnly enabled, exiting...");
		return;
	end
	local leveldiff = 0;
	if (UnitLevel("player") < UnitLevel("target")) then
		leveldiff = (UnitLevel("target") - UnitLevel("player"));
	else
		leveldiff = (UnitLevel("player") - UnitLevel("target"));
	end
	tcl_DEBUG("Level difference: "..leveldiff);
	if ( (tonumber(TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"]) ~= 0) and (tonumber(TCL_SETTINGS[TCL_REALM]["SETTINGS"]["LVLADJ"]) < leveldiff) ) then
		tcl_DEBUG("Target level too low and LvlAdj enabled, exiting...");
		return;
	end
	if (TCL_SETTINGS == nil) then
		return;
	end
	if (TCL_SETTINGS[TCL_REALM] == nil) then
		tcl_DEBUG("TCL_SETTINGS[TCL_REALM] should not be nil at this point!");
		tcl_Initialize();
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"] == nil) then
		tcl_DEBUG("TCL_SETTINGS[TCL_REALM][DATA] should not be nil at this point!");
		tcl_Initialize();
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"][AttackType] == nil) then
		tcl_DEBUG("Creating TCL_SETTINGS["..TCL_REALM.."][DATA]["..AttackType.."]...");
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType] = {};
	end
	if ( TCL_SETTINGS[TCL_REALM]["DATA"][AttackType]["Filter"] == nil ) then
		tcl_DEBUG("Creating TCL_SETTINGS["..TCL_REALM.."][DATA]["..AttackType.."][Filter]...");
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType]["Filter"] = "0";
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType] == nil) then
		tcl_DEBUG("Creating TCL_SETTINGS["..TCL_REALM.."][DATA]["..AttackType.."]["..HitType.."]...");
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType] = {};
	end
	if ( TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Value"] == nil ) then
		tcl_DEBUG("Creating TCL_SETTINGS["..TCL_REALM.."][DATA]["..AttackType.."]["..HitType.."][Value]...");
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Value"] = 0;
	end
	local oldhitvalue = TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Value"];
	TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Value"] = oldhitvalue + 1;
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_MOBS"] == "1" ) then
		if ( tcl_IsMobInFilter(uname) ) then
			return;
		end
	end
	if ( TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Damage"] == nil or TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Damage"] < Damage ) then
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Damage"] = Damage;
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Target"] = uname;
		if ( ulevel ) then
			TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Level"] = ulevel;
		else
			TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Level"] = UnitLevel("target");
		end
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["Date"] = date();
		TCL_SETTINGS[TCL_REALM]["DATA"][AttackType][HitType]["IsHeal"] = IsHealing;
		tcl_DisplayNewRecord(AttackType, Damage, HitType);
	end
end

function tcl_RecordMiss(text)
	if ( text == nil ) then
		tcl_DEBUG("RecordMiss text value is nil, return.");
		return;
	end
	if ( string.find(text, "(%d+)") ) then
		tcl_DEBUG("RecordMiss found a number in text, return.");
		return;
	else
		for k, v in pairs(TCL_SETTINGS[TCL_REALM]["DATA"]) do
			attacktype = k;
			if ( string.find(text, attacktype) ) then
				tcl_DEBUG("RecordMiss found "..attacktype.." in text, add a miss and return.");
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["Misses"] == nil ) then
					TCL_SETTINGS[TCL_REALM]["DATA"][k]["Misses"] = 1;
					do return end;
				else
					local oldvalue = TCL_SETTINGS[TCL_REALM]["DATA"][k]["Misses"];
					TCL_SETTINGS[TCL_REALM]["DATA"][k]["Misses"] = oldvalue + 1;
					do return end;
				end
			end
		end
		tcl_DEBUG("RecordMiss found no attacktype in text.");
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][NORMAL_HIT_TEXT] == nil ) then
			tcl_DEBUG("RecordMiss creating TCL_SETTINGS["..TCL_REALM.."][DATA]["..NORMAL_HIT_TEXT.."].");
			TCL_SETTINGS[TCL_REALM]["DATA"][NORMAL_HIT_TEXT] = {};
		end
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][NORMAL_HIT_TEXT]["Misses"] == nil ) then
			tcl_DEBUG("RecordMiss creating TCL_SETTINGS["..TCL_REALM.."][DATA]["..NORMAL_HIT_TEXT.."][Misses] = 1.");
			TCL_SETTINGS[TCL_REALM]["DATA"][NORMAL_HIT_TEXT]["Misses"] = 1;
			return;
		else
			tcl_DEBUG("RecordMiss add a miss to "..NORMAL_HIT_TEXT..".");
			local oldvalue = TCL_SETTINGS[TCL_REALM]["DATA"][NORMAL_HIT_TEXT]["Misses"];
			TCL_SETTINGS[TCL_REALM]["DATA"][NORMAL_HIT_TEXT]["Misses"] = oldvalue + 1;
			return;
		end
	end
	tcl_DEBUG("RecordMiss found nothing and return.");
end

function tcl_DisplayNewRecord(AttackType, DamageAmount, HitType)
	local splash_msg = TITAN_CRITLINE_NEW_RECORD_MSG;
	if ( HitType == "CRIT" ) then
		splash_msg = TITAN_CRITLINE_NEW_CRIT_RECORD_MSG;
	end
	tcl_DEBUG(format(splash_msg, AttackType));
	if(TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SPLASH"] == "1") then
		TitanCritLineSplashFrame:AddMessage(DamageAmount, 1, 1, 1, 1, 3);
		TitanCritLineSplashFrame:AddMessage(format(splash_msg, AttackType), 1, 1, 0, 1, 3);
	end
	if(TCL_SETTINGS[TCL_REALM]["SETTINGS"]["PLAYSOUND"] == "1") then 
		PlaySound("LEVELUP", 1, 1, 0, 1, 3); 
	end
	if(TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SNAPSHOT"] == "1") then 
		TakeScreenshot(); 
	end
	TitanPanelButton_UpdateButton(TITAN_CRITLINE_ID);
end

function tcl_GetHighestCrit()
	local hidmg = 0;
	local attack = "";
	local enemy = "";
	if (TCL_SETTINGS == nil) then 
		return hidmg;
	end
	if (TCL_SETTINGS[TCL_REALM] == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"] == nil) then 
		return hidmg; 
	end
	for k,v in pairs (TCL_SETTINGS[TCL_REALM]["DATA"]) do
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["Filter"] == "0" ) then
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"] ~= nil ) then
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["IsHeal"] == "0" ) then
					if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Damage"] > hidmg ) then
						hidmg = TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Damage"];
						attack = k;
						enemy = TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Target"].." ("..TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Level"]..")";
					end
				end
			end
		else
			tcl_DEBUG(k.." Filter is on, did not recognized for highest CRIT.");
		end
	end
	return hidmg, attack, enemy;
end

function tcl_GetHighestHealCrit()
	local hidmg = 0;
	local attack = "";
	local enemy = "";
	if (TCL_SETTINGS == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM] == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"] == nil) then 
		return hidmg; 
	end
	for k,v in pairs (TCL_SETTINGS[TCL_REALM]["DATA"]) do
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["Filter"] == "0" ) then
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"] ~= nil ) then
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["IsHeal"] == "1" ) then
					if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Damage"] > hidmg ) then
						hidmg = TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Damage"];
						attack = k;
						enemy = TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Target"].." ("..TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Level"]..")";
					end
				end
			end
		else
			tcl_DEBUG(k.." Filter is on, did not recognized for highest HEALCRIT");
		end
	end
	return hidmg, attack, enemy;
end

function tcl_GetHighestDamage()
	local hidmg = 0;
	local attack = "";
	local enemy = "";
	if (TCL_SETTINGS == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM] == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"] == nil) then 
		return hidmg; 
	end
	for k,v in pairs (TCL_SETTINGS[TCL_REALM]["DATA"]) do
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["Filter"] == "0" ) then
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"] ~= nil ) then
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["IsHeal"] == "0" ) then
					if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Damage"] > hidmg ) then
						hidmg = TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Damage"];
						attack = k;
						enemy = TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Target"].." ("..TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Level"]..")";
					end
				end
			end
		else
			tcl_DEBUG(k.." Filter is on, did not recognized for highest HIT.")
		end
	end
	return hidmg, attack, enemy;
end

function tcl_GetHighestHeal()
	local hidmg = 0;
	local attack = "";
	local enemy = "";
	if (TCL_SETTINGS == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM] == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"] == nil) then 
		return hidmg; 
	end
	for k,v in pairs (TCL_SETTINGS[TCL_REALM]["DATA"]) do
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["Filter"] == "0" ) then
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"] ~= nil ) then
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["IsHeal"] == "1" ) then
					if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Damage"] > hidmg ) then
						hidmg = TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Damage"];
						attack = k;
						enemy = TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Target"].." ("..TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Level"]..")";
					end
				end
			end
		else
			tcl_DEBUG(k.." Filter is on, did not recognized for highest HEAL.");
		end
	end
	return hidmg, attack, enemy;
end

function tcl_GetHighestCritPercentage()
	local critperc, crithits, normhits;
	local hidmg = 0;
	local attack = "";
	if (TCL_SETTINGS == nil) then 
		return hidmg;
	end
	if (TCL_SETTINGS[TCL_REALM] == nil) then 
		return hidmg; 
	end
	if (TCL_SETTINGS[TCL_REALM]["DATA"] == nil) then 
		return hidmg; 
	end
	for k,v in pairs (TCL_SETTINGS[TCL_REALM]["DATA"]) do
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["Filter"] == "0" ) then
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"] ~= nil ) then
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["IsHeal"] == "0") then
					crithits = TCL_SETTINGS[TCL_REALM]["DATA"][k]["CRIT"]["Value"];
				end
			end
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"] ~= nil ) then
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["IsHeal"] == "0") then
					normhits = TCL_SETTINGS[TCL_REALM]["DATA"][k]["NORMAL"]["Value"];
				end
			end
			if ( crithits == 0 or crithits == nil or normhits == 0 or normhits == nil ) then
				critperc = 0;
			else
				critperc = crithits / ( ( crithits + normhits ) / 100 );
			end
			tcl_DEBUG(k.." critical percentage: "..critperc);
			if ( critperc > hidmg ) then
				hidmg = critperc;
				attack = k;
			end
		else
			tcl_DEBUG(k.." Filter is on, did not recognized for highest CRIT percentage");
		end
	end
	return format("%.2f", hidmg), attack;
end

--[[ tooltip functions ]]
function tcl_DisplayDialog(message)
	GameTooltip:SetText(message);
	GameTooltip:Show();
end

function tcl_DisplaySummary()
	tcl_DisplayDialog(tcl_GetSummaryRichText());
end

function tcl_DisplayAbout()
	tcl_DisplayDialog(tcl_GetAboutRichText());
end

function tcl_GetSummaryRichText()
	local hicrit = tcl_GetHighestCrit();
	local hicritperc = tcl_GetHighestCritPercentage();
	local hidmg = tcl_GetHighestDamage();
	local hihealcrit = tcl_GetHighestHealCrit();
	local hihealdmg = tcl_GetHighestHeal();
	local rtfAttack="";
	for k,v in pairs (TCL_SETTINGS[TCL_REALM]["DATA"]) do
		attacktype = k;
		if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["Filter"] == "0" ) then
			local crithits, normhits, critperc, normperc;
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["CRIT"] == nil) then
				crithits = 0;
			else
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["CRIT"]["Value"] == nil) then
					crithits = 0;
				else
					crithits = TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["CRIT"]["Value"];
				end
			end
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["NORMAL"] == nil) then
				normhits = 0;
			else
				if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["NORMAL"]["Value"] == nil) then
					normhits = 0;
				else
					normhits = TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["NORMAL"]["Value"];
				end
			end
			local allhits = normhits + crithits;
			if ( crithits == 0 ) then
				critperc = 0;
			else
				critperc = format("%.2f", crithits / ( allhits / 100 ) );
			end
			if ( normhits == 0 ) then
				normperc = 0;
			else
				normperc = format("%.2f", normhits / ( allhits / 100 ) );
			end
			local allmisses;
			if ( TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["Misses"] == nil) then
				allmisses = 0;
			else
				allmisses = TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]["Misses"];
			end
			local allswings = allmisses + allhits;
			local hitperc = format("%.2f", allhits / ( allswings / 100 ) );
			if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWHITS"] == "1" ) then
				rtfAttack = rtfAttack..COLOR(HEADER_TEXT_COLOR, attacktype).."\t "..COLOR(HEADER_TEXT_COLOR, allhits).." "..HIT_TEXT.." ("..COLOR(HEADER_TEXT_COLOR, hitperc.." %")..")\n";
			else
				rtfAttack = rtfAttack..COLOR(HEADER_TEXT_COLOR, attacktype).."\n";
			end
			for k,v in pairs (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype]) do
				if (k == "NORMAL") then
					rtfAttack = rtfAttack.."  "..COLOR(SUBHEADER_TEXT_COLOR, NORMAL_TEXT).." [";
				elseif ( k == "CRIT" ) then
					rtfAttack = rtfAttack.."  "..COLOR(SUBHEADER_TEXT_COLOR, CRIT_TEXT).." [";
				end
				if ( k == "CRIT") then
					if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["IsHeal"] == "0") then
						if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"] == hicrit) then
							rtfAttack = rtfAttack..COLOR(HINT_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						else
							rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						end
					else
						if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"] == hihealcrit) then
							rtfAttack = rtfAttack..COLOR(HINT_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						else
							rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						end
					end
					if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] == "1" ) then
						if ( critperc == hicritperc ) then
							rtfAttack = rtfAttack.." ["..COLOR(HINT_TEXT_COLOR, critperc.."%").."]\t";
						else
							rtfAttack = rtfAttack.." ["..COLOR(BODY_TEXT_COLOR, critperc.."%").."]\t";
						end
					else
						rtfAttack = rtfAttack.."\t";
					end
				elseif ( k == "NORMAL" ) then
					tcl_DEBUG(TCL_REALM..", "..attacktype..", "..k);
					if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["IsHeal"] == "0") then
						if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"] == hidmg) then
							rtfAttack = rtfAttack..COLOR(HINT_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						else
							rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						end
					else
						if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"] == hihealdmg) then
							rtfAttack = rtfAttack..COLOR(HINT_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						else
							rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Damage"]).."]";
						end
					end
					if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["SHOWCRIT"] == "1" ) then
						rtfAttack = rtfAttack.." ["..COLOR(BODY_TEXT_COLOR, normperc.."%").."]\t";
					else
						rtfAttack = rtfAttack.."\t";
					end
				end
				if ( k == "NORMAL" ) then
					if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Level"] == -1) then
						rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Target"]).." ["..COLOR(BODY_TEXT_COLOR, "??").."]\n";
					else
						rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Target"]).." ["..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Level"]).."]\n";
					end
				elseif ( k == "CRIT" ) then
					if (TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Level"] == -1) then
						rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Target"]).." ["..COLOR(BODY_TEXT_COLOR, "??").."]\n";
					else
						rtfAttack = rtfAttack..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Target"]).." ["..COLOR(BODY_TEXT_COLOR, TCL_SETTINGS[TCL_REALM]["DATA"][attacktype][k]["Level"]).."]\n";
					end
				end
			end
		end
	end
	return rtfAttack
end

function tcl_GetAboutRichText()
	return 
		COLOR(HEADER_TEXT_COLOR, TITAN_CRITLINE_ID.." v"..TITAN_CRITLINE_VERSION).."\n"..
		COLOR(SUBHEADER_TEXT_COLOR, "Developers: ").."\n"..
		COLOR(BODY_TEXT_COLOR, "Sordit: ".."\t".."Concept and Stand-Alone version").."\n"..
		COLOR(BODY_TEXT_COLOR, "Uggh: ".."\t".."Titan Panel version < 0.3.7").."\n\n"..
		COLOR(BODY_TEXT_COLOR, "Falli: ".."\t".."Titan Panel version > 0.3.7");
end

--[[ chat functions ]]
function tcl_PostMessage(message_array,channel)
	if ( message_array == nil or type(message_array) ~= "table") then
		message_array = tcl_GetRecordChatText();
	end
	if ( channel == nil ) then
		channel = "GUILD";
		if ( GetNumPartyMembers() > 0 ) then
			channel = "PARTY";
		end
		if ( GetNumRaidMembers() > 0 ) then
			channel = "RAID";
		end
	end
	table.foreach(message_array, function(k,v) SendChatMessage(v, channel); end);
end

function tcl_PostToRaid()
	if ( GetNumRaidMembers ~= 0 ) then
		tcl_PostMessage(tcl_GetRecordChatText(),"RAID")
	else
		tcl_PostMessage(tcl_GetRecordChatText())
	end
end

function tcl_PostToParty()
	if ( GetNumPartyMembers ~= 0 ) then
		tcl_PostMessage(tcl_GetRecordChatText(),"PARTY")
	else
		tcl_PostMessage(tcl_GetRecordChatText())
	end
end

function tcl_PostToGuild()
	local guildName, guildRankName, guildRankIndex = GetGuildInfo("player");
	if ( guildName ) then
		tcl_PostMessage(tcl_GetRecordChatText(),"GUILD")
	else
		local message_array = tcl_GetRecordChatText();
		table.foreach(message_array, function(k,v) tcl_Msg(v); end);
	end
end

function tcl_GetRecordChatText()
	local hicrit, acrit, ecrit = tcl_GetHighestCrit();
	local hidmg, anormal, enormal = tcl_GetHighestDamage();
	local hihealcrit, hcrit, ehcrit = tcl_GetHighestHealCrit();
	local hihealdmg, hnormal, ehnormal = tcl_GetHighestHeal();
	local text = {};
	table.insert(text, TITAN_CRITLINE_ID.." "..RECORDS_TEXT..":");
	table.insert(text, CRIT_TEXT..": "..acrit.." ("..hicrit..")".." ["..ecrit.."]");
	table.insert(text, NORMAL_TEXT..": "..anormal.." ("..hidmg..")".." ["..enormal.."]");
	if ( TCL_SETTINGS[TCL_REALM]["SETTINGS"]["FILTER_HEALING"] == "0" ) then
		if ( hihealcrit > 0 ) then
			table.insert(text, CRIT_TEXT..": "..hcrit.." ("..hihealcrit..")".." ["..ehcrit.."]");
		end
		if ( hihealdmg > 0 ) then
			table.insert(text, NORMAL_TEXT..": "..hnormal.." ("..hihealdmg..")".." ["..ehnormal.."]");
		end
	end
	return text;
end

--[[ misc help functions ]]
function COLOR(color, msg)
	if ( msg == nil ) then
		return;
	end
	return color..msg..FONT_COLOR_CODE_CLOSE;
end

function tcl_Msg(msg)
	if ( msg == nil ) then
		msg = "------------------------------";
	end
	if (DEFAULT_CHAT_FRAME) then
		DEFAULT_CHAT_FRAME:AddMessage(msg);
	end
end

function tcl_Rebuild()
	tcl_Msg(TITAN_CRITLINE_ID.." "..TITAN_CRITLINE_VERSION.." rebuilding data.");
	TCL_SETTINGS[TCL_REALM] = nil;
	tcl_Initialize();
	tcl_Msg(TITAN_CRITLINE_ID.." "..TITAN_CRITLINE_VERSION.." rebuilding data complete.");
end

function tcl_DEBUG(message)
	if (DEBUG and DEFAULT_CHAT_FRAME) then
		DEFAULT_CHAT_FRAME:AddMessage("DEBUG: "..message);
	end
end
