INBOXITEMS_TO_DISPLAY = 7;
PACKAGEITEMS_TO_DISPLAY = 4;
ATTACHMENTS_MAX = 16;
ATTACHMENTS_MAX_SEND = 12;
ATTACHMENTS_PER_ROW_SEND = 7;
ATTACHMENTS_MAX_ROWS_SEND = 2;
ATTACHMENTS_MAX_RECEIVE = 16;
ATTACHMENTS_PER_ROW_RECEIVE = 7;
ATTACHMENTS_MAX_ROWS_RECEIVE = 3;
MAX_COD_AMOUNT = 10000;
SEND_MAIL_TAB_LIST = {};
SEND_MAIL_TAB_LIST[1] = "SendMailNameEditBox";
SEND_MAIL_TAB_LIST[2] = "SendMailSubjectEditBox";
SEND_MAIL_TAB_LIST[3] = "SendMailBodyEditBox";
SEND_MAIL_TAB_LIST[4] = "SendMailMoneyGold";
SEND_MAIL_TAB_LIST[5] = "SendMailMoneyCopper";

local MAX_INBOX_SIZE = 100;

function MailFrame_OnLoad(self)
	self:SetPortraitToAsset("Interface\\MailFrame\\Mail-Icon");
	-- Init pagenum
	InboxFrame.pageNum = 1;
	-- Tab Handling code
	self.maxTabWidth = self:GetWidth() / 3;
	PanelTemplates_SetNumTabs(self, 2);
	PanelTemplates_SetTab(self, 1);
	-- Register for events
	self:RegisterEvent("MAIL_INBOX_UPDATE");
	self:RegisterEvent("MAIL_SEND_INFO_UPDATE");
	self:RegisterEvent("MAIL_SEND_SUCCESS");
	self:RegisterEvent("MAIL_FAILED");
	self:RegisterEvent("MAIL_SUCCESS");
	self:RegisterEvent("CLOSE_INBOX_ITEM");
	self:RegisterEvent("MAIL_LOCK_SEND_ITEMS");
	self:RegisterEvent("MAIL_UNLOCK_SEND_ITEMS");
	self:RegisterEvent("TRIAL_STATUS_UPDATE");
	-- Set previous and next fields
	MoneyInputFrame_SetPreviousFocus(SendMailMoney, SendMailBodyEditBox);
	MoneyInputFrame_SetNextFocus(SendMailMoney, SendMailNameEditBox);
	MoneyFrame_SetMaxDisplayWidth(SendMailMoneyFrame, 160);
	MailFrame_UpdateTrialState(self);
end

function MailFrame_UpdateTrialState(self)
	local isTrialOrVeteran = GameLimitedMode_IsActive();
	MailFrameTab2:SetShown(not isTrialOrVeteran);
	self.trialError:SetShown(isTrialOrVeteran);
end

function MailFrame_Show()
	ShowUIPanel(MailFrame);
	if ( not MailFrame:IsShown() ) then
		CloseMail();
		return;
	end

	-- Update the roster so auto-completion works
	if ( IsInGuild() and GetNumGuildMembers() == 0 ) then
		C_GuildInfo.GuildRoster();
	end

	OpenAllBags(MailFrame);
	SendMailFrame_Update();
	MailFrameTab_OnClick(nil, 1);
	MailFrame_RefreshInbox(MailFrame);
	C_ChatInfo.PerformEmote("READ", nil, true);
end

function MailFrame_Hide()
	C_ChatInfo.CancelEmote();
	HideUIPanel(MailFrame);
	CloseAllBags(self);
	SendMailFrameLockSendMail:Hide();
	StaticPopup_Hide("CONFIRM_MAIL_ITEM_UNREFUNDABLE");
end

function MailFrame_OnEvent(self, event, ...)
	if ( event == "MAIL_INBOX_UPDATE" ) then
		InboxFrame_Update();
		OpenMail_Update();
		self.inboxBeingChecked = false;
	elseif ( event == "MAIL_SEND_INFO_UPDATE" ) then
		SendMailFrame_Update();
	elseif ( event == "MAIL_SEND_SUCCESS" ) then
		SendMailFrame_Reset();
		PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN);
		-- If open mail frame is open then switch the mail frame back to the inbox
		if ( SendMailFrame.sendMode == "reply" ) then
			MailFrameTab_OnClick(nil, 1);
		end
	elseif ( event == "MAIL_FAILED" ) then
		SendMailMailButton:Enable();
	elseif ( event == "MAIL_SUCCESS" ) then
		SendMailMailButton:Enable();
		if ( InboxNextPageButton:IsEnabled() ) then
			InboxGetMoreMail();
		end
	elseif ( event == "CLOSE_INBOX_ITEM" ) then
		local mailID = ...;
		if ( mailID == InboxFrame.openMailID ) then
			HideUIPanel(OpenMailFrame);
		end
	elseif ( event == "MAIL_LOCK_SEND_ITEMS" ) then
		local slotNum, itemLinkEvent = ...;
		SendMailFrameLockSendMail:Show();
		local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture = C_Item.GetItemInfo(itemLinkEvent);
		local r, g, b = C_Item.GetItemQualityColor(itemRarity)
		StaticPopup_Show("CONFIRM_MAIL_ITEM_UNREFUNDABLE", nil, nil, {["texture"] = itemTexture, ["name"] = itemName, ["color"] = {r, g, b, 1}, ["link"] = itemLink, ["slot"] = slotNum});
	elseif ( event == "MAIL_UNLOCK_SEND_ITEMS") then
		SendMailFrameLockSendMail:Hide();
		StaticPopup_Hide("CONFIRM_MAIL_ITEM_UNREFUNDABLE");
	elseif ( event == "TRIAL_STATUS_UPDATE" ) then
		MailFrame_UpdateTrialState(self);
	end
end

function MailFrame_OnMouseWheel(self, value)
	if ( value > 0 ) then
		if ( InboxPrevPageButton:IsEnabled() ) then
			InboxPrevPage();
		end
	else
		if ( InboxNextPageButton:IsEnabled() ) then
			InboxNextPage();
		end
	end
end

function MailFrameTab_OnClick(self, tabID)
	if ( not tabID ) then
		tabID = self:GetID();
	end
	PanelTemplates_SetTab(MailFrame, tabID);
	if ( tabID == 1 ) then
		-- Inbox tab clicked
		ButtonFrameTemplate_HideButtonBar(MailFrame)
		MailFrameInset:SetPoint("TOPLEFT", 4, -58);
		InboxFrame:Show();
		SendMailFrame:Hide();
		SetSendMailShowing(false);
		MailFrame:SetTitle(INBOX);
	else
		-- Sendmail tab clicked
		ButtonFrameTemplate_ShowButtonBar(MailFrame)
		MailFrameInset:SetPoint("TOPLEFT", 4, -80);
		InboxFrame:Hide();
		SendMailFrame:Show();
		SendMailFrame_Update();
		SetSendMailShowing(true);
		MailFrame:SetTitle(SENDMAIL);

		-- Set the send mode to dictate the flow after a mail is sent
		SendMailFrame.sendMode = "send";
	end
	PlaySound(SOUNDKIT.IG_SPELLBOOK_OPEN);
end

-- Inbox functions

function MailFrame_RefreshInbox(self)
	if self.refreshQueued or self.inboxBeingChecked then
		return;
	end

	local canCheck, timeUntilAvailable = C_Mail.CanCheckInbox();
	if canCheck then
		CheckInbox();
		self.inboxBeingChecked = true;
	else
		self.refreshQueued = true;
		C_Timer.After(timeUntilAvailable, function()
			self.refreshQueued = false;
			MailFrame_RefreshInbox(self);
		end);
	end
end

function InboxFrame_Update()
	local numItems, totalItems = GetInboxNumItems();

	if numItems ~= totalItems and numItems < MAX_INBOX_SIZE then
		MailFrame_RefreshInbox(MailFrame)
	end

	local index = ((InboxFrame.pageNum - 1) * INBOXITEMS_TO_DISPLAY) + 1;
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, x, y, z, isGM, firstItemQuantity, firstItemLink;
	local icon, button, expireTime, senderText, subjectText, buttonIcon;

	if ( totalItems > numItems ) then
		if ( not InboxFrame.maxShownMails ) then
			InboxFrame.maxShownMails = numItems;
		end
		InboxFrame.overflowMails = totalItems - numItems;
		InboxFrame.shownMails = numItems;
	else
		InboxFrame.overflowMails = nil;
	end

	for i=1, INBOXITEMS_TO_DISPLAY do
		if ( index <= numItems ) then
			-- Setup mail item
			packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, x, y, z, isGM, firstItemQuantity, firstItemLink = GetInboxHeaderInfo(index);

			-- Set icon
			if ( packageIcon ) and ( not isGM ) then
				icon = packageIcon;
			else
				icon = stationeryIcon;
			end


			-- If no sender set it to "Unknown"
			if ( not sender ) then
				sender = UNKNOWN;
			end
			button = _G["MailItem"..i.."Button"];
			button:Show();
			button.index = index;
			button.hasItem = itemCount;
			button.itemCount = itemCount;
			SetItemButtonCount(button, firstItemQuantity);
			if ( firstItemQuantity ) then
				SetItemButtonQuality(button, select(3, C_Item.GetItemInfo(firstItemLink)), firstItemLink);
			else
				button.IconBorder:Hide();
				button.IconOverlay:Hide();
				if button.ProfessionQualityOverlay then
					button.ProfessionQualityOverlay:Hide();
				end
			end

			buttonIcon = _G["MailItem"..i.."ButtonIcon"];
			buttonIcon:SetTexture(icon);
			subjectText = _G["MailItem"..i.."Subject"];
			subjectText:SetText(subject);
			senderText = _G["MailItem"..i.."Sender"];
			senderText:SetText(sender);

			-- If hasn't been read color the button yellow
			if ( wasRead ) then
				senderText:SetTextColor(0.75, 0.75, 0.75);
				subjectText:SetTextColor(0.75, 0.75, 0.75);
				_G["MailItem"..i.."ButtonSlot"]:SetVertexColor(0.5, 0.5, 0.5);
				SetDesaturation(buttonIcon, true);
				button.IconBorder:SetVertexColor(0.5, 0.5, 0.5);
			else
				senderText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
				subjectText:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
				_G["MailItem"..i.."ButtonSlot"]:SetVertexColor(1.0, 0.82, 0);
				SetDesaturation(buttonIcon, false);
			end
			-- Format expiration time
			if ( daysLeft >= 1 ) then
				daysLeft = GREEN_FONT_COLOR_CODE..format(DAYS_ABBR, floor(daysLeft)).." "..FONT_COLOR_CODE_CLOSE;
			else
				daysLeft = RED_FONT_COLOR_CODE..SecondsToTime(floor(daysLeft * 24 * 60 * 60))..FONT_COLOR_CODE_CLOSE;
			end
			expireTime = _G["MailItem"..i.."ExpireTime"];
			expireTime:SetText(daysLeft);
			-- Set expiration time tooltip
			if ( InboxItemCanDelete(index) ) then
				expireTime.tooltip = TIME_UNTIL_DELETED;
			else
				expireTime.tooltip = TIME_UNTIL_RETURNED;
			end
			expireTime:Show();
			-- Is a C.O.D. package
			if ( CODAmount > 0 ) then
				_G["MailItem"..i.."ButtonCOD"]:Show();
				_G["MailItem"..i.."ButtonCODBackground"]:Show();
				button.cod = CODAmount;
			else
				_G["MailItem"..i.."ButtonCOD"]:Hide();
				_G["MailItem"..i.."ButtonCODBackground"]:Hide();
				button.cod = nil;
			end
			-- Contains money
			if ( money > 0 ) then
				button.money = money;
			else
				button.money = nil;
			end
			-- Set highlight
			if ( InboxFrame.openMailID == index ) then
				button:SetChecked(true);
				OpenMailFrame:SetPortraitToAsset(stationeryIcon);
			else
				button:SetChecked(false);
			end
		else
			-- Clear everything
			_G["MailItem"..i.."Button"]:Hide();
			_G["MailItem"..i.."Sender"]:SetText("");
			_G["MailItem"..i.."Subject"]:SetText("");
			_G["MailItem"..i.."ExpireTime"]:Hide();
		end
		index = index + 1;
	end

	-- Handle page arrows
	if ( InboxFrame.pageNum == 1 ) then
		InboxPrevPageButton:Disable();
	else
		InboxPrevPageButton:Enable();
	end
	if ( (InboxFrame.pageNum * INBOXITEMS_TO_DISPLAY) < numItems ) then
		InboxNextPageButton:Enable();
	else
		InboxNextPageButton:Disable();
	end
	if ( totalItems > numItems) then
		InboxTooMuchMail:Show();
	else
		InboxTooMuchMail:Hide();
	end
end

function InboxFrame_OnClick(self, index)
	if ( self:GetChecked() ) then
		InboxFrame.openMailID = index;
		OpenMailFrame.updateButtonPositions = true;
		OpenMail_Update();
		--OpenMailFrame:Show();
		ShowUIPanel(OpenMailFrame);
		OpenMailFrameInset:SetPoint("TOPLEFT", 4, -80);
		PlaySound(SOUNDKIT.IG_SPELLBOOK_OPEN);
	else
		InboxFrame.openMailID = 0;
		HideUIPanel(OpenMailFrame);
	end
	InboxFrame_Update();
end

function InboxFrame_OnModifiedClick(self, index)
	local _, _, _, _, _, cod = GetInboxHeaderInfo(index);
	if ( cod <= 0 ) then
		AutoLootMailItem(index);
	end
	InboxFrame_OnClick(self, index);
end

function InboxFrameItem_OnEnter(self)
	GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
	if ( self.hasItem ) then
		if ( self.itemCount == 1) then
			GameTooltip:SetInboxItem(self.index);
		else
			GameTooltip:AddLine(MAIL_MULTIPLE_ITEMS.." ("..self.itemCount..")");
		end
	end
	if (self.money) then
		if ( self.hasItem ) then
			GameTooltip:AddLine(" ");
		end
		GameTooltip:AddLine(ENCLOSED_MONEY, nil, nil, nil, true);
		GameTooltip_AddMoneyLine(GameTooltip, self.money);
	elseif (self.cod) then
		if ( self.hasItem ) then
			GameTooltip:AddLine(" ");
		end
		GameTooltip:AddLine(COD_AMOUNT, nil, nil, nil, true);
		local useRedLineColor = self.cod > GetMoney();
		GameTooltip_AddMoneyLine(GameTooltip, self.cod, useRedLineColor);
	end
	GameTooltip:Show();
end

function InboxNextPage()
	PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
	InboxFrame.pageNum = InboxFrame.pageNum + 1;
	InboxGetMoreMail();
	InboxFrame_Update();
end

function InboxPrevPage()
	PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
	InboxFrame.pageNum = InboxFrame.pageNum - 1;
	InboxGetMoreMail();
	InboxFrame_Update();
end

function InboxGetMoreMail()
	-- get more mails if there is an overflow and less than max are being shown
	if ( InboxFrame.overflowMails and InboxFrame.shownMails < InboxFrame.maxShownMails ) then
		CheckInbox();
	end
end

-- Open Mail functions

function OpenMailFrame_OnHide()
	StaticPopup_Hide("DELETE_MAIL");
	if ( not OpenMailFrame_IsValidMailID() ) then
		InboxFrame_Update();
		PlaySound(SOUNDKIT.IG_SPELLBOOK_CLOSE);
		return;
	end

	-- Determine if this is an auction temp invoice
	local isInvoice = select(5, GetInboxText(InboxFrame.openMailID));
	local isAuctionTempInvoice = false;
	if ( isInvoice ) then
		local invoiceType, itemName, playerName, bid, buyout, deposit, consignment, moneyDelay, etaHour, etaMin = GetInboxInvoiceInfo(InboxFrame.openMailID);
		if (invoiceType == "seller_temp_invoice") then
			isAuctionTempInvoice = true;
		end
	end

	-- If mail contains no items, then delete it on close
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, wasReturned, textCreated  = GetInboxHeaderInfo(InboxFrame.openMailID);
	if ( money == 0 and not itemCount and textCreated and not isAuctionTempInvoice ) then
		DeleteInboxItem(InboxFrame.openMailID);
	end
	InboxFrame.openMailID = 0;
	InboxFrame_Update();
	PlaySound(SOUNDKIT.IG_SPELLBOOK_CLOSE);
end

function OpenMailFrame_IsValidMailID()
	return InboxFrame.openMailID and InboxFrame.openMailID > 0 and InboxFrame.openMailID <= GetInboxNumItems();
end

function OpenMailFrame_UpdateButtonPositions(letterIsTakeable, textCreated, stationeryIcon, money)
	if ( OpenMailFrame.activeAttachmentButtons ) then
		while (#OpenMailFrame.activeAttachmentButtons > 0) do
			tremove(OpenMailFrame.activeAttachmentButtons);
		end
	else
		OpenMailFrame.activeAttachmentButtons = {};
	end
	if ( OpenMailFrame.activeAttachmentRowPositions ) then
		while (#OpenMailFrame.activeAttachmentRowPositions  > 0) do
			tremove(OpenMailFrame.activeAttachmentRowPositions );
		end
	else
		OpenMailFrame.activeAttachmentRowPositions = {};
	end

	local rowAttachmentCount = 0;

	-- letter
	if ( letterIsTakeable and not textCreated ) then
		SetItemButtonTexture(OpenMailLetterButton, stationeryIcon);
		tinsert(OpenMailFrame.activeAttachmentButtons, OpenMailLetterButton);
		rowAttachmentCount = rowAttachmentCount + 1;
	else
		SetItemButtonTexture(OpenMailLetterButton, "");
	end
	-- money
	if ( money == 0 ) then
		SetItemButtonTexture(OpenMailMoneyButton, "");
	else
		SetItemButtonTexture(OpenMailMoneyButton, C_CurrencyInfo.GetCoinIcon(money));
		tinsert(OpenMailFrame.activeAttachmentButtons, OpenMailMoneyButton);
		rowAttachmentCount = rowAttachmentCount + 1;
	end
	-- items
	for i=1, ATTACHMENTS_MAX_RECEIVE do
		local attachmentButton = OpenMailFrame.OpenMailAttachments[i];
		if HasInboxItem(InboxFrame.openMailID, i) then
			tinsert(OpenMailFrame.activeAttachmentButtons, attachmentButton);
			rowAttachmentCount = rowAttachmentCount + 1;

			local name, id, itemTexture, count, quality, canUse, isCurrency = GetInboxItem(InboxFrame.openMailID, i);
			if name then
				attachmentButton.name = name;
				SetItemButtonTexture(attachmentButton, itemTexture);
				SetItemButtonCount(attachmentButton, count);
				SetItemButtonQuality(attachmentButton, quality, id);
			else
				attachmentButton.name = nil;
				SetItemButtonTexture(attachmentButton, "Interface/Icons/INV_Misc_QuestionMark");
				SetItemButtonCount(attachmentButton, 0);
				SetItemButtonQuality(attachmentButton, nil);
			end

			if canUse then
				SetItemButtonTextureVertexColor(attachmentButton, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
			else
				SetItemButtonTextureVertexColor(attachmentButton, 1.0, 0.1, 0.1);
			end
		else
			attachmentButton:Hide();
		end

		if ( rowAttachmentCount >= ATTACHMENTS_PER_ROW_RECEIVE ) then
			tinsert(OpenMailFrame.activeAttachmentRowPositions, {cursorxstart=0,cursorxend=ATTACHMENTS_PER_ROW_RECEIVE - 1});
			rowAttachmentCount = 0;
		end
	end
	-- insert last row's position data
	if ( rowAttachmentCount > 0 ) then
		local xstart = (ATTACHMENTS_PER_ROW_RECEIVE - rowAttachmentCount) / 2;
		local xend = xstart + rowAttachmentCount - 1;
		tinsert(OpenMailFrame.activeAttachmentRowPositions, {cursorxstart=xstart,cursorxend=xend});
	end

	-- hide unusable attachment buttons
	for i=ATTACHMENTS_MAX_RECEIVE + 1, ATTACHMENTS_MAX do
		_G["OpenMailAttachmentButton"..i]:Hide();
	end
end

function OpenMail_Update()
	if ( not OpenMailFrame_IsValidMailID()) then
		return;
	end
	if ( CanComplainInboxItem(InboxFrame.openMailID) ) then
		OpenMailReportSpamButton:Enable();
		OpenMailReportSpamButton:Show();
		OpenMailSender:SetPoint("BOTTOMRIGHT", OpenMailReportSpamButton, "BOTTOMLEFT" , -5, 0);
	else
		OpenMailReportSpamButton:Hide();
		OpenMailSender:SetPoint("BOTTOMRIGHT", OpenMailFrame, "TOPRIGHT" , -12, -54);
	end

	-- Setup mail item
	local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, wasReturned, textCreated, canReply = GetInboxHeaderInfo(InboxFrame.openMailID);
	-- Set sender and subject
	if ( not sender or not canReply or sender == UnitName("player") ) then
		OpenMailReplyButton:Disable();
	else
		OpenMailReplyButton:Enable();
	end
	if ( not sender ) then
		sender = UNKNOWN;
	end
	-- Save sender name to pass to a potential spam report
	InboxFrame.openMailSender = sender;
	OpenMailSender.Name:SetText(sender);
	OpenMailSubject:SetText(subject);
	-- Set Text
	local bodyText, stationeryID1, stationeryID2, isTakeable, isInvoice, isConsortium = GetInboxText(InboxFrame.openMailID);
	OpenMailBodyText:SetText(bodyText, true);
	if ( stationeryID1 and stationeryID2 ) then
		OpenStationeryBackgroundLeft:SetTexture(stationeryID1);
		OpenStationeryBackgroundRight:SetTexture(stationeryID2);
	end

	-- Is an invoice
	if ( isInvoice ) then
		local invoiceType, itemName, playerName, bid, buyout, deposit, consignment, moneyDelay, etaHour, etaMin, count, commerceAuction = GetInboxInvoiceInfo(InboxFrame.openMailID);
		if ( invoiceType ) then
			if ( playerName == nil ) then
				playerName = (invoiceType == "buyer") and AUCTION_HOUSE_MAIL_MULTIPLE_SELLERS or AUCTION_HOUSE_MAIL_MULTIPLE_BUYERS;
			end

			-- Setup based on whether player is the buyer or the seller
			local multipleSale = count and count > 1;
			if ( multipleSale ) then
				itemName = format(AUCTION_MAIL_ITEM_STACK, itemName, count);
			end
			OpenMailInvoicePurchaser:SetShown(not commerceAuction);
			if ( invoiceType == "buyer" ) then
				OpenMailInvoiceItemLabel:SetText(ITEM_PURCHASED_COLON.." "..itemName);
				OpenMailInvoicePurchaser:SetText(SOLD_BY_COLON.." "..playerName);
				OpenMailInvoiceAmountReceived:SetText(AMOUNT_PAID_COLON);
				-- Update purchase price
				MoneyFrame_Update("OpenMailTransactionAmountMoneyFrame", bid);
				-- Position buy line
				OpenMailArithmeticLine:SetPoint("TOP", "OpenMailInvoicePurchaser", "BOTTOMLEFT", 125, 0);
				-- Not used for a purchase invoice
				OpenMailInvoiceSalePrice:Hide();
				OpenMailInvoiceDeposit:Hide();
				OpenMailInvoiceHouseCut:Hide();
				OpenMailDepositMoneyFrame:Hide();
				OpenMailHouseCutMoneyFrame:Hide();
				OpenMailSalePriceMoneyFrame:Hide();
				OpenMailInvoiceNotYetSent:Hide();
				OpenMailInvoiceMoneyDelay:Hide();
			elseif (invoiceType == "seller") then
				OpenMailInvoiceItemLabel:SetText(ITEM_SOLD_COLON.." "..itemName);
				OpenMailInvoicePurchaser:SetText(PURCHASED_BY_COLON.." "..playerName);
				OpenMailInvoiceAmountReceived:SetText(AMOUNT_RECEIVED_COLON);
				-- Determine if auction was bought out or bid on

				OpenMailSalePriceMoneyFrame.Count:SetShown(multipleSale);
				if ( multipleSale ) then
					OpenMailSalePriceMoneyFrame.Count:SetText(AUCTION_HOUSE_MAIL_FORMAT_COUNT:format(count));
				end

				-- Position buy line
				OpenMailArithmeticLine:SetPoint("TOP", "OpenMailInvoiceHouseCut", "BOTTOMRIGHT", -114, -9);
				MoneyFrame_Update("OpenMailSalePriceMoneyFrame", multipleSale and (bid / count) or bid);
				MoneyFrame_Update("OpenMailDepositMoneyFrame", deposit);
				MoneyFrame_Update("OpenMailHouseCutMoneyFrame", consignment);
				SetMoneyFrameColor("OpenMailHouseCutMoneyFrame", "red");
				MoneyFrame_Update("OpenMailTransactionAmountMoneyFrame", bid+deposit-consignment);

				-- Show these guys if the player was the seller
				OpenMailInvoiceSalePrice:Show();
				OpenMailInvoiceDeposit:Show();
				OpenMailInvoiceHouseCut:Show();
				OpenMailDepositMoneyFrame:Show();
				OpenMailHouseCutMoneyFrame:Show();
				OpenMailSalePriceMoneyFrame:Show();
				OpenMailInvoiceNotYetSent:Hide();
				OpenMailInvoiceMoneyDelay:Hide();
			elseif (invoiceType == "seller_temp_invoice") then
				OpenMailInvoiceItemLabel:SetText(ITEM_SOLD_COLON.." "..itemName);
				OpenMailInvoicePurchaser:SetText(PURCHASED_BY_COLON.." "..playerName);
				OpenMailInvoiceAmountReceived:SetText(AUCTION_INVOICE_PENDING_FUNDS_COLON);
				-- Update purchase price
				MoneyFrame_Update("OpenMailTransactionAmountMoneyFrame", bid+deposit-consignment);
				-- Position buy line
				OpenMailArithmeticLine:SetPoint("TOP", "OpenMailInvoicePurchaser", "BOTTOMLEFT", 125, 0);
				-- How long they have to wait to get the money
				OpenMailInvoiceMoneyDelay:SetFormattedText(AUCTION_INVOICE_FUNDS_DELAY, GameTime_GetFormattedTime(etaHour, etaMin, true));
				-- Not used for a temp sale invoice
				OpenMailInvoiceSalePrice:Hide();
				OpenMailInvoiceDeposit:Hide();
				OpenMailInvoiceHouseCut:Hide();
				OpenMailDepositMoneyFrame:Hide();
				OpenMailHouseCutMoneyFrame:Hide();
				OpenMailSalePriceMoneyFrame:Hide();
				OpenMailInvoiceNotYetSent:Show();
				OpenMailInvoiceMoneyDelay:Show();
			end
			OpenMailInvoiceFrame:Show();
		end
	else
		OpenMailInvoiceFrame:Hide();
	end

	if ( isConsortium ) then
		ConsortiumMailFrame:Show();

		local info = C_Mail.GetCraftingOrderMailInfo(InboxFrame.openMailID);

		if ( info.reason == Enum.RcoCloseReason.Cancel ) then
			ConsortiumMailFrame.OpeningText:SetText(CRAFTING_ORDER_MAIL_CANCELED_BODY);
			ConsortiumMailFrame.CrafterText:Hide();
			ConsortiumMailFrame.CrafterNote:Hide();
			ConsortiumMailFrame.CommissionPaidDisplay:Hide();
			ConsortiumMailFrame.CommissionReceived:Hide();
			ConsortiumMailFrame.CommissionReceivedDisplay:Hide();
			ConsortiumMailFrame.ConsortiumNote:Hide();

		elseif ( info.reason == Enum.RcoCloseReason.Expire ) then
			ConsortiumMailFrame.OpeningText:SetText(CRAFTING_ORDER_MAIL_EXPIRED_BODY);
			ConsortiumMailFrame.CrafterText:Hide();
			ConsortiumMailFrame.CrafterNote:Hide();
			ConsortiumMailFrame.CommissionPaidDisplay:Hide();
			ConsortiumMailFrame.CommissionReceived:Hide();
			ConsortiumMailFrame.CommissionReceivedDisplay:Hide();
			ConsortiumMailFrame.ConsortiumNote:Hide();

		elseif ( info.reason == Enum.RcoCloseReason.Fulfill ) then
			ConsortiumMailFrame.OpeningText:SetText(CRAFTING_ORDER_MAIL_ORDER_HEADER:format(info.recipeName));
			ConsortiumMailFrame.CrafterText:SetText(CRAFTING_ORDER_MAIL_FULFILLED_BY:format(info.crafterName or ""));
			ConsortiumMailFrame.CrafterText:Show();
			ConsortiumMailFrame.CrafterNote:SetText(info.crafterNote);
			ConsortiumMailFrame.CrafterNote:Show();
			ConsortiumMailFrame.CommissionPaidDisplay.MoneyDisplayFrame:SetFontObject(NumberFontNormalRightRed);
			ConsortiumMailFrame.CommissionPaidDisplay.MoneyDisplayFrame:SetAmount(info.commissionPaid);
			ConsortiumMailFrame.CommissionPaidDisplay:Show();
			ConsortiumMailFrame.CommissionReceived:Hide();
			ConsortiumMailFrame.CommissionReceivedDisplay:Hide();
			ConsortiumMailFrame.ConsortiumNote:Hide();

		elseif ( info.reason == Enum.RcoCloseReason.Reject ) then
			ConsortiumMailFrame.OpeningText:SetText(CRAFTING_ORDER_MAIL_ORDER_HEADER:format(info.recipeName));
			ConsortiumMailFrame.CrafterText:SetText(CRAFTING_ORDER_MAIL_REJECTED_BY:format(info.crafterName or ""));
			ConsortiumMailFrame.CrafterText:Show();
			ConsortiumMailFrame.CrafterNote:SetText(info.crafterNote);
			ConsortiumMailFrame.CrafterNote:Show();
			ConsortiumMailFrame.CommissionPaidDisplay:Hide();
			ConsortiumMailFrame.CommissionReceived:Hide();
			ConsortiumMailFrame.CommissionReceivedDisplay:Hide();
			ConsortiumMailFrame.ConsortiumNote:Hide();

		elseif ( info.reason == Enum.RcoCloseReason.CrafterFulfill ) then
			ConsortiumMailFrame.OpeningText:SetText(CRAFTING_ORDER_MAIL_ORDER_HEADER:format(info.recipeName));
			ConsortiumMailFrame.CrafterText:SetText(CRAFTING_ORDER_MAIL_FULFILLED_TO:format(info.customerName or ""));
			ConsortiumMailFrame.CrafterText:Show();
			ConsortiumMailFrame.CommissionReceived:Show();
			ConsortiumMailFrame.CommissionReceivedDisplay:Show();
			ConsortiumMailFrame.CommissionReceivedDisplay:SetAmount(info.commissionPaid or 0);
			ConsortiumMailFrame.ConsortiumNote:SetText(CRAFTING_ORDER_AUTO_FULFILL_BODY:format(UnitName("player"), info.recipeName, info.customerName or ""));
			ConsortiumMailFrame.ConsortiumNote:Show();
			ConsortiumMailFrame.CrafterNote:Hide();
			ConsortiumMailFrame.CommissionPaidDisplay:Hide();
		end
	else
		ConsortiumMailFrame:Hide();
	end

	local itemButtonCount, itemRowCount = OpenMail_GetItemCounts(isTakeable, textCreated, money);
	if ( OpenMailFrame.updateButtonPositions ) then
		OpenMailFrame_UpdateButtonPositions(isTakeable, textCreated, stationeryIcon, money);
	end
	if ( OpenMailFrame.activeAttachmentRowPositions ) then
		itemRowCount = #OpenMailFrame.activeAttachmentRowPositions;
	end

	-- record the original number of buttons that the mail needs
	OpenMailFrame.itemButtonCount = itemButtonCount;

	-- Determine starting position for buttons
	local marginxl = 10 + 4;
	local marginxr = 43 + 4;
	local areax = OpenMailFrame:GetWidth() - marginxl - marginxr;
	local iconx = OpenMailAttachmentButton1:GetWidth() + 2;
	local icony = OpenMailAttachmentButton1:GetHeight() + 2;
	local gapx1 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_RECEIVE)) / (ATTACHMENTS_PER_ROW_RECEIVE - 1));
	local gapx2 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_RECEIVE) - (gapx1 * (ATTACHMENTS_PER_ROW_RECEIVE - 1))) / 2);
	local gapy1 = 3;
	local gapy2 = 3;
	local areay = gapy2 + OpenMailAttachmentText:GetHeight() + gapy2 + (icony * itemRowCount) + (gapy1 * (itemRowCount - 1)) + gapy2;
	local indentx = marginxl + gapx2;
	local indenty = 28 + gapy2;
	local tabx = (iconx + gapx1) + 6; --this magic number changes the button spacing
	local taby = (icony + gapy1);
	local scrollHeight = 305 - areay;
	if (scrollHeight > 256) then
		scrollHeight = 256;
		areay = 305 - scrollHeight;
	end

	-- Resize the scroll frame
	OpenMailScrollFrame:SetHeight(scrollHeight);
	OpenMailScrollChildFrame:SetHeight(scrollHeight);
	OpenMailHorizontalBarLeft:SetPoint("TOPLEFT", "OpenMailFrame", "BOTTOMLEFT", 2, 39 + areay);
	OpenStationeryBackgroundLeft:SetHeight(scrollHeight);
	OpenStationeryBackgroundLeft:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);
	OpenStationeryBackgroundRight:SetHeight(scrollHeight);
	OpenStationeryBackgroundRight:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);

	-- Set attachment text
	if ( itemButtonCount > 0 ) then
		OpenMailAttachmentText:SetText(TAKE_ATTACHMENTS);
		OpenMailAttachmentText:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
		OpenMailAttachmentText:SetPoint("TOPLEFT", "OpenMailFrame", "BOTTOMLEFT", indentx, indenty + (icony * itemRowCount) + (gapy1 * (itemRowCount - 1)) + gapy2 + OpenMailAttachmentText:GetHeight());
	else
		OpenMailAttachmentText:SetText(NO_ATTACHMENTS);
		OpenMailAttachmentText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
		OpenMailAttachmentText:SetPoint("TOPLEFT", "OpenMailFrame", "BOTTOMLEFT", marginxl + (areax - OpenMailAttachmentText:GetWidth()) / 2, indenty + (areay - OpenMailAttachmentText:GetHeight()) / 2 + OpenMailAttachmentText:GetHeight());
	end
	-- Set letter
	if ( isTakeable and not textCreated ) then
		OpenMailLetterButton:Show();
	else
		OpenMailLetterButton:Hide();
	end
	-- Set Money
	if ( money == 0 ) then
		OpenMailMoneyButton:Hide();
		OpenMailFrame.money = nil;
	else
		OpenMailMoneyButton:Show();
		OpenMailFrame.money = money;
	end
	-- Set Items
	if ( itemRowCount > 0 and OpenMailFrame.activeAttachmentButtons ) then
		local firstAttachName;
		local rowIndex = 1;
		local cursorx = OpenMailFrame.activeAttachmentRowPositions[1].cursorxstart;
		local cursorxend = OpenMailFrame.activeAttachmentRowPositions[1].cursorxend;
		local cursory = itemRowCount - 1;
		for i, attachmentButton in ipairs(OpenMailFrame.activeAttachmentButtons) do
			attachmentButton:SetPoint("TOPLEFT", OpenMailFrame, "BOTTOMLEFT", indentx + (tabx * cursorx), indenty + icony + (taby * cursory));
			if attachmentButton ~= OpenMailLetterButton and attachmentButton ~= OpenMailMoneyButton then
				if cursory >= 0 and HasInboxItem(InboxFrame.openMailID, attachmentButton:GetID()) then
					if attachmentButton.name then
						if not firstAttachName then
							firstAttachName = attachmentButton.name;
						end
					end

					attachmentButton:Enable();
					attachmentButton:Show();
				else
					attachmentButton:Hide();
				end
			end

			cursorx = cursorx + 1;
			if (cursorx > cursorxend) then
				rowIndex = rowIndex + 1;

				cursory = cursory - 1;
				if ( rowIndex <= itemRowCount ) then
					cursorx = OpenMailFrame.activeAttachmentRowPositions[rowIndex].cursorxstart;
					cursorxend = OpenMailFrame.activeAttachmentRowPositions[rowIndex].cursorxend;
				end
			end
		end

		OpenMailFrame.itemName = firstAttachName;
	else
		OpenMailFrame.itemName = nil;
	end

	-- Set COD
	if ( CODAmount > 0 ) then
		OpenMailFrame.cod = CODAmount;
	else
		OpenMailFrame.cod = nil;
	end
	-- Set button to delete or return to sender
	if ( InboxItemCanDelete(InboxFrame.openMailID) ) then
		OpenMailDeleteButton:SetText(DELETE);
	else
		OpenMailDeleteButton:SetText(MAIL_RETURN);
	end
end

function OpenMail_GetItemCounts(letterIsTakeable, textCreated, money)
	local itemButtonCount = 0;
	local itemRowCount = 0;
	local numRows = 0;
	if ( letterIsTakeable and not textCreated ) then
		itemButtonCount = itemButtonCount + 1;
		itemRowCount = itemRowCount + 1;
	end
	if ( money ~= 0 ) then
		itemButtonCount = itemButtonCount + 1;
		itemRowCount = itemRowCount + 1;
	end
	for i=1, ATTACHMENTS_MAX_RECEIVE do
		if HasInboxItem(InboxFrame.openMailID, i) then
			itemButtonCount = itemButtonCount + 1;
			itemRowCount = itemRowCount + 1;
		end

		if ( itemRowCount >= ATTACHMENTS_PER_ROW_RECEIVE ) then
			numRows = numRows + 1;
			itemRowCount = 0;
		end
	end
	if ( itemRowCount > 0 ) then
		numRows = numRows + 1;
	end
	return itemButtonCount, numRows;
end

function OpenMail_Reply()
	MailFrameTab_OnClick(nil, 2);
	SendMailNameEditBox:SetText(OpenMailSender.Name:GetText())
	local subject = OpenMailSubject:GetText();
	local prefix = MAIL_REPLY_PREFIX.." ";
	if ( strsub(subject, 1, strlen(prefix)) ~= prefix ) then
		subject = prefix..subject;
	end
	SendMailSubjectEditBox:SetText(subject)
	SendMailBodyEditBox:SetFocus();

	-- Set the send mode so the work flow can change accordingly
	SendMailFrame.sendMode = "reply";
	SendMailFrame.replyMailID = InboxFrame.openMailID;
end

function OpenMail_Delete()
	if ( InboxItemCanDelete(InboxFrame.openMailID) ) then
		if ( OpenMailFrame.itemName ) then
			StaticPopup_Show("DELETE_MAIL", OpenMailFrame.itemName);
			return;
		elseif ( OpenMailFrame.money ) then
			StaticPopup_Show("DELETE_MONEY");
			return;
		else
			DeleteInboxItem(InboxFrame.openMailID);
		end
	else
		ReturnInboxItem(InboxFrame.openMailID);
		StaticPopup_Hide("COD_CONFIRMATION");
	end
	InboxFrame.openMailID = nil;
	HideUIPanel(OpenMailFrame);
end

local function ReportMail()
	local reportInfo = ReportInfo:CreateMailReportInfo(Enum.ReportType.Mail, InboxFrame.openMailID);
	if (reportInfo) then
		local reportTarget = ConsortiumMailFrame:IsShown() and C_Mail.GetCraftingOrderMailInfo(InboxFrame.openMailID).crafterName or InboxFrame.openMailSender;
		ReportFrame:InitiateReport(reportInfo, reportTarget);
	end
	OpenMailReportSpamButton:Disable();
end		

function OpenMail_ReportSpam()
	if (ConsortiumMailFrame:IsShown() and (OpenMailFrame.itemButtonCount > 0 or OpenMailFrame.money)) then 
		local data = {text = PROFESSIONS_CRAFTING_ORDER_MAIL_REPORT_WARNING, callback = ReportMail, acceptText = ACCEPT, cancelText = CANCEL,  }
		StaticPopup_ShowCustomGenericConfirmation(data);
	else 
		ReportMail();
	end
end

function OpenMailAttachment_OnEnter(self, index)
	GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
	GameTooltip:SetInboxItem(InboxFrame.openMailID, index);

	if ( OpenMailFrame.cod ) then
		local useRedLineColor = OpenMailFrame.cod > GetMoney();
		GameTooltip_AddMoneyLine(GameTooltip, OpenMailFrame.cod, useRedLineColor);
	end
	GameTooltip:Show();
end

function OpenMailAttachment_OnClick(self, index)
	if ( OpenMailFrame.cod and (OpenMailFrame.cod > GetMoney()) ) then
		StaticPopup_Show("COD_ALERT");
	elseif ( OpenMailFrame.cod ) then
		OpenMailFrame.lastTakeAttachment = index;
		StaticPopup_Show("COD_CONFIRMATION");
		OpenMailFrame.updateButtonPositions = false;
	else
		TakeInboxItem(InboxFrame.openMailID, index);
		OpenMailFrame.updateButtonPositions = false;
	end
	PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
end

-- SendMail functions

function SendMailMailButton_OnClick(self)
	self:Disable();
	local copper = MoneyInputFrame_GetCopper(SendMailMoney);
	SetSendMailCOD(0);
	SetSendMailMoney(0);
	if ( SendMailSendMoneyButton:GetChecked() ) then
		-- Send Money
		if ( copper > 0 ) then
			-- Confirmation is now done through the secure transfer system
			SetSendMailMoney(copper)
		end
	else
		-- Send C.O.D.
		if ( copper > 0 ) then
			SetSendMailCOD(copper);
		end
	end
	SendMailFrame_SendMail();
end

function SendMailFrame_SendMail()
	local replyMailID = SendMailFrame.sendMode == "reply" and SendMailFrame.replyMailID or nil;
	SendMail(SendMailNameEditBox:GetText(), SendMailSubjectEditBox:GetText(), SendMailBodyEditBox:GetText(), replyMailID);
end

function SendMailFrame_EnableSendMailButton()
	SendMailMailButton:Enable();
end

function SendMailFrame_Update()
	-- Update the item(s) being sent
	local itemCount = 0;
	local itemTitle;
	local gap = false;
	local last = 0;
	for i=1, ATTACHMENTS_MAX_SEND do
		local sendMailAttachmentButton = SendMailFrame.SendMailAttachments[i];

		if HasSendMailItem(i) then
			itemCount = itemCount + 1;

			local itemName, itemID, itemTexture, stackCount, quality = GetSendMailItem(i);
			sendMailAttachmentButton:SetNormalTexture(itemTexture or "Interface\\Icons\\INV_Misc_QuestionMark");
			SetItemButtonCount(sendMailAttachmentButton, stackCount or 0);
			SetItemButtonQuality(sendMailAttachmentButton, quality, itemID);

			-- determine what a name for the message in case it doesn't already have one
			if not itemTitle and itemName then
				if stackCount <= 1 then
					itemTitle = itemName;
				else
					itemTitle = itemName.." ("..stackCount..")";
				end
			end

			if last + 1 ~= i then
				gap = true;
			end
			last = i;
		else
			sendMailAttachmentButton:ClearNormalTexture();
			SetItemButtonCount(sendMailAttachmentButton, 0);
			SetItemButtonQuality(sendMailAttachmentButton, nil);
		end
	end

	-- Enable or disable C.O.D. depending on whether or not there's an item to send
	if ( itemCount > 0 ) then
		SendMailCODButton:Enable();
		SendMailCODButtonText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);

		if SendMailSubjectEditBox:GetText() == "" or SendMailSubjectEditBox:GetText() == SendMailFrame.previousItem then
			itemTitle = itemTitle or "";
			SendMailSubjectEditBox:SetText(itemTitle);
			SendMailFrame.previousItem = itemTitle;
		end
	else
		-- If no itemname see if the subject is the name of the previously held item, if so clear the subject
		if ( SendMailSubjectEditBox:GetText() == SendMailFrame.previousItem ) then
			SendMailSubjectEditBox:SetText("");
		end
		SendMailFrame.previousItem = "";

		SendMailRadioButton_OnClick(1);
		SendMailCODButton:Disable();
		SendMailCODButtonText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
	end
	-- Update the cost
	MoneyFrame_Update("SendMailCostMoneyFrame", GetSendMailPrice());

	-- Color the postage text
	if ( GetSendMailPrice() > GetMoney() ) then
		SetMoneyFrameColor("SendMailCostMoneyFrame", "red");
	else
		SetMoneyFrameColor("SendMailCostMoneyFrame", "white");
	end

	-- Determine how many rows of attachments to show
	local itemRowCount = 1;
	local temp = last;
	while ((temp > ATTACHMENTS_PER_ROW_SEND) and (itemRowCount < ATTACHMENTS_MAX_ROWS_SEND)) do
		itemRowCount = itemRowCount + 1;
		temp = temp - ATTACHMENTS_PER_ROW_SEND;
	end
	if (not gap and (temp == ATTACHMENTS_PER_ROW_SEND) and (itemRowCount < ATTACHMENTS_MAX_ROWS_SEND)) then
		itemRowCount = itemRowCount + 1;
	end
	if (SendMailFrame.maxRowsShown and (last > 0) and (itemRowCount < SendMailFrame.maxRowsShown)) then
		itemRowCount = SendMailFrame.maxRowsShown;
	else
		SendMailFrame.maxRowsShown = itemRowCount;
	end

	-- Compute sizes
	local cursorx = 0;
	local cursory = itemRowCount - 1;
	local marginxl = 8 + 6;
	local marginxr = 40 + 6;
	local areax = SendMailFrame:GetWidth() - marginxl - marginxr;
	local iconx = SendMailAttachment1:GetWidth() + 2;
	local icony = SendMailAttachment1:GetHeight() + 2;
	local gapx1 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_SEND)) / (ATTACHMENTS_PER_ROW_SEND - 1));
	local gapx2 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_SEND) - (gapx1 * (ATTACHMENTS_PER_ROW_SEND - 1))) / 2);
	local gapy1 = 5;
	local gapy2 = 6;
	local areay = (gapy2 * 2) + (gapy1 * (itemRowCount - 1)) + (icony * itemRowCount);
	local indentx = marginxl + gapx2;
	local indenty = 170 + gapy2 + icony;
	local tabx = (iconx + gapx1) - 2; --this magic number changes the attachment spacing
	local taby = (icony + gapy1);
	local scrollHeight = 249 - areay;

	-- Resize the scroll frame
	SendMailScrollFrame:SetHeight(scrollHeight);
	SendMailScrollChildFrame:SetHeight(scrollHeight);
	SendMailHorizontalBarLeft2:SetPoint("TOPLEFT", "SendMailFrame", "BOTTOMLEFT", 2, 184 + areay);
	SendStationeryBackgroundLeft:SetHeight(min(scrollHeight, 256));
	SendStationeryBackgroundLeft:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);
	SendStationeryBackgroundRight:SetHeight(min(scrollHeight, 256));
	SendStationeryBackgroundRight:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);
	SendStationeryBackgroundLeft:SetTexture("Interface/Stationery/stationerytest1");
	SendStationeryBackgroundRight:SetTexture("Interface/Stationery/stationerytest2");

	-- Set Items
	for i=1, ATTACHMENTS_MAX_SEND do
		if (cursory >= 0) then
			SendMailFrame.SendMailAttachments[i]:Enable();
			SendMailFrame.SendMailAttachments[i]:Show();
			SendMailFrame.SendMailAttachments[i]:SetPoint("TOPLEFT", "SendMailFrame", "BOTTOMLEFT", indentx + (tabx * cursorx), indenty + (taby * cursory));

			cursorx = cursorx + 1;
			if (cursorx >= ATTACHMENTS_PER_ROW_SEND) then
				cursory = cursory - 1;
				cursorx = 0;
			end
		else
			SendMailFrame.SendMailAttachments[i]:Hide();
		end
	end
	for i=ATTACHMENTS_MAX_SEND+1, ATTACHMENTS_MAX do
		SendMailFrame.SendMailAttachments[i]:Hide();
	end

	SendMailFrame_CanSend();
end

function SendMailFrame_Reset()
	SendMailNameEditBox:SetText("");
	SendMailNameEditBox:SetFocus();
	SendMailSubjectEditBox:SetText("");
	SendMailBodyEditBox:SetText("");
	SendMailFrame_Update();
	MoneyInputFrame_ResetMoney(SendMailMoney);
	SendMailRadioButton_OnClick(1);
	SendMailFrame.maxRowsShown = 0;
end

function SendMailFrame_CanSend()
	local checks = 0;
	local checksRequired = 2;
	-- Has a sendee
	if ( #SendMailNameEditBox:GetText() > 0 ) then
		checks = checks + 1;
	end
	-- and has a subject
	if ( #SendMailSubjectEditBox:GetText() > 0 ) then
		checks = checks + 1;
	end
	-- check c.o.d. amount
	if ( SendMailCODButton:GetChecked() ) then
		checksRequired = checksRequired + 1;
		-- COD must be less than 10000 gold
		if ( MoneyInputFrame_GetCopper(SendMailMoney) > MAX_COD_AMOUNT * COPPER_PER_GOLD ) then
			if ( not CVarCallbackRegistry:GetCVarValueBool("colorblindMode") ) then
				SendMailErrorCoin:Show();
			end
			SendMailErrorText:Show();
		else
			SendMailErrorText:Hide();
			SendMailErrorCoin:Hide();
			checks = checks + 1;
		end
	end

	if ( checks == checksRequired ) then
		SendMailMailButton:Enable();
	else
		SendMailMailButton:Disable();
	end
end

function SendMailRadioButton_OnClick(index)
	if ( index == 1 ) then
		SendMailSendMoneyButton:SetChecked(true);
		SendMailCODButton:SetChecked(false);
		SendMailMoneyText:SetText(AMOUNT_TO_SEND);
	else
		SendMailSendMoneyButton:SetChecked(false);
		SendMailCODButton:SetChecked(true);
		SendMailMoneyText:SetText(COD_AMOUNT);
	end
	PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
end

function SendMailMoneyButton_OnClick()
	local cursorMoney = GetCursorMoney();
	if ( cursorMoney > 0 ) then
		local money = MoneyInputFrame_GetCopper(SendMailMoney);
		if ( money > 0 ) then
			cursorMoney = cursorMoney + money;
		end
		MoneyInputFrame_SetCopper(SendMailMoney, cursorMoney);
		DropCursorMoney();
	end
end

function SendMailAttachmentButton_OnClick(self, button)
	ClickSendMailItemButton(self:GetID(), button == "RightButton");
end

function SendMailAttachmentButton_OnDropAny()
	ClickSendMailItemButton();
end

function SendMailAttachment_OnEnter(self)
	local index = self:GetID();
	GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
	if ( HasSendMailItem(index) ) then
		GameTooltip:SetSendMailItem(index);
	else
		GameTooltip:SetText(ATTACHMENT_TEXT, 1.0, 1.0, 1.0);
	end
	self.UpdateTooltip = SendMailAttachment_OnEnter;
end

-----------------------------------------------------------------------------------------------
---------------------------------------- Open All Mail ----------------------------------------
-----------------------------------------------------------------------------------------------

local OPEN_ALL_MAIL_MIN_DELAY = 0.15;

OpenAllMailMixin = {};

function OpenAllMailMixin:Reset()
	self.mailIndex = 1;
	self.attachmentIndex = ATTACHMENTS_MAX;
	self.timeUntilNextRetrieval = nil;
	self.failedItemIDs = nil;
end

function OpenAllMailMixin:StartOpening()
	self:Reset();
	self:Disable();

	C_Mail.SetOpeningAll(true);

	self:SetText(OPEN_ALL_MAIL_BUTTON_OPENING);
	self:RegisterEvent("MAIL_INBOX_UPDATE");
	self:RegisterEvent("MAIL_FAILED");
	self.numToOpen = GetInboxNumItems();
	self:AdvanceAndProcessNextItem();
end

function OpenAllMailMixin:StopOpening()
	self:Reset();
	self:Enable();

	C_Mail.SetOpeningAll(false);

	self:SetText(OPEN_ALL_MAIL_BUTTON);
	self:UnregisterEvent("MAIL_INBOX_UPDATE");
	self:UnregisterEvent("MAIL_FAILED");
end

function OpenAllMailMixin:ShouldSkipCurrentMail()
	local _, _, _, _, _money, CODAmount, _daysLeft, _itemCount, _, _, _, _, isGM = GetInboxHeaderInfo(self.mailIndex);

	-- Players are required to manually open mail from GMs so they don't accidentially miss them or any restored items attached.
	if isGM then
		return true;
	end

	-- Players are required to manually open COD mail to confirm the payment.
	if CODAmount and CODAmount > 0 then
		return true;
	end

	return false;
end

function OpenAllMailMixin:ShouldSkipCurrentAttachment()
	local _, id, _, _, _, _, isCurrency = GetInboxItem(self.mailIndex, self.attachmentIndex);
	local hasFailedItem = not isCurrency and self:IsItemFailed(id);
	if hasFailedItem then
		return true;
	end

	-- Mail money is retrieved per-mail rather than per-slot, so any slot on a
	-- mail with money is considered retrievable regardless of slot index.
	if C_Mail.HasInboxMoney(self.mailIndex) then
		return false;
	end

	if HasInboxItem(self.mailIndex, self.attachmentIndex) then
		return false;
	end

	return true;
end

function OpenAllMailMixin:AdvanceToNextMail()
	self.mailIndex = self.mailIndex + 1;
	self.attachmentIndex = ATTACHMENTS_MAX;

	if self.mailIndex > GetInboxNumItems() then
		return false;
	end

	return true;
end

function OpenAllMailMixin:AdvanceToNextItem()
	if self:ShouldSkipCurrentMail() then
		if self:AdvanceToNextMail() then
			return self:AdvanceToNextItem();
		end

		return false;
	end

	local foundAttachment = false;
	while not foundAttachment do
		if self:ShouldSkipCurrentAttachment() then
			self.attachmentIndex = self.attachmentIndex - 1;
			if self.attachmentIndex == 0 then
				break;
			end
		else
			foundAttachment = true;
		end
	end

	if not foundAttachment then
		if self:AdvanceToNextMail() then
			return self:AdvanceToNextItem();
		end

		return false;
	end

	return true;
end

function OpenAllMailMixin:AdvanceAndProcessNextItem()
	if C_Container.CalculateTotalNumberOfFreeBagSlots() == 0 then
		self:StopOpening();
		return;
	end

	if self:AdvanceToNextItem() then
		self:ProcessNextItem();
	else
		self:StopOpening();
	end
end

function OpenAllMailMixin:ProcessNextItem()
	local _, _, _, _, money, _, _, itemCount = GetInboxHeaderInfo(self.mailIndex);

	if money > 0 then
		TakeInboxMoney(self.mailIndex);
		self.timeUntilNextRetrieval = OPEN_ALL_MAIL_MIN_DELAY;
	elseif itemCount and itemCount > 0 then
		TakeInboxItem(self.mailIndex, self.attachmentIndex);
		self.timeUntilNextRetrieval = OPEN_ALL_MAIL_MIN_DELAY;
	else
		self:AdvanceAndProcessNextItem();
	end
end

function OpenAllMailMixin:OnLoad()
	self:Reset();
end

function OpenAllMailMixin:OnEvent(event, ...)
	if event == "MAIL_INBOX_UPDATE" then
		if self.numToOpen ~= GetInboxNumItems() then
			self.mailIndex = 1;
			self.attachmentIndex = ATTACHMENTS_MAX;
		end
	elseif event == "MAIL_FAILED" then
		local itemID = ...;
		if itemID then
			self:AddFailedItem(itemID);
		end
	end
end

function OpenAllMailMixin:OnUpdate(dt)
	if self.timeUntilNextRetrieval then
		self.timeUntilNextRetrieval = self.timeUntilNextRetrieval - dt;

		if self.timeUntilNextRetrieval <= 0 then
			if not C_Mail.IsCommandPending() then
				self.timeUntilNextRetrieval = nil;
				self:AdvanceAndProcessNextItem();
			else
				-- Delay until the current mail command is done processing.
				self.timeUntilNextRetrieval = OPEN_ALL_MAIL_MIN_DELAY;
			end
		end
	end
end

function OpenAllMailMixin:OnClick()
	self:StartOpening();
end

function OpenAllMailMixin:OnHide()
	self:StopOpening();
end

function OpenAllMailMixin:AddFailedItem(itemID)
	if not self.failedItemIDs then
		self.failedItemIDs = {};
	end

	self.failedItemIDs[itemID] = true;
end

function OpenAllMailMixin:IsItemFailed(itemID)
	return self.failedItemIDs and self.failedItemIDs[itemID];
end
