--[[
	OmniCC
		A universal cooldown count, based on an idea by Gello
--]]

local DEFAULT_FONT = "Fonts\\K_Damage.TTF"
local ICON_SCALE = 37

local active = {}
local activePulses = {}
local blackList = {}

local function msg(message, showAddon)
	if showAddon then
		ChatFrame1:AddMessage(format("|cFF33FF99OmniCC|r: %s", tostring(message)))
	else
		ChatFrame1:AddMessage(tostring(message))
	end
end

OmniCC = CreateFrame("Frame")
OmniCC:Hide()

OmniCC:SetScript("OnEvent", function(self, event, arg1)
	if arg1 == "OmniCC" then
		self:UnregisterEvent(event)
		self:Init()
	end
end)
OmniCC:RegisterEvent("ADDON_LOADED")

OmniCC:SetScript("OnUpdate", function(self)
	if next(activePulses) then
		for pulse in pairs(activePulses) do
			self:UpdatePulse(pulse)
		end
	else
		self:Hide()
	end
end)


--[[ Settings Loading ]]--

function OmniCC:Init()
	self:LoadSettings()
	self:LoadFont()
end

function OmniCC:LoadSettings()
	local current = GetAddOnMetadata("OmniCC", "Version")

	if not(OmniCC2DB and OmniCC2DB.version) then
		self:LoadDefaults(current)
		if (GetLocale()=="koKR") then
			msg("초기값", true)
		else
			msg("Initialized", true)
		end
	else
		local cMajor, cMinor = current:match("(%d+)%.(%d+)")
		local major, minor = OmniCC2DB.version:match("(%d+)%.(%d+)")

		if major ~= cMajor then
			self:LoadDefaults(current)
			if (GetLocale()=="koKR") then
				msg("호환되지 않은 버전을 업데이트 합니다. 기본 설정을 불려옵니다.", true)
			else
				msg("Upgrading from an incompatible version. Default settings loaded", true)
			end
		elseif minor ~= cMinor then
			self:UpdateSettings(current)
		end
	end
	self.sets = OmniCC2DB
end

function OmniCC:LoadDefaults(current)
	OmniCC2DB = {
		version = current, --minimum duration to show text
		vlong = {r = 0.8, g = 0.8, b = 0.9, s = 0.6}, --settings for cooldowns greater than an hour
		long = {r = 0.8, g = 0.8, b = 0.9, s = 0.8}, --settings for cooldowns greater than one minute
		med = {r = 1, g = 1, b = 0.4, s = 1}, --settings for cooldowns under a minute
		short = {r = 1, g = 0, b = 0, s = 1.3}, --settings for cooldowns less than five seconds
		useBlacklist = 1,
		-- 추가 --
		font = DAMAGE_TEXT_FONT,
		font_name = {"2002", "2002B", "ARIALN", "FRIZQT__", "K_Damage", "K_Pagetext"},
		font_prefix = {"Fonts\\", "Interface\\Addons\\!OmniCC\\Fonts\\"},
		font_suffix = ".TTF",
		-- 추가 끝 --
	}
end

function OmniCC:UpdateSettings(current)
	-- OmniCC2DB.useBlacklist = 1
	OmniCC2DB.version = current
	if (GetLocale()=="koKR") then
		msg(format("업데이트 v%s", OmniCC2DB.version), true)
	else
		msg(format("Updated to v%s", OmniCC2DB.version), true)
	end
end


--[[ Config Functions ]]--

function OmniCC:UpdateActiveTimers()
	for timer in pairs(active) do
		self:UpdateTimer(timer)
	end
end

function OmniCC:Reset()
	self:LoadDefaults(GetAddOnMetadata("OmniCC", "Version"))
	self:UpdateActiveTimers()
end


--font
function OmniCC:LoadFont()
	if not self.font then
		self.font = CreateFont("OmniCCFont")
	end

	local font, size = self:GetFont()

	if not self.font:SetFont(font, size) then
		self.sets.font = nil
		self.font:SetFont(DAMAGE_TEXT_FONT, size)
	end
end

function OmniCC:SetFont(font)
	self.sets.font = font
	self:LoadFont()
	self:UpdateActiveTimers()
end

function OmniCC:SetFontSize(size)
	self.sets.fontSize = size
	self:UpdateActiveTimers()
end

function OmniCC:SetFontFormat(index, r, g, b, s)
	local sets = self.sets[index]
	if sets then
		sets.r = r or sets.r
		sets.g = g or sets.g
		sets.b = b or sets.b
		sets.s = s or sets.s
	end
	self:UpdateActiveTimers()
end

function OmniCC:GetFont()
	return self.sets.font or DAMAGE_TEXT_FONT, self.sets.fontSize or 20
end


--model
function OmniCC:ToggleModel()
	if self.sets.hideModel then
		self.sets.hideModel = nil
	else
		self.sets.hideModel = 1
	end
end

function OmniCC:ShowingModel()
	return not self.sets.hideModel
end


--time format
function OmniCC:ToggleMMSS()
	if self.sets.mmSS then
		self.sets.mmSS = nil
	else
		self.sets.mmSS = 1
	end
	self:UpdateActiveTimers()
end

function OmniCC:InMMSSFormat()
	return self.sets.mmSS
end


--minimum duration
function OmniCC:SetMinimumDuration(duration)
	self.sets.minDur = duration
end

function OmniCC:GetMinimumDuration()
	return self.sets.minDur or 3
end


--pulse
function OmniCC:TogglePulse()
	if self.sets.pulse then
		self.sets.pulse = nil
	else
		self.sets.pulse = 1
	end
end

function OmniCC:ShowingPulse()
	return self.sets.pulse
end


--frame blacklisting
function OmniCC:ToggleBlacklist()
	if self.sets.useBlacklist then
		self.sets.useBlacklist = nil
	else
		self.sets.useBlacklist = 1
	end
end

function OmniCC:UsingBlacklist()
	return self.sets.useBlacklist
end

function OmniCC:Blacklist(name)
	table.insert(blackList, name)
end


--[[ Cooldown Timer Code ]]--

local function GetFormattedTime(s)
	local mmSSFormat = OmniCC:InMMSSFormat()

	if s >= 86400 then
		return format("%dd", floor(s/86400 + 0.5)), mod(s, 86400)
	elseif s >= 3600 then
		return format("%dh", floor(s/3600 + 0.5)), mod(s, 3600)
	elseif s >= 180 or (not mmSSFormat and s >= 60.5) then
		return format("%dm", floor(s/60 + 0.5)), mod(s, 60)
	elseif mmSSFormat and s >= 60.5 then
		return format("%d:%02d", floor(s/60), mod(s, 60)), s - floor(s)
	end
	return floor(s + 0.5), s - floor(s)
end

local function GetFormattedFont(s)
	local index
	if s >= 3600 then
		index = "vlong"
	elseif s >= 60.5 then
		index = "long"
	elseif s >= 5.5 then
		index = "med"
	end
	local sets = OmniCC.sets[index or "short"]
	local font, size = OmniCC:GetFont()

	return font, size * (sets.s or 1), (sets.r or 1), (sets.g or 1), (sets.b or 1)
end

local function Timer_OnUpdate(self, elapsed)
	local icon = self.icon
	if self.toNextUpdate <= 0 or not icon:IsVisible() then
		--check and see if the frame we're on is still visible
		if(not icon:IsVisible()) then
			OmniCC:StopTimer(self)
			return
		end
	
		--icon check for bufs
		local texture = icon:GetTexture()
		if texture ~= self.texture then
			OmniCC:StopTimer(self)
			return
		end
		
		--update text
		local remain = self.duration - (GetTime() - self.start)
		if floor(remain + 0.5) > 0 then
			local time, toNextUpdate = GetFormattedTime(remain)
			local font, size, r, g, b = GetFormattedFont(remain)
			local scale = min(self:GetWidth() / ICON_SCALE, 1)

			--hide the timer if text is too small to see
			-- 추가
			local xFontCheck = self.text:SetFont(font, size * scale, "OUTLINE")
			if not(xFontCheck) then
				msg("- 입력하신 추가 글꼴은 유효하지 않은 글꼴입니다. 글꼴명을 확인해 주십시요.");
				msg("- 유효한 폰트 입력전까지 K_Damage 글꼴로 적용됩니다.");
				OmniCC2DB.font = OmniCC2DB.font_prefix[1]..OmniCC2DB.font_name[1]..OmniCC2DB.font_suffix;
			end		
			-- 추가 끝	
			if (size * scale) >= 8 then
				self.text:SetFont(font, size * scale, "OUTLINE")
				self.text:SetText(time)
				self.text:SetTextColor(r, g, b)
			else
				OmniCC:StopTimer(self)
				return
			end
			self.toNextUpdate = toNextUpdate
		--finished cooldown, show pulse
		else
			OmniCC:StopTimer(self)
			if OmniCC:ShowingPulse() then
				OmniCC:StartPulse(self)
			end
		end
	else
		self.toNextUpdate = self.toNextUpdate - elapsed
	end
end

local function Timer_Create(parent, cooldown, icon)
	local timer = CreateFrame("Frame", nil, parent)
	timer:SetFrameLevel(parent:GetFrameLevel() + 3)
	timer:SetToplevel(true)
	timer:Hide()

	timer:SetAllPoints(parent)
	timer:SetScript("OnUpdate", Timer_OnUpdate)

	timer.icon = icon
	timer.text = timer:CreateFontString(nil, "OVERLAY")
	timer.text:SetPoint("CENTER", timer, "CENTER", 0, 1)

	parent.timer = timer

	return timer
end

local function Cooldown_OnHide(self)
	OmniCC:StopTimer(self:GetParent().timer)
end

function OmniCC:StartTimer(cooldown, start, duration)
	local parent = cooldown:GetParent()
	if parent then
		local icon = parent.icon
		local name = parent:GetName()
		if(not(icon) and name) then
			icon = getglobal(name .. "Icon") or getglobal(name .. "IconTexture")
		end

		if icon then
			local timer = parent.timer or Timer_Create(parent, cooldown, icon)
			timer.start = start
			timer.duration = duration
			timer.toNextUpdate = 0
			timer.texture = icon:GetTexture()
			active[timer] = true
			timer:Show()
			cooldown:SetScript("OnHide", Cooldown_OnHide)
		end
	end
end

function OmniCC:StopTimer(timer)
	if timer then
		active[timer] = nil
		timer:Hide()
	end
end

function OmniCC:UpdateTimer(timer)
	timer.toNextUpdate = 0
end

hooksecurefunc("CooldownFrame_SetTimer", function(frame, start, duration, enable)
	if not OmniCC:ShowingModel() then
		frame:Hide()
	end

	if start > 0 and duration > OmniCC:GetMinimumDuration() and enable == 1 then
		if OmniCC:UsingBlacklist() then
			local frameName = frame:GetName()
			if(frameName) then
				for _, name in pairs(blackList) do
					if frameName:match(name) then return end
				end
			end
		end
		OmniCC:StartTimer(frame, start, duration)
	else
		local timer = frame:GetParent().timer
		if timer then
			OmniCC:StopTimer(timer)
		end
	end
end)


--[[  Pulse Code ]]--

local function Pulse_Create(parent)
	local frame = CreateFrame("Frame", nil, parent)
	frame:SetToplevel(true)
	frame:SetAllPoints(parent)

	local icon = frame:CreateTexture(nil, "OVERLAY")
	icon:SetPoint("CENTER", frame, "CENTER")
	icon:SetBlendMode("ADD")
	icon:SetHeight(frame:GetHeight())
	icon:SetWidth(frame:GetWidth())
	frame.icon = icon

	parent.pulse = frame

	return frame
end

function OmniCC:StartPulse(cooldown)
	local parent = cooldown:GetParent()

	if parent and parent:IsVisible() then
		local pulse = parent.pulse or Pulse_Create(parent)
		pulse.scale = 1
		pulse.icon:SetTexture(cooldown.icon:GetTexture())
		pulse:Show()
		activePulses[pulse] = true

		self:Show()
	end
end

function OmniCC:UpdatePulse(pulse)
	if pulse.scale >= 2 then
		pulse.dec = 1
	end

	if pulse.dec then
		pulse.scale = pulse.scale - pulse.scale * 0.09
	else
		pulse.scale = pulse.scale + pulse.scale * 0.09
	end

	if pulse.scale <= 1 then
		activePulses[pulse] = nil

		pulse:Hide()
		pulse.dec = nil
	else
		pulse.icon:SetHeight(pulse:GetHeight() * pulse.scale)
		pulse.icon:SetWidth(pulse:GetWidth() * pulse.scale)
	end
end


--[[ Slash Commands ]]--

local function PrintCommands()
    if (GetLocale()=="koKR") then
		msg("사용자 명령어 (/옴니)", true)
		msg(format("- 크기 <크기>: 글꼴 크기를 설정합니다. 현재 크기는 '%s'입니다.", select(2, OmniCC:GetFont())))
		msg("- 글꼴 <숫자>: 사용자 글꼴을 설정합니다. 현재 글꼴은 '"..OmniCC:GetFont().."'입니다.")
		for k ,v in pairs(OmniCC2DB.font_name) do
			if fontlist then
				fontlist = fontlist .. "  "..k..". "..v;
			else
				fontlist = k..". "..v;
			end
		end
		msg("  사용 가능한 글꼴 번호 :");
		msg("  "..fontlist);
		msg("- 색상 <기간> <적> <녹> <청>: 기간(vlong, long, med, short)별 색상을 설정 합니다.")
		msg("- 비율 <기간> <비율>: 기간(vlong, long, med, short)별 비율을 설정 합니다.")
		msg("- 최소 <시간>: 대기 시간 타이머가 감지할 최소 시간을 설정합니다. 기본 '3초'입니다.")
		msg("- 모델: 기본 블리자드 대기시간을 표시합니다.")
		msg("- 반응: 대기 시간 끝마침 반응을 표시합니다.")
		msg("- 분초: 시간 형식 MM:SS로 변경합니다.")
		msg("- 블랙: 재사용 글꼴을 블랙리스트 프레임에 올립니다.")
		msg("- 리셋: 기본설정으로 되돌립니다.")
	else
		msg("Commands (/omnicc)", true)
		msg("- size <size>: Set font size. 20 is default");
		msg("- font <font>: Set the font to use. " .. STANDARD_TEXT_FONT .. " is default")
		msg("- color <dur> <r> <g> <b>: Set the color to use for cooldowns of <dur>. <dur> can be vlong, long, med or short")
		msg("- scale <dur> <scale>: Set the scale to use for cooldowns of <dur>. <dur> can be vlong, long, med or short")
		msg("- min <time>: Set the minimum duration (secs) a cooldown should be to show text. Default value of 3")
		msg("- model: Toggles the cooldown model")
		msg("- pulse: Toggles a pulse when cooldowns are finished")
		msg("- mmss: Toggles MM:SS format")
		msg("- blacklist: Toggles showing cooldown text on blacklisted frames")
		msg("- reset: Returns to default settings")
    end
end

SlashCmdList["OmniCCCOMMAND"] = function(message)
	if not message or message == "" or message:lower() == "help" or message == "?" then
		PrintCommands();
	else
		local args = {strsplit(" ", message:lower())}
		local cmd = args[1]
        
		if cmd == "font" or cmd == "글꼴" and args[2] then  
			if ( tonumber(args[2]) ) then
				if ( tonumber(args[2]) <= tonumber(getn(OmniCC2DB.font_name)) ) then
					OmniCC2DB.font = OmniCC2DB.font_prefix[1]..OmniCC2DB.font_name[tonumber(args[2])]..OmniCC2DB.font_suffix;
					msg(format("글꼴이 "..OmniCC2DB.font_name[tonumber(args[2])].." 로 변경되었습니다.", true))
				else
					msg(format("- 기본 폰트는 숫자로 선택하십시요. 입력 가능한 숫자는 '1~"..getn(OmniCC2DB.font_name).."' 입니다.", true))
					msg(format("- 올바른 글꼴 입력전까지 "..OmniCC2DB.font.." 글꼴을 사용합니다.", true))
					OmniCC2DB.font = OmniCC2DB.font_prefix[1]..OmniCC2DB.font_name[1]..OmniCC2DB.font_suffix;
				end
			else
				OmniCC2DB.font = OmniCC2DB.font_prefix[2]..args[2]..OmniCC2DB.font_suffix;
				msg(format("글꼴 설정 : "..args[2], true))
			end
		elseif cmd == "size" or cmd == "크기" then
			OmniCC:SetFontSize(tonumber(args[2]))
			if (GetLocale()=="koKR") then
				msg(format("글꼴 크기 설정 : %s", select(2, OmniCC:GetFont())), true)
			else
				msg(format("Set font size to %s", select(2, OmniCC:GetFont())), true)
			end
		elseif cmd == "min" or cmd == "최소" then
			OmniCC:SetMinimumDuration(tonumber(args[2]))
			if (GetLocale()=="koKR") then
				msg(format("최소 감지 시간 설정 : %s", OmniCC:GetMinimumDuration(), true))
			else
				msg(format("Set minimum duration to %s", OmniCC:GetMinimumDuration(), true))
			end
		elseif cmd == "model" or cmd == "모델" then
			OmniCC:ToggleModel()
			if OmniCC:ShowingModel() then
				if (GetLocale()=="koKR") then
					msg("블리자드 재사용 대기시간 기능을 표시합니다.", true)
				else
					msg("Cooldown models enabled", true)
				end
			else
				if (GetLocale()=="koKR") then
					msg("블리자드 재사용 대기시간 기능을 표시하지 않습니다.", true)
				else
					msg("Cooldown models disabled", true)
				end
			end
		elseif cmd == "pulse" or cmd == "반응" then
			OmniCC:TogglePulse()
			if OmniCC:ShowingPulse() then
				if (GetLocale()=="koKR") then
					msg("재사용 끝남 반응을 표시합니다.", true)
				else
					msg("Pulse enabled", true)
				end
			else
				if (GetLocale()=="koKR") then
					msg("재사용 끝남 반응을 표시하지 않습니다.", true)
				else
					msg("Pulse disabled", true)
				end
			end
		elseif cmd == "mmss" or cmd == "분초" then
			OmniCC:ToggleMMSS()
			if OmniCC:InMMSSFormat() then
				if (GetLocale()=="koKR") then
					msg("시간 형식을 MM:SS로 변경합니다.", true)
				else
					msg("MM:SS format enabled", true)
				end	
			else
				if (GetLocale()=="koKR") then
					msg("시간 형식을 MM:SS로 변경하지 않습니다.", true)
				else
					msg("MM:SS format disabled", true)
				end
			end
		elseif cmd == "blacklist" or cmd == "블랙" then
			OmniCC:ToggleBlacklist()
			if OmniCC:UsingBlacklist() then
				if (GetLocale()=="koKR") then
					msg("블랙리스트에 올린 프레임의 재사용 대기시간을 표시하지 않습니다.", true)
				else
					msg("Hiding cooldown text on blacklisted frames", true)
				end	
			else
				if (GetLocale()=="koKR") then
					msg("모든 프레임에 재사용 대기시간을 표시합니다.", true)
				else
					msg("Showing cooldown text on all frames", true)
				end				
			end
		elseif cmd == "color" or cmd == "색상" then
			OmniCC:SetFontFormat(args[2], tonumber(args[3]), tonumber(args[4]), tonumber(args[5]))
		elseif cmd == "scale" or cmd == "비율" then
			OmniCC:SetFontFormat(args[2], nil, nil, nil, tonumber(args[3]))
		elseif cmd == "reset" or cmd == "리셋" or cmd == "초기화" then
			OmniCC:Reset()
			if (GetLocale()=="koKR") then
				msg("기본 설정을 불려옵니다.", true)
			else
				msg("Loaded default settings", true)
			end	
		else
			if (GetLocale()=="koKR") then
				msg(format("'%s'는 알수없는 명령입니다.", cmd), true)
			else
				msg(format("'%s' is an invalid command", cmd), true)
			end	
		end
	end
end
SLASH_OmniCCCOMMAND1 = "/omnicc"
SLASH_OmniCCCOMMAND2 = "/재사용";
SLASH_OmniCCCOMMAND3 = "/옴니";
SLASH_OmniCCCOMMAND4 = "/옴";