--***********************************
--Title: wowshell cooldown
--Description: spell item cooldown timer
--Author: 月色狼影
--Revision: $Rev: 1591 $
--LastUpadate: $Id: Cooldown.lua 286 2008-04-03 01:41:58Z wolftankk $
--***********************************

local L = wsGetLocale
--申明
local timers = {}
local shines = {}
local activeShines = {}
local centerData = {}
local text, color, center
--font = GameTooltipTextLeft1:GetFont();
font = NumberFontNormalHuge:GetFont();
font = string.lower(font)

wsSVNVer = 3.02;

shine_style = {
	"",
	"Interface\\Cooldown\\star4",
	"Interface\\Cooldown\\ping4",
	"Interface\\Cooldown\\starburst",
	"Interface\\AddOns\\wsCC\\heart",
}

WSBTNTREE = {
	{key = 1, value = "^SpellButton", type = "Spell"  },
	{key = 2, value = "AutoCastable", type = "Pet"    },
	{key = 2, value = "HotKey", type = "Action" },
	{key = 2, value = "Stock", type = "Item"   },
}

--插件加载
wsCC = CreateFrame("Frame");
wsCC:Hide();
wsCC:RegisterEvent("PLAYER_LOGIN")
wsCC:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
wsCC:SetScript("OnUpdate", function(self, elapsed) self:UpdateAllShines(elapsed) end)
wsCC:SetScript("OnEvent", function(self, event)
	if (event == "PLAYER_LOGIN") then
		local methods = getmetatable(CreateFrame("CoolDown", nil, nil, "CooldownFrameTemplate")).__index
		hooksecurefunc(methods, "SetCooldown", function(cd, start, duration)
			local btn = cd:GetParent()
			local type = wsCC:ButtonGetType(btn)

			if start>0 and duration > (wsCC:get(type, "min") or 0) and wsCC:get(type, "config") then
				wsCC:StartTimer(cd, start, duration, type)
			else
				local timer = timers[cd]
				if timer then
					timer:Hide()
				end
			end
		end)
	else
		if (arg1 ~= "player") then return end
		local icon = self:GetIcon(arg2)
		if icon then
			centerData[icon] = arg2
		end
	end

	if (not wsCCDB ) then
		self:GetDefault()
	end

	if tonumber(wsCCDB["wsSVN"]) < tonumber(wsSVNVer) then
		self:GetDefault();
		wsCCDB["wsSVN"] = wsSVNVer;
	end
end)

--shine = flag
--cpoint中间显示位置
function wsCC:GetDefault()
	wsCCDB = {
		wsSVN = wsSVNVer,
		Action = {
			config = true, min = 3, font = font, size = 20, shine = true, sound = false, style = 2, time = 1, scale = 150, center = false, cscale = 100, ctime = 1, calpha = 1, cmode = true, hide = false, cpoint = "TOP"
		},
		Pet = {
			config = true,  min = 3, font = font, size = 20, shine = true, sound = false,
			time = 1, scale = 150, style = 2, center = false,  cscale = 100, ctime = 1, calpha = 1, cmode = true, hide = false, cpoint = "TOP"
		},
		Buff = {
			config = false, max = 60, font = font, size = 10,
			point = "TOPRIGHT", hide = false
		},
		Spell = {--技能书
			config = false, min = 3, font = font, size = 20, shine = true,
			time = 1, scale = 150, style = 2, hide = false
		},
		Item = {
			config = true,  min = 3, font = font, size = 20, shine = true,
			time = 1, scale = 150, style = 2, hide = false
		},
		Color = {
			Range =  {r = 0.5, g = 0.1, b = 0.1},
			Mana =   {r = 0.5, g = 0.5, b = 1.0},
			Usable = {r = 0.4, g = 0.4, b = 0.4},
			TextColor = {r = 0, g = 1, b = 1},
		},
		Other = {
			text = false, type = nil, num = true, font = font, size = 20, Days = 0, Hours = 0, Mins = 0, Secs = 0, Short = 0,
			Color = {"Usable", "Range", "Mana"},
		},
		Fonts = {font},
	}
end

function wsCC:GetIcon(name)
	if (not name) then return end
	local booktype = {"spell", "pet"}
	local i, spell, j, _ =1
	for _,book in pairs(booktype) do
		while name do
			spell, _ = GetSpellName(i, book)
			if (not spell) then
				i = 1
				break;
			end
			if ( string.lower(name) == string.lower(spell)) then
				return GetSpellTexture(i, book)
			end
			i = i+ 1;
		end
	end
end

function Timer_OnUpdate(self, elapsed)
	if not wsCC:get(self.type, "config") or not self.cd:IsVisible() or self.duration <= (wsCC:get(self.type, "min") or 0) then
		self:Hide()
		return
	end
	if (self.nextUpdate <= 0) then
		wsCC:UpdateTimer(self)
	else
		self.nextUpdate = self.nextUpdate - elapsed
	end
end

local function Center_OnUpdate(self, elapsed)
	self.finish = self.finish + elapsed
	local alpha = wsCC:get(self.type, "calpha")
	if self.finish > wsCC:get(self.type, "ctime") / 2 then
		alpha = (1 - self.finish / wsCC:get(self.type, "ctime")) * 2 * alpha
	end
	self:SetAlpha(alpha)

	if self.finish >= wsCC:get(self.type, "ctime") then
		self.finish = 0
		self:Hide()
	end
end

local function Shine_OnUpdate(self, elapsed)
	local type = self.type
	if wsCC:get(type, "shine") then
		self.finish = self.finish + elapsed
		if self.finish >= wsCC:get(type, "time") then
			self:Hide()
			return
		end
		local alpha = 1 - self.finish / wsCC:get(type, "time")
		local scale = wsCC:get(type, "scale") * (1- self.finish / wsCC:get(type, "time"))
		self.icon:SetWidth(scale)
		self.icon:SetHeight(scale)
		self.icon:SetAlpha(alpha)
	end
end

function wsCC:StartTimer(cd, start, duration, type)
	local timer = timers[cd] or self:CreateTimer(cd)
	if (timer) then
		cd:SetAlpha(self:get(type, "hide") and 0 or 1)
		timer.start = start
		timer.duration = duration
		timer.type = type
		timer.cd = cd
		timer.nextUpdate = 0
		if (wsCCDB["Other"]["num"]) then
			timer:Show()
		else
			timer:Hide()
		end
	end
end

function wsCC:CreateTimer(cd)
	local timer = CreateFrame("Frame", nil, cd:GetParent())
	timer:SetFrameLevel(cd:GetFrameLevel() + 5)
	timer:SetAllPoints(cd)
	timer:SetToplevel(true)
	timer:Hide()
	timer:SetScript("OnUpdate", Timer_OnUpdate)

	local text = timer:CreateFontString(nil, "OVERLAY")
	text:SetPoint("CENTER", timer, self:get(type, "point") or "CENTER", 0, 1)
	timer.text = text

	local btn = cd:GetParent()
	if btn then
		if btn.icon then
			timer.icon = btn.icon
		else
			local name = btn:GetName()
			if name then
				timer.icon = getglobal(name .. "Icon") or getglobal(name .. "IconTexture")
			end
		end
	end
	timers[cd] = timer
	return timer
end

function wsCC:UpdateTimer(timer)
	local type = timer.type
	local time = timer.start + timer.duration - GetTime()
	local max = self:get(type, "max")
	if max then
		if time > max and max ~= 0 then
			if timer.text:IsVisible() then
				timer.text:Hide()
			end
			return
		else
			if not timer.text:IsVisible() then
				timer.text:Show()
			end
		end
	end

	if timer.text:IsVisible() then
		local text, scale, r, g, b, nextUpdate = self:GetFormattedTime(time)

		timer.text:SetFont(self:get(type, "font"), self:get(type, "size"), "OUTLINE")
		timer.text:SetText(text)
		--bug <unnamed>:SetText(): Font not set
		timer.text:SetTextColor(r, g, b)
		timer.text:SetPoint("CENTER", timer, self:get(type, "point") or "CENTER", 0, 0)
		timer:SetScale(scale)

		timer.nextUpdate = nextUpdate
	end

	if time < 0.2 then
		timer:Hide()
		if self:get(type, "sound") and timer.icon and centerData[timer.icon:GetTexture()] then
			PlaySoundFile("Interface\\AddOns\\wsCC\\sound.wav")
		end
		if self:get(type, "shine") then
			self:StartShine(timer)
		end
		if self:get(type, "center") then
			self:StartCenter(timer)
		end
	end

end

function wsCC:CreateCenter()
	center = CreateFrame("frame", nil, UIParent)
	center:Hide()
	center:SetAllPoints(UIParent)
	center:SetFrameStrata("HIGH")
	center:SetScript("OnUpdate", function(self, elapsed) Center_OnUpdate(self, elapsed) end)

	center.icon = center:CreateTexture(nil, "OVERLAY")
	center.icon:Show()
	center.text = center:CreateFontString(nil, "ARTWORK", "SystemFont_Large")
	center.text:SetPoint("TOP", center.icon, "BOTTOM")

	self.center = center
	return center
end


function wsCC:StartCenter(timer)
	center = self.center or self:CreateCenter()
	text = centerData[timer.icon:GetTexture()]
	center.text:SetText("")

	if text and self:get("Other", "text") then
		color = self:get("Color", "TextColor")
		center.text:SetFont(self:get("Other", "font"), self:get("Other", "size"), "OUTLINE")
		center.text:SetText(format(("%s 준비 완료!"), "|cff"..format("%2x%2x%2x",color.r*255,color.g*255,color.b*255)..text.."|r"))
--		center.text:SetText(format(L("WS_CDOVER"), "|cff"..format("%2x%2x%2x",color.r*255,color.g*255,color.b*255)..text.."|r"))
	end
	if center:IsVisible() and center.start and center.start == timer.start then
		if text then
			centerData[timer.icon:GetTexture()] = nil
		else
			return
		end
	end
	center:ClearAllPoints()
	if self:get(timer.type, "p") then
		center.icon:SetPoint(self:get(timer.type, "p"),
			UIParent,
			self:get(timer.type, "s"),
			self:get(timer.type, "x"),
			self:get(timer.type, "y"))
	else
		center.icon:SetPoint("CENTER",UIParent, "CENTER" ,0,0)--set
	end
	center.icon:SetWidth(self:get(timer.type, "cscale"))
	center.icon:SetHeight(self:get(timer.type, "cscale"))
	center.icon:SetBlendMode(self:get(timer.type, "cmode") and "ADD" or "BLEND")
	center.icon:SetTexture(timer.icon:GetTexture())

	center.finish = 0
	center.start = timer.start
	center.type = timer.type
	center:Show()
end

--新增 shine 参数
--add
function wsCC:UpdateAllShines(elapsed)
	if next(activeShines) then
		for shine in pairs(activeShines) do
			self:UpdateShine(shine, elapsed)
		end
	else
		self:Hide()
	end
end
--add
function wsCC:UpdateShine(shine, elapsed)
	local type = shine.type
	if self:get(type, "shine") then
		shine.finish = shine.finish + elapsed
		if shine.finish >= self:get(type, "time") then
			activeShines[shine] = nil
			shine:Hide()
			return
		end
		local time = self:get(type, "time")
		local alpha = 1 - shine.finish / time
		local scale = self:get(type, "scale") * ( 1 - shine.finish / time)
		shine.icon:SetWidth(scale)
		shine.icon:SetHeight(scale)
		shine.icon:SetAlpha(alpha)
	end
end

function wsCC:StartShine(timer)
	local btn = timer:GetParent()

	if btn:IsVisible() then
		local shine = shines[btn] or self:CreateShine(btn)
		if shine then
			shine.finish = 0
			shine.type = timer.type
			if self:get(timer.type, "style") == 1 then
				shine.icon:SetTexture(timer.icon:GetTexture())
			else
				shine.icon:SetTexture(shine_style[self:get(timer.type, "style")])
			end
			activeShines[shine] = true;
			shine:Show();
			self:Show();
		end
	end
end

function wsCC:CreateShine(btn)
	local shine = CreateFrame("Frame", nil, btn)
	shine:SetAllPoints(btn)
	shine:SetToplevel(true)
	shine:SetScript("OnUpdate", function(self, elapsed) Shine_OnUpdate(self, elapsed) end)

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

	shines[btn] = shine
	return shine
end

--returns the formatted time, scaling to use, color, and the time until the next update is needed
function wsCC:GetFormattedTime(t)
	if t < 9 then
		return ceil(t), 1.3,					-- scale
			1, t-floor(t)>0.5 and 0.12 or 0.82, 0.12,	-- rgb
			0.2						-- nextUpdate
	elseif t < 60 then
		return ceil(t), 1,	-- scale
			1, 0.82, 0,	-- rgb
			t-floor(t)	-- nextUpdate
	elseif t < 600 then
		if self:get("Other", "type") then
			return format("%d:%02d",floor(t/60),t%60), 0.7,	-- scale
				0.8,0.6,0,				-- rgb
				t-floor(t)				-- nextUpdate
		end
		return ceil(t/60).."m", 0.85,	-- scale
			0.8,0.6,0,		-- rgb
			t-floor(t)		-- nextUpdate
	elseif t < 3600 then
		return ceil(t/60).."m", 0.7,	-- scale
			0.8,0.6,0,		-- rgb
			t%60			-- nextUpdate
	elseif (t < 86400) then
		return ceil(t / 3600).."h", 0.6,	-- scale
			0.6,0.4,0,			-- rgb
			t%3600				-- nextUpdate
	else
		return ceil(t / 86400).."d", 0.6,	-- scale
			0.4,0.4,0.4,			-- rgb
			t%86400				-- nextUpdate
	end
end

function wsCC:get(type, var)
	if wsCCDB[type] and wsCCDB[type][var] then
		return wsCCDB[type][var]
	else
		return nil
	end
end

function wsCC:ButtonGetType(btn)
	local name, index = btn:GetName()
	for _, index in ipairs(WSBTNTREE) do
		if index.key == 1 then
			if string.find(name, index.value) then
				return index.type
			end
		elseif index.key == 2 then
			if getglobal(name..index.value) then
				return index.type
			end
		end
	end
	return "Buff"
end