local compost = CompostLib:GetInstance('compost-1')
local dewdrop = DewdropLib:GetInstance('1.0')
local tablet = TabletLib:GetInstance('1.0')
local metro = Metrognome:GetInstance('1')

ClockFu = FuBarPlugin:GetInstance("1.2"):new({
	name          = ClockFuLocals.NAME,
	description   = ClockFuLocals.DESCRIPTION,
	version       = "1.1." .. string.sub("$Revision: 1615 $", 12, -3),
	releaseDate   = string.sub("$Date: 2006-05-08 10:37:44 -0500 (Mon, 08 May 2006) $", 8, 17),
	aceCompatible = 103,
	author        = "ckknight",
	email         = "ckknight@gmail.com",
	website       = "http://ckknight.wowinterface.com/",
	category      = "interface",
	db            = AceDatabase:new("ClockFuDB"),
	defaults      = {
		twentyFour = false,
		showSeconds = false,
		localTime = false,
		bothTimes = false,
		bubble = false,
		r = 1,
		g = 1,
		b = 1,
	},
	cmd           = AceChatCmd:new(ClockFuLocals.COMMANDS, ClockFuLocals.CMD_OPTIONS),
	loc           = ClockFuLocals,
	hasIcon       = false,
	defaultPosition = "RIGHT",
})

function ClockFu:GetColor()
	return self.data.r, self.data.g, self.data.b
end

function ClockFu:GetHexColor()
	return format("%02x%02x%02x", self.data.r * 255, self.data.g * 255, self.data.b * 255)
end

function ClockFu:SetColor(r, g, b)
	self.data.r = r
	self.data.g = g
	self.data.b = b
	self:UpdateText()
end

function ClockFu:IsTwentyFour()
	return self.data.twentyFour
end

function ClockFu:ToggleTwentyFour(loud)
	self.data.twentyFour = not self.data.twentyFour
	if loud then
		self.cmd:status(self.loc.ARGUMENT_TWENTYFOUR, self.data.twentyFour and 1 or 0, FuBarLocals.MAP_ONOFF)
	end
	self:Update()
	return self.data.twentyFour
end

function ClockFu:IsShowingSeconds()
	return self.data.showSeconds
end

function ClockFu:ToggleShowSeconds(loud)
	self.data.showSeconds = not self.data.showSeconds
	if loud then
		self.cmd:status(self.loc.ARGUMENT_SHOWSECONDS, self.data.showSeconds and 1 or 0, FuBarLocals.MAP_ONOFF)
	end
	self:Update()
	return self.data.showSeconds
end

function ClockFu:IsLocalTime()
	return self.data.localTime
end

function ClockFu:ToggleLocalTime(loud)
	self.data.localTime = not self.data.localTime
	if loud then
		self.cmd:status(self.loc.ARGUMENT_LOCALTIME, self.data.localTime and 1 or 0, FuBarLocals.MAP_ONOFF)
	end
	self:Update()
	return self.data.localTime
end

function ClockFu:IsBothTimes()
	return self.data.bothTimes
end

function ClockFu:ToggleBothTimes(loud)
	self.data.bothTimes = not self.data.bothTimes
	if loud then
		self.cmd:status(self.loc.ARGUMENT_BOTHTIMES, self.data.bothTimes and 1 or 0, FuBarLocals.MAP_ONOFF)
	end
	self:Update()
	return self.data.bothTimes
end

function ClockFu:IsShowingBubble()
	return self.data.bubble
end

function ClockFu:ToggleShowingBubble(loud)
	self.data.bubble = not self.data.bubble
	if loud then
		self.cmd:status(self.loc.ARGUMENT_BUBBLE, self.data.bubble and 1 or 0, FuBarLocals.MAP_ONOFF)
	end
	if not self.data.bubble then
		GameTimeFrame:Hide()
	else
		GameTimeFrame:Show()
	end
	return self.data.bubble
end

function ClockFu:GetLocalOffset()
	if self.localOffset ~= nil then
		return self.localOffset
	end
	local localHour = tonumber(date("%H"))
	local localMinute = tonumber(date("%M"))
	local utcHour = tonumber(date("!%H"))
	local utcMinute = tonumber(date("!%M"))
	local loc = localHour + localMinute / 60
	local utc = utcHour + utcMinute / 60
	self.localOffset = floor((loc - utc) * 2 + 0.5) / 2
	if self.localOffset >= 12 then
		self.localOffset = self.localOffset - 24
	end
	return self.localOffset
end

function ClockFu:GetServerOffset()
	if self.serverOffset ~= nil then
		return self.serverOffset
	end
	local serverHour, serverMinute = GetGameTime()
	local utcHour = tonumber(date("!%H"))
	local utcMinute = tonumber(date("!%M"))
	local ser = serverHour + serverMinute / 60
	local utc = utcHour + utcMinute / 60
	self.serverOffset = floor((ser - utc) * 2 + 0.5) / 2
	if self.serverOffset >= 12 then
		self.serverOffset = self.serverOffset - 24
	elseif self.serverOffset < -12 then
		self.serverOffset = self.serverOffset + 24
	end
	return self.serverOffset
end

function ClockFu:Initialize()
	if GroupCalendar_OnLoad then
		self.data.bubble = true
	end
end

function ClockFu:Enable()
	self.timeSinceLastUpdate = 0
	self.secondsDifference = 0
	_,self.lastMinute = GetGameTime()
	if not self:IsShowingBubble() then
		self.data.bubble = TRUE
		self:ToggleShowingBubble()
	end
	metro:Register(self.name, self.Update, 1, self)
	metro:Start(self.name)
end

function ClockFu:Disable()
	if not self:IsShowingBubble() then
		self:ToggleShowingBubble()
		self.data.bubble = not self.data.bubble
	end
	metro:Unregister(self.name)
end

function ClockFu:Report()
	local report = compost:Acquire(
		compost:AcquireHash(
			'text', self.loc.ARGUMENT_TWENTYFOUR,
			'val', self:IsTwentyFour() and 1 or 0,
			'map', FuBarLocals.MAP_ONOFF
		),
		compost:AcquireHash(
			'text', self.loc.ARGUMENT_SHOWSECONDS,
			'val', self:IsShowingSeconds() and 1 or 0,
			'map', FuBarLocals.MAP_ONOFF
		),
		compost:AcquireHash(
			'text', self.loc.ARGUMENT_BUBBLE,
			'val', self:IsShowingBubble() and 1 or 0,
			'map', FuBarLocals.MAP_ONOFF
		),
		compost:AcquireHash(
			'text', self.loc.ARGUMENT_LOCALTIME,
			'val', self:IsLocalTime() and 1 or 0,
			'map', FuBarLocals.MAP_ONOFF
		),
		compost:AcquireHash(
			'text', self.loc.ARGUMENT_BOTHTIMES,
			'val', self:IsBothTimes() and 1 or 0,
			'map', FuBarLocals.MAP_ONOFF
		)
	)
	self.cmd:report(report)
	compost:Reclaim(report, 1)
end

local setColor

function ClockFu:MenuSettings(level, value)
	if level == 1 then
		dewdrop:AddLine(
			'text', self.loc.MENU_24_HOUR_FORMAT,
			'func', function()
				self:ToggleTwentyFour()
			end,
			'checked', self:IsTwentyFour()
		)
		
		dewdrop:AddLine()
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_SECONDS,
			'func', function()
				self:ToggleShowSeconds()
			end,
			'checked', self:IsShowingSeconds()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_LOCAL_TIME,
			'func', function()
				self:ToggleLocalTime()
			end,
			'checked', self:IsLocalTime()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_BOTH_TIMES,
			'func', function()
				self:ToggleBothTimes()
			end,
			'checked', self:IsBothTimes()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_DAY_NIGHT_BUBBLE,
			'func', function()
				self:ToggleShowingBubble()
			end,
			'checked', self:IsShowingBubble()
		)
		
		if not setColor then
			function setColor(r, g, b)
				self:SetColor(r, g, b)
			end
		end
		
		dewdrop:AddLine(
			'text', COLOR,
			'hasColorSwatch', true,
			'swatchFunc', setColor,
			'cancelFunc', setColor,
			'r', self.data.r,
			'g', self.data.g,
			'b', self.data.b,
			'disabled', not self:IsTextColored()
		)
	end
end

function ClockFu:FormatTime(hour, minute, second, colorize)
	if self:IsTwentyFour() then
		if not colorize then
			if self:IsShowingSeconds() then
				return format("%d:%02d:%02d", hour, minute, second)
			else
				return format("%d:%02d", hour, minute)
			end
		else
			local color = self:GetHexColor()
			if self:IsShowingSeconds() then
				return format("|cff%s%d|r:|cff%s%02d|r:|cff%s%02d|r", color, hour, color, minute, color, second)
			else
				return format("|cff%s%d|r:|cff%s%02d|r", color, hour, color, minute)
			end
		end
	else
		pm = floor(hour / 12) == 1
		hour = mod(hour, 12)
		if hour == 0 then
			hour = 12
		end
		if not colorize then
			if self:IsShowingSeconds() then
				return format("%d:%02d:%02d %s", hour, minute, second, pm and " PM" or " AM")
			else
				return format("%d:%02d %s", hour, minute, pm and " PM" or " AM")
			end
		else
			local color = self:GetHexColor()
			if self:IsShowingSeconds() then
				return format("|cff%s%d|r:|cff%s%02d|r:|cff%s%02d|r %s", color, hour, color, minute, color, second, pm and " PM" or " AM")
			else
				return format("|cff%s%d|r:|cff%s%02d|r %s", color, hour, color, minute, pm and " PM" or " AM")
			end
		end
	end
end

function ClockFu:GetServerTime(colorize)
	local hour, minute = GetGameTime()
	if self.lastMinute ~= minute then
		_,self.lastMinute = GetGameTime()
		self.secondsDifference = mod(time(), 60)
	end
	local second = mod(time() - self.secondsDifference, 60)
	return self:FormatTime(hour, minute, second, colorize)
end

function ClockFu:GetLocalTime(colorize)
	local hour = tonumber(date("%H"))
	local minute = tonumber(date("%M"))
	local second = tonumber(date("%S"))
	return self:FormatTime(hour, minute, second, colorize)
end

function ClockFu:GetUtcTime()
	local hour = tonumber(date("!%H"))
	local minute = tonumber(date("!%M"))
	local second = tonumber(date("!%S"))
	return self:FormatTime(hour, minute, second)
end

function ClockFu:UpdateText()
	local hour, minute = GetGameTime()
	if self.lastMinute ~= minute then
		_,self.lastMinute = GetGameTime()
		self.secondsDifference = mod(time(), 60)
	end
	if self:IsBothTimes() then
		if self:IsLocalTime() then
			self:SetText(format("%s || %s", self:GetLocalTime(true), self:GetServerTime(true)))
		else
			self:SetText(format("%s || %s", self:GetServerTime(true), self:GetLocalTime(true)))
		end
	elseif self:IsLocalTime() then
		self:SetText(self:GetLocalTime(true))
	else
		self:SetText(self:GetServerTime(true))
	end
end

function ClockFu:UpdateTooltip()
	local s = self:GetServerOffset()
	local l = self:GetLocalOffset()
	
	local cat = tablet:AddCategory(
		'columns', 2,
		'child_textR', 1,
		'child_textG', 1,
		'child_textB', 0,
		'child_text2R', 1,
		'child_text2G', 1,
		'child_text2B', 1
	)
	cat:AddLine(
		'text', format(self.loc.TEXT_LOCAL_TIME .. " (%+03d:%02d)", l, mod(l * 60, 60)),
		'text2', self:GetLocalTime()
	)
	cat:AddLine(
		'text', format(self.loc.TEXT_SERVER_TIME .. " (%+03d:%02d)", s, mod(s * 60, 60)),
		'text2', self:GetServerTime()
	)
	cat:AddLine(
		'text', "UTC",
		'text2', self:GetUtcTime()
	)
	
	tablet:AddCategory():AddLine(
		'text', date("%A, %B %d, %Y"),
		'textR', 1,
		'textG', 1,
		'textB', 1,
		'justify', "CENTER"
	)
end

ClockFu:RegisterForLoad()
