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

MoneyFu = FuBarPlugin:GetInstance("1.2"):new({
	name		  = MoneyFuLocals.NAME,
	description   = MoneyFuLocals.DESCRIPTION,
	version	   = "1.2." .. string.sub("$Revision: 2203 $", 12, -3),
	releaseDate   = string.sub("$Date: 2006-05-29 22:29:22 -1000 (Mon, 29 May 2006) $", 8, 17),
	aceCompatible = 103,
	author		= "ckknight",
	email		 = "ckknight@gmail.com",
	website	   = "http://ckknight.wowinterface.com/",
	category	  = "inventory",
	db			= AceDatabase:new("MoneyFuDB"),
	chardb		= "MoneyFuCharDB",
	defaults	  = {
		style = "GRAPHICAL",
		trackByRealm = true,
	},
	realmDefaults = {
		chars = {},
		spent = {},
		gained = {},
		time = {},
	},
	charDefaults = {
		spent = {},
		gained = {},
		time = {},
	},
	cmd		   = AceChatCmd:new(MoneyFuLocals.COMMANDS, MoneyFuLocals.CMD_OPTIONS),
	loc		   = MoneyFuLocals,
})
MoneyFu.frame = MoneyFu:CreateBasicPluginFrame("MoneyFuFrame")

function MoneyFu:GetStyle()
	if self.data == nil then
		return "GRAPHICAL"
	end
	return self.data.style or "GRAPHICAL"
end

function MoneyFu:SetStyle(style)
	style = string.upper(style)
	if style ~= "GRAPHICAL" and style ~= "FULL" and style ~= "SHORT" and style ~= "CONDENSED" then
		style = "GRAPHICAL"
	end
	self.data.style = style
	self:UpdateText()
end

function MoneyFu:IsTrackingByRealm()
	return self.data.trackByRealm
end

function MoneyFu:ToggleTrackingByRealm()
	self.data.trackByRealm = not self.data.trackByRealm
	if loud then
		self.cmd:status(self.loc.ARGUMENT_TRACKBYREALM, self.data.trackByRealm and 1 or 0, FuBarLocals.MAP_ONOFF)
	end
	self:UpdateTooltip()
	return self.data.trackByRealm
end

function MoneyFu:ResetSession(loud)
	self.initialMoney = GetMoney()
	self.sessionTime = time()
	self.gained = 0
	self.spent = 0
	if loud then
		self.cmd:msg(self.loc.TEXT_SESSION_RESET)
	end
end

function MoneyFu:Initialize()
	self.hasIcon = true
	self.canHideText = true
	local frame = self.frame
	local icon = frame:CreateTexture("MoneyFuFrameIcon", "ARTWORK")
	icon:SetWidth(16)
	icon:SetHeight(16)
	icon:SetPoint("LEFT", frame, "LEFT")
	self.iconFrame = icon
	
	local text = frame:CreateFontString("MoneyFuFrameText", "OVERLAY")
	text:SetJustifyH("RIGHT")
	text:SetPoint("RIGHT", frame, "RIGHT", 0, 1)
	text:SetFontObject(GameFontNormal)
	self.textFrame = text
	
	self:SetIcon(true)
	
	local goldIcon = frame:CreateTexture("MoneyFuFrameGoldIcon", "ARTWORK")
	goldIcon:SetWidth(16)
	goldIcon:SetHeight(16)
	goldIcon:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
	goldIcon:SetTexCoord(0, 0.25, 0, 1)
	
	local silverIcon = frame:CreateTexture("MoneyFuFrameSilverIcon", "ARTWORK")
	silverIcon:SetWidth(16)
	silverIcon:SetHeight(16)
	silverIcon:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
	silverIcon:SetTexCoord(0.25, 0.5, 0, 1)
	
	local copperIcon = frame:CreateTexture("MoneyFuFrameCopperIcon", "ARTWORK")
	copperIcon:SetWidth(16)
	copperIcon:SetHeight(16)
	copperIcon:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
	copperIcon:SetTexCoord(0.5, 0.75, 0, 1)
	
	local goldText = frame:CreateFontString("MoneyFuFrameGoldText", "OVERLAY")
	goldText:SetJustifyH("RIGHT")
	goldText:SetPoint("RIGHT", goldIcon, "LEFT", 0, 1)
	goldText:SetFontObject(GameFontNormal)
	
	local silverText = frame:CreateFontString("MoneyFuFrameSilverText", "OVERLAY")
	silverText:SetJustifyH("RIGHT")
	silverText:SetPoint("RIGHT", silverIcon, "LEFT", 0, 1)
	silverText:SetFontObject(GameFontNormal)
	
	local copperText = frame:CreateFontString("MoneyFuFrameCopperText", "OVERLAY")
	copperText:SetJustifyH("RIGHT")
	copperText:SetPoint("RIGHT", copperIcon, "LEFT", 0, 1)
	copperText:SetFontObject(GameFontNormal)
	
	copperIcon:SetPoint("RIGHT", frame, "RIGHT")
	silverIcon:SetPoint("RIGHT", copperText, "LEFT")
	goldIcon:SetPoint("RIGHT", silverText, "LEFT")
end

local function GetToday(self)
	return floor((time() / 60 / 60 + self:GetServerOffset()) / 24)
end

function MoneyFu:Enable()
	self.initialMoney = GetMoney()
	self.lastMoney = self.initialMoney
	self.lastTime = GetToday(self)
	local lastWeek = self.lastTime - 6
	for day in pairs(self.charData.gained) do
		if day < lastWeek then
			self.charData.gained[day] = nil
		end
	end
	for day in pairs(self.charData.spent) do
		if day < lastWeek then
			self.charData.spent[day] = nil
		end
	end
	for day in pairs(self.charData.time) do
		if day < lastWeek then
			self.charData.time[day] = nil
		end
	end
	for day in pairs(self.realmData.gained) do
		if day < lastWeek then
			self.realmData.gained[day] = nil
		end
	end
	for day in pairs(self.realmData.spent) do
		if day < lastWeek then
			self.realmData.spent[day] = nil
		end
	end
	for day in pairs(self.realmData.time) do
		if day < lastWeek then
			self.realmData.time[day] = nil
		end
	end
	for i = self.lastTime - 6, self.lastTime do
		if not self.charData.gained[i] then
			self.charData.gained[i] = 0
		end
		if not self.charData.spent[i] then
			self.charData.spent[i] = 0
		end
		if not self.charData.time[i] then
			self.charData.time[i] = 0
		end
		if not self.realmData.gained[i] then
			self.realmData.gained[i] = 0
		end
		if not self.realmData.spent[i] then
			self.realmData.spent[i] = 0
		end
		if not self.realmData.time[i] then
			self.realmData.time[i] = 0
		end
	end
	self.gained = 0
	self.spent = 0
	self.sessionTime = time()
	self.savedTime = time()
	
	if self:GetStyle() == "GRAPHICAL" then
		self:HideIcon()
		self.iconFrame:Hide()
		self.hasIcon = false
	end
	self:RegisterEvent("PLAYER_MONEY", "Update")
	self:RegisterEvent("PLAYER_TRADE_MONEY", "Update")
	self:RegisterEvent("TRADE_MONEY_CHANGED", "Update")
	self:RegisterEvent("SEND_MAIL_MONEY_CHANGED", "Update")
	self:RegisterEvent("SEND_MAIL_COD_CHANGED", "Update")
	
	self:Hook("OpenCoinPickupFrame")
	
	MoneyFuFrameGoldIcon:ClearAllPoints()
	MoneyFuFrameGoldIcon:SetPoint("RIGHT", MoneyFuFrameSilverText, "LEFT", 0, -1)
	MoneyFuFrameSilverIcon:ClearAllPoints()
	MoneyFuFrameSilverIcon:SetPoint("RIGHT", MoneyFuFrameCopperText, "LEFT", 0, -1)
	
	metro:Register(self.name, self.UpdateTooltip, 1, self)
	metro:Start(self.name)
end

function MoneyFu:Disable()
	metro:Unregister(self.name)
end

function MoneyFu:MenuSettings(level, value)
	if level == 1 then
		dewdrop:AddLine(
			'text', self.loc.MENU_RESET_SESSION,
			'arg1', self,
			'func', "ResetSession",
			'closeWhenClicked', true
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_CHARACTER_SPECIFIC_CASHFLOW,
			'arg1', self,
			'func', "ToggleTrackingByRealm",
			'checked', not self:IsTrackingByRealm()
		)
		
		dewdrop:AddLine()
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_GRAPHICAL,
			'arg1', self,
			'func', self:GetStyle() ~= "GRAPHICAL" and "SetStyle",
			'arg2', "GRAPHICAL",
			'checked', self:GetStyle() == "GRAPHICAL",
			'isRadio', true
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_FULL,
			'arg1', self,
			'func', self:GetStyle() ~= "FULL" and "SetStyle",
			'arg2', "FULL",
			'checked', self:GetStyle() == "FULL",
			'isRadio', true
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_SHORT,
			'arg1', self,
			'func', self:GetStyle() ~= "SHORT" and "SetStyle",
			'arg2', "SHORT",
			'checked', self:GetStyle() == "SHORT",
			'isRadio', true
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_CONDENSED,
			'arg1', self,
			'func', self:GetStyle() ~= "CONDENSED" and "SetStyle",
			'arg2', "CONDENSED",
			'checked', self:GetStyle() == "CONDENSED",
			'isRadio', true
		)
		
		if next(self.realmData.chars) ~= UnitName("player") or next(self.realmData.chars, UnitName("player")) then
			dewdrop:AddLine()
			
			dewdrop:AddLine(
				'text', self.loc.MENU_PURGE,
				'hasArrow', true,
				'value', "purge"
			)
		end
	elseif level == 2 then
		if value == "purge" then
			for name in self.realmData.chars do
				if name ~= UnitName("player") then
					dewdrop:AddLine(
						'text', name,
						'arg1', name,
						'func', function(name)
							self.realmData.chars[name] = nil
						end,
						'closeWhenClicked', true
					)
				end
			end
		end
	end
end

function MoneyFu:UpdateData()
	local today = GetToday(self)
	if not self.lastTime then
		self.lastTime = today
	end
	if today > self.lastTime then
		self.charData.gained[today - 7] = nil
		self.charData.spent[today - 7] = nil
		self.charData.time[today - 7] = nil
		self.realmData.gained[today - 7] = nil
		self.realmData.spent[today - 7] = nil
		self.realmData.time[today - 7] = nil
		self.charData.gained[today] = self.charData.gained[today] or 0
		self.charData.spent[today] = self.charData.spent[today] or 0
		self.charData.time[today] = self.charData.time[today] or 0
		self.realmData.gained[today] = self.realmData.gained[today] or 0
		self.realmData.spent[today] = self.realmData.spent[today] or 0
		self.realmData.time[today] = self.realmData.time[today] or 0
		self.lastTime = today
	end
	local current = GetMoney()
	if not self.lastMoney then
		self.lastMoney = current
	end
	if self.lastMoney < current then
		self.gained = (self.gained or 0) + current - self.lastMoney
		self.charData.gained[today] = (self.charData.gained[today] or 0) + current - self.lastMoney
		self.realmData.gained[today] = (self.realmData.gained[today] or 0) + current - self.lastMoney
	elseif self.lastMoney > current then
		self.spent = (self.spent or 0) + self.lastMoney - current
		self.charData.spent[today] = (self.charData.spent[today] or 0) + self.lastMoney - current
		self.realmData.spent[today] = (self.realmData.spent[today] or 0) + self.lastMoney - current
	end
	self.lastMoney = current
	self.realmData.chars[UnitName("player")] = current
	local now = time()
	self.charData.time[today] = self.charData.time[today] + now - self.savedTime
	self.realmData.time[today] = self.realmData.time[today] + now - self.savedTime
	self.savedTime = now
end

function MoneyFu:UpdateText()
	if self.data == nil then
		return
	end
	if self:GetStyle() == "GRAPHICAL" then
		if self:IsIconShown() then
			self.data.iconVisible = true
			self:HideIcon()
		end
		self.hasIcon = false
		MoneyFuFrameIcon:Hide()
		MoneyFuFrameText:Hide()
		local copper = GetMoney()
		local gold = floor(copper / 10000)
		local silver = mod(floor(copper / 100), 100)
		copper = mod(copper, 100)
		local width = 0
		if gold == 0 then
			MoneyFuFrameGoldIcon:Hide()
			MoneyFuFrameGoldText:Hide()
		else
			MoneyFuFrameGoldIcon:Show()
			MoneyFuFrameGoldText:Show()
			MoneyFuFrameGoldText:SetWidth(0)
			MoneyFuFrameGoldText:SetText(gold)
			width = width + MoneyFuFrameGoldIcon:GetWidth() + MoneyFuFrameGoldText:GetWidth()
		end
		if gold == 0 and silver == 0 then
			MoneyFuFrameSilverIcon:Hide()
			MoneyFuFrameSilverText:Hide()
		else
			MoneyFuFrameSilverIcon:Show()
			MoneyFuFrameSilverText:Show()
			MoneyFuFrameSilverText:SetWidth(0)
			MoneyFuFrameSilverText:SetText(silver)
			width = width + MoneyFuFrameSilverIcon:GetWidth() + MoneyFuFrameSilverText:GetWidth()
		end
		MoneyFuFrameCopperIcon:Show()
		MoneyFuFrameCopperText:Show()
		MoneyFuFrameCopperText:SetWidth(0)
		MoneyFuFrameCopperText:SetText(copper)
		width = width + MoneyFuFrameCopperIcon:GetWidth() + MoneyFuFrameCopperText:GetWidth()
		self.frame:SetWidth(width)
	else
		if not self.hasIcon then
			self.hasIcon = true
			if self.data.iconVisible then
				self:ShowIcon()
			end
		end
		self.data.iconVisible = false
		MoneyFuFrameGoldIcon:Hide()
		MoneyFuFrameSilverIcon:Hide()
		MoneyFuFrameCopperIcon:Hide()
		MoneyFuFrameGoldText:Hide()
		MoneyFuFrameSilverText:Hide()
		MoneyFuFrameCopperText:Hide()
		MoneyFuFrameText:Show()
		if self:GetStyle() == "CONDENSED" then
			self:SetText(FuBarUtils.FormatMoneyCondensed(GetMoney(), true))
		elseif self:GetStyle() == "FULL" then
			self:SetText(FuBarUtils.FormatMoneyFull(GetMoney(), true))
		else
			self:SetText(FuBarUtils.FormatMoneyShort(GetMoney(), true))
		end
		self:CheckWidth(true)
	end
end

function MoneyFu:UpdateTooltip()
	local now = time()
	local today = self.lastTime
	self.charData.time[today] = self.charData.time[today] + now - self.savedTime
	self.realmData.time[today] = self.realmData.time[today] + now - self.savedTime
	self.savedTime = now
	local func
	if self:GetStyle() == "CONDENSED" then
		func = FuBarUtils.FormatMoneyCondensed
	elseif self:GetStyle() == "SHORT" then
		func = FuBarUtils.FormatMoneyShort
	else
		func = FuBarUtils.FormatMoneyFull
	end
	
	local supercat = tablet:AddCategory(
		'columns', 3,
		'child_text2', self.loc.TEXT_AMOUNT,
		'child_text3', self.loc.TEXT_PER_HOUR,
		'child_child_textR', 1,
		'child_child_textG', 1,
		'child_child_textB', 0,
		'child_child_text2R', 1,
		'child_child_text2G', 1,
		'child_child_text2B', 1,
		'child_child_text3R', 1,
		'child_child_text3G', 1,
		'child_child_text3B', 1
	)
	
	local cat = supercat:AddCategory(
		'text', self.loc.TEXT_THIS_SESSION
	)
	
	cat:AddLine(
		'text', self.loc.TEXT_GAINED,
		'text2', func(self.gained, true),
		'text3', func(self.gained / (now - self.sessionTime) * 3600, true)
	)
	cat:AddLine(
		'text', self.loc.TEXT_SPENT,
		'text2', func(self.spent, true),
		'text3', func(self.spent / (now - self.sessionTime) * 3600, true)
	)
	local profit = self.gained - self.spent
	cat:AddLine(
		'text', profit >= 0 and self.loc.TEXT_PROFIT or self.loc.TEXT_LOSS,
		'text2', func(profit, true, true),
		'text3', func(profit / (now - self.sessionTime) * 3600, true, true)
	)
	
	local t = self:IsTrackingByRealm() and self.realmData or self.charData
	local gained = t.gained
	local spent = t.spent
	local time = t.time
	
	cat = supercat:AddCategory(
		'text', HONOR_THIS_SESSION
	)
	
	cat:AddLine(
		'text', self.loc.TEXT_GAINED,
		'text2', func(gained[self.lastTime], true),
		'text3', func(gained[self.lastTime] / time[self.lastTime] * 3600, true)
	)
	cat:AddLine(
		'text', self.loc.TEXT_SPENT,
		'text2', func(spent[self.lastTime], true),
		'text3', func(spent[self.lastTime] / time[self.lastTime] * 3600, true)
	)
	local profit = gained[self.lastTime] - spent[self.lastTime]
	cat:AddLine(
		'text', profit >= 0 and self.loc.TEXT_PROFIT or self.loc.TEXT_LOSS,
		'text2', func(profit, true, true),
		'text3', func(profit / time[self.lastTime] * 3600, true, true)
	)
	
	cat = supercat:AddCategory(
		'text', HONOR_YESTERDAY
	)
	
	cat:AddLine(
		'text', self.loc.TEXT_GAINED,
		'text2', func(gained[self.lastTime - 1], true),
		'text3', func(gained[self.lastTime - 1] / time[self.lastTime - 1] * 3600, true)
	)
	cat:AddLine(
		'text', self.loc.TEXT_SPENT,
		'text2', func(spent[self.lastTime - 1], true),
		'text3', func(spent[self.lastTime - 1] / time[self.lastTime - 1] * 3600, true)
	)
	local profit = gained[self.lastTime - 1] - spent[self.lastTime - 1]
	cat:AddLine(
		'text', profit >= 0 and self.loc.TEXT_PROFIT or self.loc.TEXT_LOSS,
		'text2', func(profit, true, true),
		'text3', func(profit / time[self.lastTime - 1] * 3600, true, true)
	)
	
	local weekGained = 0
	local weekSpent = 0
	local weekTime = 0
	for i = self.lastTime - 6, self.lastTime do
		weekGained = weekGained + gained[i]
		weekSpent = weekSpent + spent[i]
		weekTime = weekTime + time[i]
	end
	cat = supercat:AddCategory(
		'text', HONOR_THISWEEK
	)
	
	cat:AddLine(
		'text', self.loc.TEXT_GAINED,
		'text2', func(weekGained, true),
		'text3', func(weekGained / weekTime * 3600, true)
	)
	cat:AddLine(
		'text', self.loc.TEXT_SPENT,
		'text2', func(weekSpent, true),
		'text3', func(weekSpent / weekTime * 3600, true)
	)
	local profit = weekGained - weekSpent
	cat:AddLine(
		'text', profit >= 0 and self.loc.TEXT_PROFIT or self.loc.TEXT_LOSS,
		'text2', func(profit, true, true),
		'text3', func(profit / weekTime * 3600, true, true)
	)
	
	local total = 0
	local addedCat = false
	if next(self.realmData.chars) ~= UnitName("player") or next(self.realmData.chars, UnitName("player")) then
		local t = compost:Acquire()
		for name in pairs(self.realmData.chars) do
			table.insert(t, name)
		end
		table.sort(t, function(alpha, bravo)
			return self.realmData.chars[alpha] < self.realmData.chars[bravo]
		end)
		
		cat = tablet:AddCategory(
			'columns', 2,
			'text', self.loc.TEXT_CHARACTERS,
			'text2', "Amount",
			'child_textR', 1,
			'child_textG', 1,
			'child_textB', 0,
			'child_text2R', 1,
			'child_text2G', 1,
			'child_text2B', 1
		)
		for _,name in t do
			local value = self.realmData.chars[name]
			cat:AddLine(
				'text', name,
				'text2', func(value, true)
			)
			total = total + value
		end
	else
		total = self.realmData.chars[UnitName("player")]
	end
	
	cat = tablet:AddCategory(
		'columns', 2,
		'child_textR', 1,
		'child_textG', 1,
		'child_textB', 1,
		'child_text2R', 1,
		'child_text2G', 1,
		'child_text2B', 1
	)
	
	cat:AddLine(
		'text', self.loc.TEXT_TOTAL,
		'text2', func(total, true)
	)
	
	tablet:SetHint(self.loc.HINT)
end

local function getsecond(_, value)
	return value
end

function MoneyFu:OnClick(button)
	local money = GetMoney()
	if money < 100 then
		money = 1
	elseif money < 10000 then
		money = 100
	else
		money = 10000
	end
	self.frame.moneyType = "PLAYER"
	OpenCoinPickupFrame(money, GetMoney(), self.frame)
	self.frame.hasPickup = 1
	
	CoinPickupFrame:ClearAllPoints()
	local frame = self.frame
	if self:IsMinimapAttached() then
		frame = self.minimapFrame
	end
	if frame:GetCenter() < GetScreenWidth()/2 then
		if getsecond(frame:GetCenter()) < GetScreenHeight()/2 then
			CoinPickupFrame:SetPoint("BOTTOMLEFT", frame, "TOPLEFT")
		else
			CoinPickupFrame:SetPoint("TOPLEFT", frame, "BOTTOMLEFT")
		end
	else
		if getsecond(frame:GetCenter()) < GetScreenHeight()/2 then
			CoinPickupFrame:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT")
		else
			CoinPickupFrame:SetPoint("TOPRIGHT", frame, "BOTTOMRIGHT")
		end
	end
end

function MoneyFu:OpenCoinPickupFrame(multiplier, maxMoney, parent)
	CoinPickupFrame:ClearAllPoints()
	self:CallHook("OpenCoinPickupFrame", multiplier, maxMoney, parent)
end

function MoneyFu:SetFontSize(size)
	if MoneyFuFrameGoldIcon == nil then
		self.fontSize = size
		return
	end
	MoneyFuFrameGoldIcon:SetWidth(size)
	MoneyFuFrameGoldIcon:SetHeight(size)
	MoneyFuFrameSilverIcon:SetWidth(size)
	MoneyFuFrameSilverIcon:SetHeight(size)
	MoneyFuFrameCopperIcon:SetWidth(size)
	MoneyFuFrameCopperIcon:SetHeight(size)
	self.iconFrame:SetWidth(size)
	self.iconFrame:SetHeight(size)
	local font,_,flags = MoneyFuFrameGoldText:GetFont()
	if font ~= nil then
		MoneyFuFrameGoldText:SetFont(font, size, flags)
		MoneyFuFrameSilverText:SetFont(font, size, flags)
		MoneyFuFrameCopperText:SetFont(font, size, flags)
		self.textFrame:SetFont(font, size)
	end
	self:UpdateText()
end

local offset
function MoneyFu:GetServerOffset()
	if offset then
		return offset
	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
	offset = floor((ser - utc) * 2 + 0.5) / 2
	if offset >= 12 then
		offset = offset - 24
	elseif offset < -12 then
		offset = offset + 24
	end
	return offset
end

MoneyFu:RegisterForLoad()