Quantcast
---@diagnostic disable: duplicate-set-field
--[[
-- **************************************************************************
-- * TitanClock.lua
-- *
-- * By: The Titan Panel Development Team
-- **************************************************************************
--]]

-- ******************************** Constants *******************************
TITAN_CLOCK_ID = "Clock";
local TITAN_BUTTON = "TitanPanel" .. TITAN_CLOCK_ID .. "Button"

local TITAN_CLOCK_FORMAT_12H = "12H";
local TITAN_CLOCK_FORMAT_24H = "24H";
local TITAN_CLOCK_FRAME_SHOW_TIME = 0.5;
local _G = getfenv(0);
-- ******************************** Variables *******************************
local AceTimer = LibStub("AceTimer-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true)
local ClockTimer = {}
local ClockTimerRunning = false
local updateTable = { TITAN_CLOCK_ID, TITAN_PANEL_UPDATE_ALL };
local realmName = GetRealmName();
-- ******************************** Functions *******************************
local function SetColor(text)
	local label = "";
	if (TitanGetVar(TITAN_CLOCK_ID, "ShowColoredText")) then
		label = TitanUtils_GetGreenText(text)
	else
		label = TitanUtils_GetHighlightText(text)
	end
	return label;
end

---@param displaytype string Server | Local
---@param offset number User selected offset
---@return nil
---@return string formatted_time
local function FormatTime(displaytype, offset)
	-- Calculate the hour/minutes considering the offset
	local hour, minute = GetGameTime();
	local twentyfour = "";
	local offsettime = string.format("%s", offset);
	local offsethour = 0;
	local hour_str = ""
	local offsetmin = 0;
	local min_str = ""
	local s, e, id = string.find(offsettime, '%.5');

	if displaytype == "Server" then
		if (s ~= nil) then
			hour_str = string.sub(offsettime, 1, s);
			min_str = string.sub(offsettime, s + 1);
			if min_str == "" or min_str == nil then min_str = "0"; end
			if hour_str == "" or hour_str == nil then hour_str = "0"; end
			offsethour = tonumber(hour_str);
			if (tonumber(offsettime) < 0) then offsetmin = tonumber("-" .. min_str); end
			minute = minute + (offsetmin * 6);
			if (minute > 59) then
				minute = minute - 60;
				offsethour = offsethour + 1;
			elseif (minute < 0) then
				minute = 60 + minute;
				offsethour = offsethour - 1;
			end
		else
			offsethour = offset;
		end
	else
		-- no offset for local time
		hour, minute = tonumber(date("%H")), tonumber(date("%M"));
		offsethour = 0;
	end

	hour = hour + offsethour;

	if (hour > 23) then
		hour = hour - 24;
	elseif (hour < 0) then
		hour = 24 + hour;
	end

	-- Calculate the display text based on format 12H/24H
	if (TitanGetVar(TITAN_CLOCK_ID, "Format") == TITAN_CLOCK_FORMAT_12H) then
		local isAM;
		if (hour >= 12) then
			isAM = false;
			hour = hour - 12;
		else
			isAM = true;
		end
		if (hour == 0) then
			hour = 12;
		end
		if (isAM) then
			return nil, format(TIME_TWELVEHOURAM, hour, minute);
		else
			return nil, format(TIME_TWELVEHOURPM, hour, minute);
		end
	else
		twentyfour = format(TIME_TWENTYFOURHOURS, hour, minute);
		if (hour < 10) then
			twentyfour = "0" .. twentyfour
		end
		return nil, twentyfour;
	end
end

--- local Display time on button based on user settings
local function GetButtonText()
	local clocktime = "";
	local labeltext = "";
	local clocktime2 = nil;
	local labeltext2 = nil;
	local _ = nil
	if TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "Server" then
		_, clocktime = FormatTime("Server", 0)
		labeltext = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(S) ") or ""
	elseif TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "ServerAdjusted" then
		_, clocktime = FormatTime("Server", TitanGetVar(TITAN_CLOCK_ID, "OffsetHour"))
		labeltext = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(A) ") or ""
	elseif TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "Local" then
		_, clocktime = FormatTime("Local", 0)
		labeltext = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(L) ") or ""
	elseif TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "ServerLocal" then
		local _, s = FormatTime("Server", 0)
		local _, l = FormatTime("Local", 0)
		local sl = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(S) ") or ""
		local ll = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(L) ") or ""
		clocktime = s
		labeltext = sl
		clocktime2 = l
		labeltext2 = ll
	elseif TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "ServerAdjustedLocal" then
		local _, s = FormatTime("Server", TitanGetVar(TITAN_CLOCK_ID, "OffsetHour"))
		local _, l = FormatTime("Local", 0)
		local sl = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(A) ") or ""
		local ll = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(L) ") or ""
		clocktime = s
		labeltext = sl
		clocktime2 = l
		labeltext2 = ll
	elseif TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "Local" then
		_, clocktime = FormatTime("Local", 0)
		labeltext = TitanGetVar(TITAN_CLOCK_ID, "ShowLabelText") and SetColor("(L) ") or ""
	end
	return labeltext, clocktime, labeltext2, clocktime2
end

---@param offset number User selected offset
---@return string formatted_offset
local function GetOffsetText(offset)
	if (offset > 0) then
		return TitanUtils_GetGreenText("+" .. tostring(offset));
	elseif (offset < 0) then
		return TitanUtils_GetRedText(tostring(offset));
	else
		return TitanUtils_GetHighlightText(tostring(offset));
	end
end

---local Return the tool tip text based on user settings
---@return string formatted_text
local function GetTooltipText()
	local _, clockTimeLocal = FormatTime("Local", 0)
	local _, clockTimeServer = FormatTime("Server", 0)
	local _, clockTimeServerAdjusted = FormatTime("Server", TitanGetVar(TITAN_CLOCK_ID, "OffsetHour"))
	local clockTimeLocalLabel = L["TITAN_CLOCK_TOOLTIP_LOCAL_TIME"] .. "\t" ..
	TitanUtils_GetHighlightText(clockTimeLocal)
	local clockTimeServerLabel = L["TITAN_CLOCK_TOOLTIP_SERVER_TIME"] ..
	"\t" .. TitanUtils_GetHighlightText(clockTimeServer)
	local clockTimeServerAdjustedLabel = "";
	if TitanGetVar(TITAN_CLOCK_ID, "OffsetHour") ~= 0 then
		clockTimeServerAdjustedLabel = L["TITAN_CLOCK_TOOLTIP_SERVER_ADJUSTED_TIME"] ..
		"\t" .. TitanUtils_GetHighlightText(clockTimeServerAdjusted) .. "\n"
	end
	local clockText = GetOffsetText(TitanGetVar(TITAN_CLOCK_ID, "OffsetHour"));
	return "" ..
		clockTimeLocalLabel .. "\n" ..
		clockTimeServerLabel .. "\n" ..
		clockTimeServerAdjustedLabel ..
		L["TITAN_CLOCK_TOOLTIP_VALUE"] .. "\t" .. TitanUtils_GetHighlightText(clockText) .. "\n" ..
		TitanUtils_GetGreenText(L["TITAN_CLOCK_TOOLTIP_HINT1"]) .. "\n" ..
		TitanUtils_GetGreenText(L["TITAN_CLOCK_TOOLTIP_HINT2"]) .. "\n" ..
		TitanUtils_GetGreenText(L["TITAN_CLOCK_TOOLTIP_HINT3"]);
end

local function ToggleGameTimeFrameShown()
	TitanToggleVar(TITAN_CLOCK_ID, "HideGameTimeMinimap");
	if GameTimeFrame and GameTimeFrame:GetName() then
		if TitanGetVar(TITAN_CLOCK_ID, "HideGameTimeMinimap") then
			GameTimeFrame:Hide()
		else
			GameTimeFrame:Show()
		end
	end
end

local function ToggleMapTime()
	TitanToggleVar(TITAN_CLOCK_ID, "HideMapTime");
	if TimeManagerClockButton and TimeManagerClockButton:GetName() then
		if TitanGetVar(TITAN_CLOCK_ID, "HideMapTime") then
			TimeManagerClockButton:Hide()
		else
			TimeManagerClockButton:Show()
		end
	else
		print("TitanClock: no time widget")
	end
end

---local Build the right click menu
local function CreateMenu()
	TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_CLOCK_ID].menuText);

	local info = {};
	info.text = L["TITAN_CLOCK_MENU_LOCAL_TIME"];
	info.func = function()
		TitanSetVar(TITAN_CLOCK_ID, "TimeMode", "Local")
		TitanPanelButton_UpdateButton(TITAN_CLOCK_ID)
	end
	info.checked = function() return TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "Local" end
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	info = {};
	info.text = L["TITAN_CLOCK_MENU_SERVER_TIME"];
	info.func = function()
		TitanSetVar(TITAN_CLOCK_ID, "TimeMode", "Server")
		TitanPanelButton_UpdateButton(TITAN_CLOCK_ID)
	end
	info.checked = function() return TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "Server" end
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	info = {};
	info.text = L["TITAN_CLOCK_MENU_SERVER_ADJUSTED_TIME"];
	info.func = function()
		TitanSetVar(TITAN_CLOCK_ID, "TimeMode", "ServerAdjusted")
		TitanPanelButton_UpdateButton(TITAN_CLOCK_ID)
	end
	info.checked = function() return TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "ServerAdjusted" end
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	info = {};
	info.text = L["TITAN_CLOCK_MENU_SERVER_TIME"] .. " & " .. L["TITAN_CLOCK_MENU_LOCAL_TIME"]
	info.func = function()
		TitanSetVar(TITAN_CLOCK_ID, "TimeMode", "ServerLocal")
		TitanPanelButton_UpdateButton(TITAN_CLOCK_ID)
	end
	info.checked = function() return TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "ServerLocal" end
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	info = {};
	info.text = L["TITAN_CLOCK_MENU_SERVER_ADJUSTED_TIME"] .. " & " .. L["TITAN_CLOCK_MENU_LOCAL_TIME"]
	info.func = function()
		TitanSetVar(TITAN_CLOCK_ID, "TimeMode", "ServerAdjustedLocal")
		TitanPanelButton_UpdateButton(TITAN_CLOCK_ID)
	end
	info.checked = function() return TitanGetVar(TITAN_CLOCK_ID, "TimeMode") == "ServerAdjustedLocal" end
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	info = {}; -- 12 or 24 hour format
	info.text = L["TITAN_CLOCK_CHECKBUTTON"]
	info.func = function()
		if (TitanGetVar(TITAN_CLOCK_ID, "Format") == TITAN_CLOCK_FORMAT_12H) then
			TitanSetVar(TITAN_CLOCK_ID, "Format", TITAN_CLOCK_FORMAT_24H);
		else
			TitanSetVar(TITAN_CLOCK_ID, "Format", TITAN_CLOCK_FORMAT_12H);
		end
		if (ServerHourFormat[realmName]) then
			ServerHourFormat[realmName] = TitanGetVar(TITAN_CLOCK_ID, "Format");
		end

		TitanPanelButton_UpdateButton(TITAN_CLOCK_ID)
	end
	info.checked = function()
		if (TitanGetVar(TITAN_CLOCK_ID, "Format") == TITAN_CLOCK_FORMAT_24H) then
			return true
		else
			return false
		end
	end
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	TitanPanelRightClickMenu_AddSpacer();

	info = {};
	info.text = L["TITAN_CLOCK_MENU_HIDE_MAPTIME"];
	info.func = ToggleMapTime;
	info.checked = TitanGetVar(TITAN_CLOCK_ID, "HideMapTime");
	info.keepShownOnClick = 1;
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	info = {};
	info.text = L["TITAN_CLOCK_MENU_HIDE_CALENDAR"];
	info.func = ToggleGameTimeFrameShown;
	info.checked = TitanGetVar(TITAN_CLOCK_ID, "HideGameTimeMinimap");
	info.keepShownOnClick = 1;
	TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel());

	TitanPanelRightClickMenu_AddControlVars(TITAN_CLOCK_ID)
end

---local Build the plugin .registry and register events
---@param self Button plugin frame
local function OnLoad(self)
	local notes = ""
		.. "Adds a clock to Titan Panel.\n"
		.. "- Select server time / local time / both server and local time.\n"
	self.registry = {
		id = TITAN_CLOCK_ID,
		category = "Built-ins",
		version = TITAN_VERSION,
		menuText = L["TITAN_CLOCK_MENU_TEXT"],
		menuTextFunction = CreateMenu,
		buttonTextFunction = GetButtonText,
		tooltipTitle = L["TITAN_CLOCK_TOOLTIP"],
		tooltipTextFunction = GetTooltipText,
		notes = notes,
		controlVariables = {
			ShowIcon = false,
			ShowLabelText = true,
			ShowColoredText = true,
			DisplayOnRightSide = true,
		},
		savedVariables = {
			OffsetHour = 0,
			Format = TITAN_CLOCK_FORMAT_12H,
			TimeMode = "Server",
			ShowIcon = true,
			ShowLabelText = false,
			ShowColoredText = false,
			DisplayOnRightSide = 1,
			HideGameTimeMinimap = false,
			HideMapTime = false,
		}
	};
	self:RegisterEvent("PLAYER_ENTERING_WORLD");
end

---local Start the timer for advancing the clock time
---@param self Button plugin frame
local function OnShow(self)
	if ClockTimerRunning then
		-- Do not create a new one
	else
		ClockTimer = AceTimer:ScheduleRepeatingTimer(TitanPanelPluginHandle_OnUpdate, 30, updateTable)
		ClockTimerRunning = true
	end
end

---local Stop the timer for advancing the clock time
---@param self Button plugin frame
local function OnHide(self)
	AceTimer:CancelTimer(ClockTimer)
	ClockTimerRunning = false
end

---local Handle events the clock plugin is interested in.
---@param self Button plugin frame
---@param event string Event
---@param ... any Event parameters
local function OnEvent(self, event, ...)
	if (event == "PLAYER_ENTERING_WORLD") then
		-- If the user wants the minimap clock or calendar hidden then hide them
		if TitanGetVar(TITAN_CLOCK_ID, "HideGameTimeMinimap") then
			if GameTimeFrame then GameTimeFrame:Hide() end
		end
		if TimeManagerClockButton and TimeManagerClockButton:GetName() then
			if TitanGetVar(TITAN_CLOCK_ID, "HideMapTime") then
				TimeManagerClockButton:Hide()
			else
				TimeManagerClockButton:Show()
			end
		end
	end
end

---local Handle mouse events the clock plugin is interested in.
---@param self Button plugin frame
---@param button string Button pushed with any modifiers
local function OnClick(self, button)
	if button == "LeftButton" and IsShiftKeyDown() then
		TitanUtils_CloseAllControlFrames();
		if (TitanPanelRightClickMenu_IsVisible()) then
			TitanPanelRightClickMenu_Close();
		end
		ToggleCalendar()
	elseif button == "LeftButton" then
	else
		TitanPanelButton_OnClick(self, button);
	end
end

-- === Slider routines

---local Generate slider tooltip.
---@param self Slider plugin slider frame
local function Slider_GetTooltip(self)
	local slider_tooltip = TitanOptionSlider_TooltipText(L["TITAN_CLOCK_CONTROL_TOOLTIP"],
		GetOffsetText(TitanGetVar(TITAN_CLOCK_ID, "OffsetHour")));
	GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT");
	GameTooltip:SetText(slider_tooltip, nil, nil, nil, nil, 1);
end

---local Display slider tooltip on mouse over.
---@param self Slider plugin slider frame
local function Slider_OnEnter(self)
	Slider_GetTooltip(self)
	TitanUtils_StopFrameCounting(self:GetParent());
end

---local Remove slider tooltip on mouse over leaving.
---@param self Slider plugin slider frame
local function Slider_OnLeave(self)
	GameTooltip:Hide();
	TitanUtils_StartFrameCounting(self:GetParent(), TITAN_CLOCK_FRAME_SHOW_TIME);
end

---local Display slider tooltip options
---@param self Slider plugin slider frame
local function Slider_OnShow(self)
	_G[self:GetName() .. "Text"]:SetText(GetOffsetText(TitanGetVar(TITAN_CLOCK_ID, "OffsetHour")));
	_G[self:GetName() .. "High"]:SetText(L["TITAN_CLOCK_CONTROL_LOW"]);
	_G[self:GetName() .. "Low"]:SetText(L["TITAN_CLOCK_CONTROL_HIGH"]);
	--	self:SetThumbTexture("Interface\Buttons\UI-SliderBar-Button-Vertical")
	self:SetMinMaxValues(-12, 12);
	self:SetValueStep(0.5);
	self:SetObeyStepOnDrag(true) -- since 5.4.2 (Mists of Pandaria)
	self:SetValue(0 - TitanGetVar(TITAN_CLOCK_ID, "OffsetHour"));
end

---local Display slider tooltip text
---@param self Slider plugin slider frame
---@param a1 number positive or negative change to apply
local function Slider_OnValueChangedWheel(self, a1)
	_G[self:GetName() .. "Text"]:SetText(GetOffsetText(0 - self:GetValue()));
	local tempval = self:GetValue();

	if a1 == -1 then
		self:SetValue(tempval + 0.5);
	end

	if a1 == 1 then
		self:SetValue(tempval - 0.5);
	end

	TitanSetVar(TITAN_CLOCK_ID, "OffsetHour", 0 - self:GetValue());
	if (ServerTimeOffsets[realmName]) then
		ServerTimeOffsets[realmName] = TitanGetVar(TITAN_CLOCK_ID, "OffsetHour");
	end
	TitanPanelButton_UpdateButton(TITAN_CLOCK_ID);

	-- Update GameTooltip
	Slider_GetTooltip(self)
end


---local Display slider tooltip text
---@param self Slider plugin slider frame
---@param a1 number positive or negative change to apply
local function Slider_OnValueChanged(self, a1)
	local step = self:GetValue()
	_G[self:GetName() .. "Text"]:SetText(GetOffsetText(0 - step));
	TitanSetVar(TITAN_CLOCK_ID, "OffsetHour", 0 - step);
	if (ServerTimeOffsets[realmName]) then
		ServerTimeOffsets[realmName] = TitanGetVar(TITAN_CLOCK_ID, "OffsetHour");
	end
	TitanPanelButton_UpdateButton(TITAN_CLOCK_ID);

	-- Update GameTooltip
	Slider_GetTooltip(self)
end

-- === Option menu routines

---local Create clock option frame
---@param self Frame Plugin option menu frame
local function TitanPanelClockControlFrame_OnLoad(self)
	_G[self:GetName() .. "Title"]:SetText(L["TITAN_CLOCK_CONTROL_TITLE"]);
	--[[
Blizzard decided to remove direct Backdrop API in 9.0 (Shadowlands)
so inherit the template (XML)
and set the values in the code (Lua)

9.5 The tooltip template was removed from the GameTooltip.
--]]
	TitanPanelRightClickMenu_SetCustomBackdrop(self)
end

---If dropdown is visible, see if its timer has expired.  If expired, hide frame.
---@param self Frame Plugin option menu frame
---@param elapsed number portion of second since last OnUpdate
local function Control_OnUpdate(self, elapsed)
	TitanUtils_CheckFrameCounting(self, elapsed);
end

-- ====== Create needed frames
local function Create_Frames()
	if _G[TITAN_BUTTON] then
		return -- if already created
	end

	-- general container frame
	local f = CreateFrame("Frame", nil, UIParent)
	--	f:Hide()

	-- Titan plugin button
	local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelTextTemplate")
	window:SetFrameStrata("FULLSCREEN")
	-- Using SetScript("OnLoad",   does not work
	OnLoad(window);
	--	TitanPanelButton_OnLoad(window); -- Titan XML template calls this...

	window:SetScript("OnShow", function(self)
		OnShow(self)
		TitanPanelButton_OnShow(self)
	end)
	window:SetScript("OnHide", function(self)
		OnHide(self)
	end)
	window:SetScript("OnEvent", function(self, event, ...)
		OnEvent(self, event, ...)
	end)
	window:SetScript("OnClick", function(self, button)
		OnClick(self, button)
		TitanPanelButton_OnClick(self, button)
	end)


	---[===[
	-- Config screen
	local cname = "TitanPanelClockControlFrame"
	local config = CreateFrame("Frame", cname, f, BackdropTemplateMixin and "BackdropTemplate")
	config:SetFrameStrata("FULLSCREEN") -- FULLSCREEN
	config:Hide()                    --
	config:SetWidth(90)
	config:SetHeight(200)

	config:SetScript("OnShow", function(self)
	end)
	config:SetScript("OnEnter", function(self)
		TitanUtils_StopFrameCounting(self)
	end)
	config:SetScript("OnLeave", function(self)
		TitanUtils_StartFrameCounting(self, 0.5)
	end)
	config:SetScript("OnUpdate", function(self, elapsed)
		Control_OnUpdate(self, elapsed)
	end)

	-- Config Title
	local str = nil
	local style = "GameFontNormalSmall"
	str = config:CreateFontString(cname .. "Title", "ARTWORK", style)
	str:SetPoint("TOP", config, 0, -10)

	-- Config slider sections
	local slider = nil

	-- Hours offset
	local inherit = "TitanOptionsSliderTemplate"
	local offset = CreateFrame("Slider", "TitanPanelClockControlSlider", config, inherit)
	offset:SetPoint("TOP", config, 0, -40)
	offset:SetScript("OnShow", function(self)
		Slider_OnShow(self)
	end)
	offset:SetScript("OnValueChanged", function(self, value, userInput)
		Slider_OnValueChanged(self, value)
	end)
	offset:SetScript("OnMouseWheel", function(self, delta)
		Slider_OnValueChangedWheel(self, delta)
	end)
	offset:SetScript("OnEnter", function(self)
		Slider_OnEnter(self)
	end)
	offset:SetScript("OnLeave", function(self)
		Slider_OnLeave(self)
	end)

	-- Now that the parts exist, initialize
	TitanPanelClockControlFrame_OnLoad(config)

	--]===]
end

Create_Frames() -- do the work