GMail = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.1")

local L = AceLibrary("AceLocale-2.2"):new("GMail")

GMAIL_HELP = L["Fill in as many slots as you want. Each item will be sent in a separate mail to the recipient, with the subject you specify, followed by the item's name and count (for example: <Subject> [Gold Bar x10]). The combined postage is shown in the top right. You can alt-click on items in your bags to add them to the list automatically."]
GMAIL_SEND = L["Send Mail"]
GMAIL_SENDBUTTON = L["Send"]
GMAIL_CANCELBUTTON = L["Cancel"]
GMAIL_SENDINFO = L["Are you sure you want to send the mail? Total postage will be:"]
GMAIL_SENDINFO2 = L["You are sending:"]
GMAIL_ITEMS = L["Item(s)"]
GMAIL_ABORT = L["Abort"]
GMAIL_ITEMNUM = L["Item %d out of %d."]
GMAIL_SENDING = L["Sending mail |c00FFFFFF%d|r/|c00FFFFFF%d|r..."]
GMAIL_DONESENDING = L["Done sending |c00FFFFFF%d|r mail(s)!"]
GMAIL_ABORTED = L["Aborted. |c00FFFFFF%d|r/|c00FFFFFF%d|r mail were sent."]
GMAIL_INBOX_OPENSELECTED = L["Open Selected"]
GMAIL_INBOX_RETURNSELECTED = L["Return Selected"]
GMAIL_INBOX_OPENALL = L["Open All"]
GMAIL_INBOX_OPENALLTITLE = L["Open All?"]
GMAIL_INBOX_OPENALLCONFIRMATION = L["Are you sure you want to open all mail?"]
GMAIL_INBOX_DISPLAYPROCESSMESSAGES = L["Display process messages"]
GMAIL_MASS_MAIL = L["Mass Mail"]
GMAIL_FORWARD = L["Forward"]
GMAIL_NOSUBJECT = L["<No Subject>"]
GMAIL_UNKNOWNSENDER = L["<Unknown Sender>"]
GMAIL_OPEN_FORMAT1 = L["GMail: Mail |c00FFFFFF%d|r/|c00FFFFFF%d|r is Cash on Delivery, skipping..."]
GMAIL_OPEN_FORMAT2 = L["GMail: Mail |c00FFFFFF%d|r/|c00FFFFFF%d|r has no money or items, skipping..."]
GMAIL_OPEN_FORMAT3 = L["GMail: Opening mail |c00FFFFFF%d|r/|c00FFFFFF%d|r: \"|c00FFFFFF%s|r\" from |c00FFFFFF%s|r."]
GMAIL_RETURN_FORMAT = L["GMail: Returning mail |c00FFFFFF%d|r/|c00FFFFFF%d|r: \"|c00FFFFFF%s|r\" to |c00FFFFFF%s|r."]
GMAIL_ERROR = L["GMail: An error occured in GMail. This might be related to lag, trying to send items with an item placed in the normal send mail window, or trying to send items that cannot be sent."]

function GMail:OnInitialize()
	tinsert(UISpecialFrames, "GMailInboxOpenAll")

	-- Allows the mail frame to be pushed
	if ( UIPanelWindows["MailFrame"] ) then
		UIPanelWindows["MailFrame"].pushable = 1
	else
		UIPanelWindows["MailFrame"] = { area = "left", pushable = 1 }
	end

	-- Close FriendsFrame will close if you try to open a mail with mailframe+friendsframe open
	if ( UIPanelWindows["FriendsFrame"] ) then
		UIPanelWindows["FriendsFrame"].pushable = 2
	else
		UIPanelWindows["FriendsFrame"] = { area = "left", pushable = 2 }
	end

	MailItem1:SetPoint("TOPLEFT", "InboxFrame", "TOPLEFT", 48, -80)
	for i = 1, 7, 1 do
		getglobal("MailItem" .. i .. "ExpireTime"):SetPoint("TOPRIGHT", "MailItem" .. i, "TOPRIGHT", 10, -4)
		getglobal("MailItem" .. i):SetWidth(280)
	end

	GMAIL_NUMITEMBUTTONS = 21
	GMail_BagLinks = { }
	GMail_ScheduledStack = { }
	GMail_SelectedItems = { }
	GMail_DELETEDELAY = 1
	GMail_DELETEEVENTDELAY = 1

	GMailFrame.num = 0
	PanelTemplates_SetNumTabs(MailFrame, 3)

	GMailForwardFrame.pickItem = { }
	GMailForwardFrame.process = 0

	GMailGlobalFrame.queue = { }
	GMailGlobalFrame.update = 0
	GMailGlobalFrame.total = 0
	GMailGlobalFrame.sendmail = 0
	GMailGlobalFrame.latency = 2.25

	GMailTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")

	GMailInboxFrame.eventFunc = { }
end

function GMail:OnEnable()
	self:RegisterEvent("MAIL_INBOX_UPDATE")
	self:RegisterEvent("MAIL_SEND_SUCCESS")
	self:RegisterEvent("MAIL_SEND_INFO_UPDATE")
	self:RegisterEvent("MAIL_CLOSED")
	self:RegisterEvent("MAIL_SHOW")
	self:SecureHook("ContainerFrameItemButton_OnModifiedClick")
	self:SecureHook("PickupContainerItem")
	self:Hook("ContainerFrame_Update", true)
	self:Hook("ClickSendMailItemButton", true)
	self:HookScript(TradeFrame, "OnShow", "TF_Show")
	self:Hook("InboxFrameItem_OnEnter", true)
	self:Hook("MailFrameTab_OnClick", true)
	self:Hook("InboxFrame_OnClick", true)
	self:Hook("InboxFrame_Update", true)
	self:Hook("CloseMail", true)
	self:Hook("TakeInboxItem", true)
	self:Hook("OpenMail_Reply", true)
	oldTakeInboxMoney = OpenMailMoneyButton:GetScript("OnClick")
end

function GMail:MAIL_SHOW()
	if (not self:IsEventRegistered("BAG_UPDATE")) then self:RegisterEvent("BAG_UPDATE") end
	if (not self:IsEventRegistered("UI_ERROR_MESSAGE")) then self:RegisterEvent("UI_ERROR_MESSAGE") end
	GMailForwardFrame:Show()
end

function GMail:MAIL_CLOSED()
	if (self:IsEventRegistered("BAG_UPDATE")) then self:UnregisterEvent("BAG_UPDATE") end
	if (self:IsEventRegistered("UI_ERROR_MESSAGE")) then self:UnregisterEvent("UI_ERROR_MESSAGE") end
	GMail:ClearItems()
	GMailGlobalFrame.total = 0
	GMailGlobalFrame.queue = { }
	self:ScheduleEvent(function() GMailForwardFrame:Hide() end, 10)
end

function GMail:MAIL_SEND_SUCCESS()
	GMAIL_CANSENDNEXT = 1
end

function GMail:ContainerFrameItemButton_OnModifiedClick(...)
	if ( (...) == "LeftButton" ) then
		local bag, item = this:GetParent():GetID(), this:GetID()
		if ( IsAltKeyDown() ) then
			if ( GMailFrame:IsVisible() and not CursorHasItem() ) then
				if ( ( self:GetItemFrame(bag, item) or ( GMail_addItem and GMail_addItem[1] == bag and GMail_addItem[2] == item ) ) and not special ) then
					return
				end
				local i
				for i = 1, GMAIL_NUMITEMBUTTONS, 1 do
					if ( not getglobal("GMailButton" .. i).item ) then
						if ( self:ItemIsMailable(bag, item) ) then
							GMail:Print(L["GMail: cannot attach item."], 1, 0.5, 0)
							return
						end
						PickupContainerItem(bag, item)
						self:MailButton_OnClick(getglobal("GMailButton" .. i))
						self:UpdateItemButtons()
						return
					end
				end
			elseif ( SendMailFrame:IsVisible() and not CursorHasItem() ) then
				PickupContainerItem(bag, item)
				ClickSendMailItemButton()
				return
			elseif ( TradeFrame:IsVisible() and not CursorHasItem() ) then
				for i = 1, 6, 1 do
					if ( not GetTradePlayerItemLink(i) ) then
						PickupContainerItem(bag, item)
						ClickTradeButton(i)
						return
					end
				end
			elseif ( not CursorHasItem() and ( not TradeFrame or not TradeFrame:IsVisible() ) and ( not AuctionFrame or not AuctionFrame:IsVisible() ) and UnitExists("target") and CheckInteractDistance("target", 2) and UnitIsFriend("player", "target") and UnitIsPlayer("target") ) then
				InitiateTrade("target")
				GMail_addItem = { bag, item, UnitName("target"), 2 }
				for i = 1, NUM_CONTAINER_FRAMES, 1 do
					if ( getglobal("ContainerFrame" .. i):IsVisible() ) then
						ContainerFrame_Update(getglobal("ContainerFrame" .. i))
					end
				end
				return
			end
		end
	end
end

function GMail:PickupContainerItem(bag, item, special)
	if ( CursorHasItem() ) then
		GMailFrame.bag = bag
		GMailFrame.item = item
	else
		GMailFrame.bag = nil
		GMailFrame.item = nil
	end
	self:UpdateItemButtons()
end

function GMail:MailFrameTab_OnClick(tab)
	if ( not tab ) then
		tab = this:GetID()
	end
	if ( tab == 3 ) then
		PanelTemplates_SetTab(MailFrame, 3)
		InboxFrame:Hide()
		SendMailFrame:Hide()
		GMailFrame:Show()
		SendMailFrame.sendMode = "massmail"
		MailFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft")
		MailFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight")
		MailFrameBotLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotLeft")
		MailFrameBotRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotRight")
		MailFrameTopLeft:SetPoint("TOPLEFT", "MailFrame", "TOPLEFT", 2, -1)
		return
	else
		GMailFrame:Hide()
	end
	self.hooks["MailFrameTab_OnClick"](tab)
	self:Forward_EnableForward()
end

function GMail:ClickSendMailItemButton()
	if ( not GetSendMailItem() ) then
		GMailFrame.mailbag = GMailFrame.bag
		GMailFrame.mailitem = GMailFrame.item
	end
	self.hooks["ClickSendMailItemButton"]()
end

function GMail:MailButton_OnClick(button)
	if ( not button ) then button = this end
	if ( CursorHasItem() ) then
		local bag = GMailFrame.bag
		local item = GMailFrame.item
		if ( not bag or not item ) then return end
		if ( self:ItemIsMailable(bag, item) ) then
			GMail:Print(L["GMail: cannot attach item."], 1, 0.5, 0)
			return
		end
		PickupContainerItem(bag, item)
		if ( this.bag and this.item ) then
			PickupContainerItem(button.bag, button.item)
			GMailFrame.bag = button.bag
			GMailFrame.item = button.item
		else
			GMailFrame.bag = nil
			GMailFrame.item = nil
		end
		local texture, count = GetContainerItemInfo(bag, item)
		getglobal(button:GetName() .. "IconTexture"):Show()
		getglobal(button:GetName() .. "IconTexture"):SetTexture(texture)
		if ( count > 1 ) then
			getglobal(button:GetName() .. "Count"):SetText(count)
			getglobal(button:GetName() .. "Count"):Show()
		else
			getglobal(button:GetName() .. "Count"):Hide()
		end
		button.bag = bag
		button.item = item
		button.texture = texture
		button.count = count
	elseif ( button.item and button.bag ) then
		PickupContainerItem(button.bag, button.item)
		getglobal(button:GetName() .. "IconTexture"):Hide()
		getglobal(button:GetName() .. "Count"):Hide()
		GMailFrame.bag = button.bag
		GMailFrame.item = button.item
		button.item = nil
		button.bag = nil
		button.count = nil
		button.texture = nil
	end
	local num = self:GetNumMails()
	GMailFrame.num = num
	self:CanSend(GMailNameEditBox)
	if ( num == 0 ) then num = 1 end
	MoneyFrame_Update("GMailCostMoneyFrame", GetSendMailPrice()*num)
	for i = 1, NUM_CONTAINER_FRAMES, 1 do
		if ( getglobal("ContainerFrame" .. i):IsVisible() ) then
			ContainerFrame_Update(getglobal("ContainerFrame" .. i))
		end
	end
end

function GMail:ItemIsMailable(bag, item)
	local i, obj = 1
	while ( true ) do
		obj = getglobal("GMailTooltipTextLeft" .. i)
		if ( not obj ) then
			break
		end
		obj:SetText("")
		i = i + 1
	end
	GMailTooltip:SetBagItem(bag, item)
	for i = 1, GMailTooltip:NumLines(), 1 do
		local text = getglobal("GMailTooltipTextLeft" .. i):GetText()
		if ( text == ITEM_SOULBOUND or text == ITEM_BIND_QUEST or text == ITEM_CONJURED or text == ITEM_BIND_ON_PICKUP ) then
			return 1
		end
	end
	return nil
end


function GMail:UpdateItemButtons(frame)
	local i
	for i = 1, GMAIL_NUMITEMBUTTONS, 1 do
		local btn = getglobal("GMailButton" .. i)
		if ( not frame or btn ~= frame ) then
			local texture, count
			if ( btn.item and btn.bag ) then
				texture, count = GetContainerItemInfo(btn.bag, btn.item)
			end
			if ( not texture ) then
				getglobal(btn:GetName() .. "IconTexture"):Hide()
				getglobal(btn:GetName() .. "Count"):Hide()
				btn.item = nil
				btn.bag = nil
				btn.count = nil
				btn.texture = nil
			else
				btn.count = count
				btn.texture = texture
				getglobal(btn:GetName() .. "IconTexture"):Show()
				getglobal(btn:GetName() .. "IconTexture"):SetTexture(texture)
				if ( count > 1 ) then
					getglobal(btn:GetName() .. "Count"):Show()
					getglobal(btn:GetName() .. "Count"):SetText(count)
				else
					getglobal(btn:GetName() .. "Count"):Hide()
				end
			end
		end
	end
end

function GMail:GetItemFrame(bag, item)
	local i
	for i = 1, GMAIL_NUMITEMBUTTONS, 1 do
		local btn = getglobal("GMailButton" .. i)
		if ( btn.item == item and btn.bag == bag ) then
			return btn
		end
	end
	return nil
end

function GMail:GetNumMails()
	local i
	local num = 0
	for i = 1, GMAIL_NUMITEMBUTTONS, 1 do
		local btn = getglobal("GMailButton" .. i)
		if ( btn.item and btn.bag ) then
			num = num + 1
		end
	end
	return num
end

function GMail:ClearItems()
	local i
	local num = 0
	for i = 1, GMAIL_NUMITEMBUTTONS, 1 do
		local btn = getglobal("GMailButton" .. i)
		btn.item = nil
		btn.count = nil
		btn.bag = nil
		btn.texture = nil
	end
	self:UpdateItemButtons()
	GMailMailButton:Disable()
	GMailNameEditBox:HighlightText(0,-1)
	GMailSubjectEditBox:SetText("")
	GMailStatusText:SetText("")
	GMailAbortButton:Hide()
	GMailAcceptSendFrame:Hide()
end

function GMail:CanSend(eb)
	if ( not eb ) then eb = this end
	if ( strlen(eb:GetText()) > 0 and GMailFrame.num > 0 and GetSendMailPrice()*GMailFrame.num <= GetMoney() ) then
		GMailMailButton:Enable()
	else
		GMailMailButton:Disable()
	end
end

function GMail:SendMail()
	for key, val in pairs(this.queue) do
		GMailStatusText:SetText(format(GMAIL_SENDING, key, this.total))
		GMailAbortButton:Show()
		if ( GetSendMailItem() and GMailFrame.mailbag and GMailFrame.mailitem ) then
			ClickSendMailItemButton()
			PickupContainerItem(GMailFrame.mailbag, GMailFrame.mailitem)
			GMailFrame.mailbag = nil
			GMailFrame.mailitem = nil
		elseif ( CursorHasItem() and GMailFrame.bag and GMailFrame.item ) then
			PickupContainerItem(GMailFrame.bag, GMailFrame.item)
			GMailFrame.bag = nil
			GMailFrame.item = nil
		end
		PickupContainerItem(val.bag, val.item)
		ClickSendMailItemButton()
		local name, useless, count = GetSendMailItem()
		if ( not name ) then
			GMail:Print(GMAIL_ERROR, 1, 0, 0)
		else
			local subjectstr = GMailSubjectEditBox:GetText()
			if ( strlen(subjectstr) > 0 ) then
				subjectstr = subjectstr .. " "
			end
			if ( count > 1 ) then
				subjectstr = subjectstr .. "[" .. name .. " x" .. count .. "]"
			else
				subjectstr = subjectstr .. "[" .. name .. "]"
			end
			SendMail(val.to, subjectstr, format(GMAIL_ITEMNUM, key, this.total))
		end
		GMailGlobalFrame.queue[key] = nil
		return
	end
	GMailStatusText:SetText(format(GMAIL_DONESENDING, this.total))
	GMailAbortButton:Hide()
	GMailGlobalFrame:Hide()
	GMailGlobalFrame.total = 0
	GMailGlobalFrame.queue = { }
end

function GMail:FillItemTable()
	local arr = { }
	for i = 1, GMAIL_NUMITEMBUTTONS, 1 do
		local btn = getglobal("GMailButton" .. i)
		if ( btn.item and btn.bag ) then
			tinsert(arr, { ["item"] = btn.item, ["bag"] = btn.bag, ["to"] = GMailNameEditBox:GetText() })
		end
	end
	return arr
end

function GMail:ProcessQueue(elapsed)
	if ( not GMAIL_CANSENDNEXT ) then
		return
	end
	this.sendmail = this.sendmail + elapsed
	if ( this.sendmail > 0.5 ) then
		this.sendmail = 0
		if ( this.total > 0 ) then
			self:SendMail()
			GMAIL_CANSENDNEXT = nil
		end
	end
end

function GMail:ContainerFrame_Update(frame)
	self.hooks["ContainerFrame_Update"](frame)
	local id = frame:GetID()
	if ( GMailFrame:IsVisible() ) then
		local i
		for i = 1, GMAIL_NUMITEMBUTTONS, 1 do
			local btn = getglobal("GMailButton" .. i)
			if ( btn.item and btn.bag ) then
				if ( btn.bag == frame:GetID() ) then
					SetItemButtonDesaturated(getglobal(frame:GetName() .. "Item" .. (frame.size-btn.item)+1), 1, 0.5, 0.5, 0.5)
				end
			end
		end
	end
	if ( GMail_addItem and GMail_addItem[1] == frame:GetID() ) then
		SetItemButtonDesaturated(getglobal(frame:GetName() .. "Item" .. (frame.size-GMail_addItem[2])+1), 1, 0.5, 0.5, 0.5)
	end
end

function GMail:MAIL_SEND_INFO_UPDATE()
	if ( not SendMailFrame:IsVisible() ) then return end
	local name, useless, count = GetSendMailItem()
	if ( name and strlen(SendMailSubjectEditBox:GetText()) == 0 ) then
		if ( count > 1 ) then
			name = name .. " x" .. count
		end
		SendMailSubjectEditBox:SetText(name)
	end
end

function GMail:InboxFrameItem_OnEnter()
	local didSetTooltip
	if ( this.index ) then
		if ( GetInboxItem(this.index) ) then
			GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
			GameTooltip:SetInboxItem(this.index)
			didSetTooltip = 1
		end
	end
	if ( not didSetTooltip ) then
		GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
	end
	if (this.money) then
		GameTooltip:AddLine(ENCLOSED_MONEY, "", 1, 1, 1)
		SetTooltipMoney(GameTooltip, this.money)
		SetMoneyFrameColor("GameTooltipMoneyFrame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
	elseif (this.cod) then
		GameTooltip:AddLine(COD_AMOUNT, "", 1, 1, 1)
		SetTooltipMoney(GameTooltip, this.cod)
		if ( this.cod > GetMoney() ) then
			SetMoneyFrameColor("GameTooltipMoneyFrame", RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b)
		else
			SetMoneyFrameColor("GameTooltipMoneyFrame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
		end
	end
	if ( didSetTooltip and ( this.money or this.cod ) ) then
		GameTooltip:SetHeight(GameTooltip:GetHeight()+getglobal("GameTooltipTextLeft" .. GameTooltip:NumLines()):GetHeight())
		if ( GameTooltipMoneyFrame:IsVisible() ) then
			GameTooltip:SetHeight(GameTooltip:GetHeight()+GameTooltipMoneyFrame:GetHeight())
		end
	end
	GameTooltip:Show()
end

function GMail:TF_Show()
	self.hooks[TradeFrame].OnShow()
	if ( GMail_addItem and not CursorHasItem() and UnitName("NPC") == GMail_addItem[3] ) then
		PickupContainerItem(GMail_addItem[1], GMail_addItem[2])
		ClickTradeButton(1)
	end
	GMail_addItem = nil
end

function GMail:Inbox_OnUpdate(elapsed)
	if ( GMail_addItem ) then
		GMail_addItem[4] = GMail_addItem[4] - elapsed
		if ( GMail_addItem[4] <= 0 ) then
			GMail_addItem = nil
			for i = 1, NUM_CONTAINER_FRAMES, 1 do
				if ( getglobal("ContainerFrame" .. i):IsVisible() ) then
					ContainerFrame_Update(getglobal("ContainerFrame" .. i))
				end
			end
		end
	end
	if ( not this.returnSelected and this.num and this.elapsed ) then
		this.elapsed = this.elapsed - elapsed
		if ( this.elapsed <= 0 ) then
			this.elapsed = nil
			if ( this.id[1] ) then
				local val = this.id[1]
				local success = GMail:PickMail(val, this.openSelected)
				if ( success ~= 2 ) then
					tremove(this.id, 1)
					this.num = this.num - 1
				end
				if ( success == 1 ) then
					for key, va in pairs(this.id) do
						if ( va > val ) then
							this.id[key] = va-1
						end
					end
					this.lastVal = val
					InboxFrame_Update()
				else
					this.elapsed = 1+GMail_DELETEDELAY
					this.lastVal = nil
				end
				if ( this.num == 0 ) then
					this.num = nil
					GMail:Inbox_DisableClicks(nil)
				end
			end
		end
	end
	if ( this.returnSelected and this.num and this.elapsed ) then
		this.elapsed = this.elapsed - elapsed
		if ( this.elapsed <= 0 ) then
			this.elapsed = nil
			if ( this.id[1] ) then
				local val = this.id[1]
				local success = GMail_Inbox_ReturnMail(val, this.returnSelected)
				if ( success ~= 2 ) then
					tremove(this.id, 1)
					this.num = this.num - 1
				end
				if ( success == 1 ) then
					for key, va in pairs(this.id) do
						if ( va > val ) then
							this.id[key] = va-1
						end
					end
					this.lastVal = val
					InboxFrame_Update()
				else
					this.elapsed = 1+GMail_DELETEDELAY
					this.lastVal = nil
				end
				if ( this.num == 0 ) then
					this.num = nil
					GMail:Inbox_DisableClicks(nil)
					this.returnSelected = nil
				end
			end
		end
	end
	if ( this.delete ) then
		this.delete[1] = this.delete[1] - elapsed
		if ( this.delete[1] <= 0 ) then
			local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemID, wasRead, wasReturned, textCreated  = GetInboxHeaderInfo(this.delete[2])
			if ( money == 0 and not itemID ) then
				GetInboxText(this.delete[2])
				DeleteInboxItem(this.delete[2])
			end
			this.delete = nil
			this.elapsed = 0.5+GMail_DELETEDELAY
		end
	end
end

function GMail:MAIL_INBOX_UPDATE()
	if ( GMailInboxFrame.eventDelete ) then
		GMailInboxFrame.delete = { GMail_DELETEEVENTDELAY, GMailInboxFrame.eventDelete }
		GMailInboxFrame.eventDelete = nil
	end
end

function GMail:UI_ERROR_MESSAGE()
	if ( event == "UI_ERROR_MESSAGE" and ( arg1 == ERR_INV_FULL or arg1 == ERR_ITEM_MAX_COUNT ) ) then
		if ( this.num ) then
			if ( arg1 == ERR_INV_FULL ) then
				GMail:Inbox_Abort()
				GMail:Print(L["GMail: Inventory full, aborting."], 1, 0, 0)
			elseif ( arg1 == ERR_ITEM_MAX_COUNT ) then
				GMail:Print(L["GMail: You already have the maximum amount of that item, skipping..."], 1, 0, 0)
				this.elapsed = GMail_DELETEDELAY
				if ( this.lastVal ) then
					for key, va in pairs(this.id) do
						if ( va >= this.lastVal ) then
							this.id[key] = va+1
						end
					end
				end
			end
		end
	end
end

function GMail:PickMail(id, openSelected)
	if ( not id ) then
		return 0
	end
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead, wasReturned, textCreated, canReply = GetInboxHeaderInfo(id)
	if ( CODAmount > 0 ) then
		GMail:Print(format(GMAIL_OPEN_FORMAT1, this.numMails-(this.num-1), this.numMails), 1, 0, 0)
		return 0
	elseif ( not hasItem and money == 0 and not openSelected ) then
		GMail:Print(format(GMAIL_OPEN_FORMAT2, this.numMails-(this.num-1), this.numMails), 1, 1, 0)
		return 0
	end
	GMail:Print(format(GMAIL_OPEN_FORMAT3, this.numMails-(this.num-1), this.numMails, (subject or GMAIL_NOSUBJECT), (sender or GMAIL_UNKNOWNSENDER)), 1, 1, 0)
	local eventDelete
	if ( hasItem ) then
		TakeInboxItem(id)
		eventDelete = 1
		if ( money > 0 ) then
			return 2
		end
	end
	if ( money > 0 ) then
		TakeInboxMoney(id)
		eventDelete = 1
	end
	if ( eventDelete ) then
		GMailInboxFrame.eventDelete = id
	else
		GMailInboxFrame.delete = { GMail_DELETEDELAY, id }
	end
	return 1
end

function GMail_Inbox_SetSelected()
	local id = this:GetID() + (InboxFrame.pageNum-1)*7
	if ( not this:GetChecked() ) then
		for k, v in pairs(GMail_SelectedItems) do
			if ( v == id ) then
				tremove(GMail_SelectedItems, k)
				break
			end
		end
	else
		tinsert(GMail_SelectedItems, id)
	end
end

function GMail_Inbox_OpenSelected(openAll)
	GMail:Inbox_DisableClicks(1)
	GMailInboxFrame.num = 0
	GMailInboxFrame.elapsed = GMail_DELETEDELAY
	GMailInboxFrame.id = { }
	GMailInboxFrame.openSelected = not openAll
	if ( openAll ) then
		for i = 1, GetInboxNumItems(), 1 do
			GMailInboxFrame.num = GMailInboxFrame.num + 1
			tinsert(GMailInboxFrame.id, i)
		end
	else
		for k, v in pairs(GMail_SelectedItems) do
			GMailInboxFrame.num = GMailInboxFrame.num + 1
			tinsert(GMailInboxFrame.id, v)
		end
	end
	GMailInboxFrame.numMails = GMailInboxFrame.num
	GMail_SelectedItems = { }
end

function GMail_Inbox_ReturnMail(id, returnSelected)
	if ( not id ) then
		return 0
	end
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead, wasReturned, textCreated, canReply = GetInboxHeaderInfo(id)

	curmail = 
	GMail:Print(format(GMAIL_RETURN_FORMAT, this.numMails-(this.num-1), this.numMails, (subject or GMAIL_NOSUBJECT), (sender or GMAIL_UNKNOWNSENDER)), 1, 1, 0)

	local eventDelete

	ReturnInboxItem(id)

	if ( eventDelete ) then
		GMailInboxFrame.eventDelete = id
	else
		GMailInboxFrame.delete = { GMail_DELETEDELAY, id }
	end
	return 1
end

function GMail_Inbox_ReturnSelected()
	GMail:Inbox_DisableClicks(1)
	GMailInboxFrame.num = 0
	GMailInboxFrame.elapsed = GMail_DELETEDELAY
	GMailInboxFrame.id = { }
	GMailInboxFrame.returnSelected = 1
	for k, v in pairs(GMail_SelectedItems) do
		GMailInboxFrame.num = GMailInboxFrame.num + 1
		tinsert(GMailInboxFrame.id, v)
	end
	GMailInboxFrame.numMails = GMailInboxFrame.num
	GMail_SelectedItems = { }
end

function GMail:InboxFrame_Update()
	self.hooks["InboxFrame_Update"]()
	for i = 1, 7, 1 do
		local index = (i + (InboxFrame.pageNum-1)*7)
		if ( index > GetInboxNumItems() ) then
			getglobal("GMailBoxItem" .. i .. "CB"):Hide()
		else
			getglobal("GMailBoxItem" .. i .. "CB"):Show()
			getglobal("GMailBoxItem" .. i .. "CB"):SetChecked(nil)
			for k, v in pairs(GMail_SelectedItems) do
				if ( v == index ) then
					getglobal("GMailBoxItem" .. i .. "CB"):SetChecked(1)
					break
				end
			end
		end
	end
	if ( GMailInboxFrame.num ) then
		GMail:Inbox_DisableClicks(1, 1)
	end
end

function GMail:Inbox_DisableClicks(disable, loopPrevention)
	if ( disable ) then
		for i = 1, 7, 1 do
			getglobal("MailItem" .. i .. "ButtonIcon"):SetDesaturated(1)
		end
		if not self:IsHooked("InboxFrame_OnClick") then self:Hook("InboxFrame_OnClick", "DummyFunction", true) end
	else
		for i = 1, 7, 1 do
			getglobal("MailItem" .. i .. "ButtonIcon"):SetDesaturated(nil)
		end
		if ( not loopPrevention ) then
			InboxFrame_Update()
		end
		if self:IsHooked("InboxFrame_OnClick") then self:Unhook("InboxFrame_OnClick") end
	end
end

function GMail:InboxFrame_OnClick()
	this:SetChecked(nil)
end

function GMail:Inbox_Abort()
	GMailInboxFrame.num = nil
	GMailInboxFrame.elapsed = nil
	GMailInboxFrame.id = { }
	GMail_SelectedItems = { }
	GMail:Inbox_DisableClicks()
	HideUIPanel(GMailInboxOpenAll)
end

function GMail:CloseMail()
	self.hooks["CloseMail"]()
	GMail:Inbox_Abort()
end

function GMail:TakeInboxItem(id)
	local name = GetInboxItem(id)
	if name then
		tinsert(GMailForwardFrame.pickItem, name)
	end
	self.hooks["TakeInboxItem"](id)
end

function GMail:DisableAttachments(disable)
	if ( disable ) then
		OpenMailMoneyButtonIconTexture:SetDesaturated(1)
		OpenMailPackageButtonIconTexture:SetDesaturated(1)
		if not self:IsHooked(OpenMailMoneyButton, "OnClick") then self:HookScript(OpenMailMoneyButton, "OnClick", "DummyFunction") end
		if not self:IsHooked(OpenMailPackageButton, "OnClick") then self:HookScript(OpenMailPackageButton, "OnClick", "DummyFunction") end
	else
		OpenMailMoneyButtonIconTexture:SetDesaturated(nil)
		OpenMailPackageButtonIconTexture:SetDesaturated(nil)
		if self:IsHooked(OpenMailMoneyButton, "OnClick") then self:Unhook(OpenMailMoneyButton, "OnClick") end
		if self:IsHooked(OpenMailPackageButton, "OnClick") then self:Unhook(OpenMailPackageButton, "OnClick") end
	end
end

function GMail:DummyFunction()
end

function GMail:OpenMail_Reply()
	self.hooks["OpenMail_Reply"]()
	SendMailMoneyCopper:SetText("")
	SendMailMoneySilver:SetText("")
	SendMailMoneyGold:SetText("")
end


function GMail:OpenReply()
	OpenMail_Reply()
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead, wasReturned, textCreated, canReply = GetInboxHeaderInfo(InboxFrame.openMailID)
	local gold, silver, copper = "", "", ""
	if ( money and money > 0 ) then
		gold = floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD))
		silver = floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER)
		copper = mod(money, COPPER_PER_SILVER)
	end
	SendMailMoneyCopper:SetText(copper)
	SendMailMoneySilver:SetText(silver)
	SendMailMoneyGold:SetText(gold)
	local name, itemTexture, count, quality, canUse = GetInboxItem(InboxFrame.openMailID)
	SendMailPackageButton:SetNormalTexture(itemTexture)
	if ( count > 1 ) then
		SendMailPackageButtonCount:SetText(count)
	else
		SendMailPackageButtonCount:SetText("")
	end
	SendMailNameEditBox:SetText("")
	local subject = OpenMailSubject:GetText()
	local prefix = "FW:".." "
	if ( strsub(subject, 1, strlen(prefix)) ~= prefix ) then
		subject = prefix..subject
	end
	SendMailSubjectEditBox:SetText(subject or "")
	SendMailBodyEditBox:SetText(string.gsub(OpenMailBodyText:GetText() or "", "\n", "\n>"))
	SendMailNameEditBox:SetFocus()
	SendMailFrame.sendMode = "reply"
	self:Forward_EnableForward(1)
end

function GMail:SendMailMailButton_OnClick()
	local name, itemTexture, count, quality, canUse = GetInboxItem(InboxFrame.openMailID)
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead, wasReturned, textCreated, canReply = GetInboxHeaderInfo(InboxFrame.openMailID)
	if ( name ) then
		GMailForwardFrame.searchItem = name
		GMailForwardFrame.forwardStep = 1
		self.hooks["TakeInboxItem"](InboxFrame.openMailID)
	else
		GMailForwardFrame.forwardStep = 2
		if ( money and money > 0 ) then
			SetSendMailMoney(money)
			GMailForwardFrame.countDown = 2
			oldTakeInboxMoney(InboxFrame.openMailID)
		else
			GMailForwardFrame.countDown = 0.5
		end
	end
	SendMailMailButton:Disable()
end

function GMail:Forward_OnUpdate(elapsed)
	if ( this.forwardStep and this.forwardStep > 1 ) then
		if ( this.countDown ) then
			this.countDown = this.countDown - elapsed
			if ( this.countDown <= 0 ) then
				if ( this.forwardStep == 2 ) then
					this.countDown = 0.5
					this.forwardStep = 3
					SendMail(SendMailNameEditBox:GetText(), SendMailSubjectEditBox:GetText(), SendMailBodyEditBox:GetText())
					SendMailMailButton:Disable()
				elseif ( this.forwardStep == 3 ) then
					local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemID, wasRead, wasReturned, textCreated  = GetInboxHeaderInfo(InboxFrame.openMailID)
					if ( money == 0 and not itemID ) then
						DeleteInboxItem(InboxFrame.openMailID)
					end
					self:MailFrameTab_OnClick(1)
					HideUIPanel(OpenMailFrame)
					this.countDown = nil
					this.forwardStep = nil
				end
			end
		end
	end
	this.process = this.process - elapsed
	if ( this.process <= 0 ) then
		this.process = 3
		if ( getn(GMail_ScheduledStack) > 0 ) then
			self:ProcessStack()
		end
	end
end

function GMail:InboxFrame_OnClick(id)
	self.hooks["InboxFrame_OnClick"](id)
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemID, wasRead, wasReturned, textCreated  = GetInboxHeaderInfo(id)
	if ( CODAmount and CODAmount > 0 ) then
		OpenMailForwardButton:Disable()
	else
		OpenMailForwardButton:Enable()
	end
end

function GMail:Forward_EnableForward(enable)
	if ( enable ) then
		OpenMailForwardButton:Disable()
		if not self:IsHooked(SendMailPackageButton, "OnEnter") then self:HookScript(SendMailPackageButton, "OnEnter", "SMPBOE") end
		SendMailCODButton:Disable()
		self:DisableAttachments(1)
		if not self:IsHooked("SendMailMailButton_OnClick") then self:Hook("SendMailMailButton_OnClick", true) end
		if not self:IsHooked("SendMailPackageButton_OnClick") then self:Hook("SendMailPackageButton_OnClick", true) end
	else
		OpenMailForwardButton:Enable()
		if self:IsHooked(SendMailPackageButton, "OnEnter") then self:Unhook(SendMailPackageButton, "OnEnter") end
		SendMailCODButton:Enable()
		self:DisableAttachments(nil)
		if self:IsHooked("SendMailMailButton_OnClick") then self:Unhook("SendMailMailButton_OnClick") end
		if self:IsHooked("SendMailPackageButton_OnClick") then self:Unhook("SendMailPackageButton_OnClick") end
	end
end

function GMail:SMPBOE()
	GameTooltip:SetOwner(SendMailPackageButton, "ANCHOR_RIGHT")
	GameTooltip:SetInboxItem(InboxFrame.openMailID)
end
function GMail:SendMailPackageButton_OnClick()
end

function GMail:Forward_AttachSlot(container, item)
	PickupContainerItem(container, item)
	ClickSendMailItemButton()
	GMailForwardFrame.searchItem = nil
	GMailForwardFrame.forwardStep = 2
	GMailForwardFrame.countDown = 1.5
end

function GMail:BAG_UPDATE()
	local old = { }
	for k, v in pairs(GMail_BagLinks) do
		if ( type(v) == "table" ) then
			old[k] = { }
			for key, val in pairs(v) do
				old[k][key] = val
			end
		end
	end
	GMail_BagLinks = { }
	for i = 0, 4, 1 do
		GMail_BagLinks[i] = { }
		for y = 1, GetContainerNumSlots(i), 1 do
			local curr = GetContainerItemLink(i, y)
			local _, _, name = string.find(( curr or "" ), "%[(.+)%]")
			if ( name ) then
				if ( GMailForwardFrame.searchItem ) then
					if ( name and name == GMailForwardFrame.searchItem and (not old[i] or not old[i][y])) then
						self:Forward_AttachSlot(i, y)
					end
				else
					local _, _, name = string.find(( curr or "" ), "%[(.+)%]")
					if ( name and name == GMailForwardFrame.pickItem[1] and (not old[i] or not old[i][y])) then
						tremove(GMailForwardFrame.pickItem, 1)
						for k, v in pairs(old) do
							local hasFound
							for key, val in pairs(v) do
								if ( val == name and ( k ~= i or key ~= y ) ) then
									local _,_, link = string.find((GetContainerItemLink(k, key) or ""), "(item:[%d:]+)")
									if ( link ) then
										local texture, itemCount = GetContainerItemInfo(k,key)
										local tex, iC = GetContainerItemInfo(i, y)
										local sName, sLink, iQuality, iLevel, _, sType, sSubType, iCount = GetItemInfo(link)
										if ( sName and itemCount and iCount and iC ) then
											if ( iCount >= (itemCount+iC) ) then
												if ( getn(GMail_ScheduledStack) == 0 ) then
													GMailForwardFrame.process = 2
												end
												tinsert(GMail_ScheduledStack, { i, y, k, key })
												hasFound = 1
												break
											end
										end
									end
								end
							end
							if ( hasFound ) then
								break
							end
						end
					end
				end
				GMail_BagLinks[i][y] = name
			end
		end
	end
end


function GMail:ProcessStack()
	local val = tremove(GMail_ScheduledStack, 1)
	PickupContainerItem(val[1], val[2])
	PickupContainerItem(val[3], val[4])
end

local oldSMMFfunc = SendMailMoneyFrame.onvalueChangedFunc
SendMailMoneyFrame.onvalueChangedFunc = function()
	if ( oldSMMFfunc ) then
		oldSMMFfunc()
	end
	local subject = SendMailSubjectEditBox:GetText()
	if ( subject == "" or string.find(subject, "%[%d+G, %d+S, %d+C%]") ) then
		local copper, silver, gold = SendMailMoneyFrameCopper:GetText(), SendMailMoneyFrameSilver:GetText(), SendMailMoneyFrameGold:GetText()
		if ( not tonumber(copper) ) then
			copper = 0
		end
		if ( not tonumber(silver) ) then
			silver = 0
		end
		if ( not tonumber(gold) ) then
			gold = 0
		end
		SendMailSubjectEditBox:SetText(format("[%sG, %sS, %sC]", gold, silver, copper))
	end
end

function GMail:Print(msg, r, g, b)
	DEFAULT_CHAT_FRAME:AddMessage(msg, r, g, b)
end

