'use strict';

var
	_ = require('underscore'),
	$ = require('jquery'),
	ko = require('knockout'),

	TextUtils = require('%PathToCoreWebclientModule%/js/utils/Text.js'),
	Types = require('%PathToCoreWebclientModule%/js/utils/Types.js'),
	UrlUtils = require('%PathToCoreWebclientModule%/js/utils/Url.js'),
	Utils = require('%PathToCoreWebclientModule%/js/utils/Common.js'),

	App = require('%PathToCoreWebclientModule%/js/App.js'),
	MainTabExtMethods = require('modules/%ModuleName%/js/MainTabExtMethods.js'),
	ModulesManager = require('%PathToCoreWebclientModule%/js/ModulesManager.js'),
	Pulse = require('%PathToCoreWebclientModule%/js/Pulse.js'),
	Routing = require('%PathToCoreWebclientModule%/js/Routing.js'),
	Storage = require('%PathToCoreWebclientModule%/js/Storage.js'),
	UserSettings = require('%PathToCoreWebclientModule%/js/Settings.js'),
	WindowOpener = require('%PathToCoreWebclientModule%/js/WindowOpener.js'),

	CAbstractScreenView = require('%PathToCoreWebclientModule%/js/views/CAbstractScreenView.js'),

	ComposeUtils = require('modules/%ModuleName%/js/utils/Compose.js'),
	LinksUtils = require('modules/%ModuleName%/js/utils/Links.js'),
	MailUtils = require('modules/%ModuleName%/js/utils/Mail.js'),
	SendingUtils = require('modules/%ModuleName%/js/utils/Sending.js'),

	AccountList = require('modules/%ModuleName%/js/AccountList.js'),
	Ajax = require('modules/%ModuleName%/js/Ajax.js'),
	MailCache = require('modules/%ModuleName%/js/Cache.js'),
	MessagePaneSpamButtonsController = require('modules/%ModuleName%/js/views/message/SpamButtonsView.js'),
	Settings = require('modules/%ModuleName%/js/Settings.js'),

	CAttachmentModel = require('modules/%ModuleName%/js/models/CAttachmentModel.js'),

	MainTab = App.isNewTab() && window.opener && window.opener.MainTabMailMethods
;

/**
 * @constructor
 */
function CMessagePaneView()
{
	CAbstractScreenView.call(this, '%ModuleName%');
	
	this.bNewTab = App.isNewTab();
	this.isLoading = ko.observable(false);

	this.bAllowSearchMessagesBySubject = Settings.AllowSearchMessagesBySubject;

	MailCache.folderList.subscribe(this.onFolderListSubscribe, this);
	this.messages = MailCache.messages;
	this.messages.subscribe(this.onMessagesSubscribe, this);
	this.currentMessage = MailCache.currentMessage;
	this.currentMessage.subscribe(this.onCurrentMessageSubscribe, this);
	UserSettings.timeFormat.subscribe(this.onCurrentMessageSubscribe, this);
	UserSettings.dateFormat.subscribe(this.onCurrentMessageSubscribe, this);
	this.displayedMessageUid = ko.observable('');
	
	this.browserTitle = ko.computed(function () {
		var
			oMessage = this.currentMessage(),
			sSubject = oMessage ? oMessage.subject() : '',
			sPrefix = sSubject ? sSubject + ' - ' : ''
		;
		return sPrefix + AccountList.getEmail() + ' - ' + TextUtils.i18n('%MODULENAME%/HEADING_MESSAGE_BROWSER_TAB');
	}, this);

	this.isCurrentMessage = ko.computed(function () {
		return !!this.currentMessage();
	}, this);

	this.isCurrentMessageLoaded = ko.computed(function () {
		return this.isCurrentMessage() && !this.isLoading();
	}, this);

	this.visibleNoMessageSelectedText = ko.computed(function () {
		return this.messages().length > 0 && !this.isCurrentMessage();
	}, this);

	this.prevMessageUid = MailCache.prevMessageUid;
	this.nextMessageUid = MailCache.nextMessageUid;

	this.isEnablePrevMessage = ko.computed(function () {
		return App.isNewTab() && Types.isNonEmptyString(this.prevMessageUid());
	}, this);
	this.isEnableNextMessage = ko.computed(function () {
		return App.isNewTab() && Types.isNonEmptyString(this.nextMessageUid());
	}, this);

	this.isEnableDelete = this.isCurrentMessage;
	this.isEnableReply = this.isCurrentMessageLoaded;
	this.isEnableReplyAll = this.isCurrentMessageLoaded;
	this.isEnableResend = this.isCurrentMessageLoaded;
	this.isEnableForward = this.isCurrentMessageLoaded;
	this.isEnablePrint = this.isCurrentMessageLoaded;
	this.isEnableSave = function () {
		return this.isCurrentMessage() && this.currentMessage().sDownloadAsEmlUrl !== '';
	};

	this.deleteCommand = Utils.createCommand(this, this.executeDeleteMessage, this.isEnableDelete);
	this.prevMessageCommand = Utils.createCommand(this, this.executePrevMessage, this.isEnablePrevMessage);
	this.nextMessageCommand = Utils.createCommand(this, this.executeNextMessage, this.isEnableNextMessage);
	this.replyCommand = Utils.createCommand(this, this.executeReply, this.isEnableReply);
	this.replyAllCommand = Utils.createCommand(this, this.executeReplyAll, this.isEnableReplyAll);
	this.resendCommand = Utils.createCommand(this, this.executeResend, this.isEnableResend);
	this.forwardCommand = Utils.createCommand(this, this.executeForward, this.isEnableForward);
	this.printCommand = Utils.createCommand(this, this.executePrint, this.isEnablePrint);
	this.saveCommand = Utils.createCommand(this, this.executeSave, this.isEnableSave);
	this.forwardAsAttachment = Utils.createCommand(this, this.executeForwardAsAttachment, this.isCurrentMessageLoaded);
	this.messageToolbarControllers = ko.observableArray([]);
	this.registerController(MessagePaneSpamButtonsController, 'OnMessageToolbar');

	this.moreCommand = Utils.createCommand(this, null, this.isCurrentMessageLoaded);
	this.moreSectionCommands = ko.observableArray([]);
	App.broadcastEvent('%ModuleName%::AddMoreSectionCommand', _.bind(function (oCommand) {
		var oNewCommand = _.extend({
			'Text': '',
			'CssClass': '',
			'Handler': function () {},
			'Visible': true
		}, oCommand);
		oNewCommand.Command = Utils.createCommand(this, oNewCommand.Handler, this.isCurrentMessageLoaded);
		this.moreSectionCommands.push(oNewCommand);
	}, this));

	this.oUnsubscribeButtonView = require('modules/%ModuleName%/js/views/message-pane/UnsubscribeButtonView.js'),

	this.visiblePicturesControl = ko.observable(false);
	this.visibleShowPicturesLink = ko.observable(false);

	this.visibleConfirmationControl = ko.computed(function () {
		return (this.currentMessage() && this.currentMessage().readingConfirmationAddressee() !== '' && this.currentMessage() && this.currentMessage().readingConfirmationAddressee() !== AccountList.getEmail());
	}, this);

	this.isCurrentNotDraftOrSent = ko.computed(function () {
		var oCurrFolder = MailCache.getCurrentFolder();
		return (oCurrFolder && oCurrFolder.fullName().length > 0 &&
			oCurrFolder.type() !== Enums.FolderTypes.Drafts &&
			oCurrFolder.type() !== Enums.FolderTypes.Sent);
	}, this);

	this.isCurrentSentFolder = ko.computed(function () {
		var oCurrFolder = MailCache.getCurrentFolder();
		return !!oCurrFolder && oCurrFolder.fullName().length > 0 && oCurrFolder.type() === Enums.FolderTypes.Sent;
	}, this);

	this.isCurrentNotDraftFolder = ko.computed(function () {
		var oCurrFolder = MailCache.getCurrentFolder();
		return !!oCurrFolder && oCurrFolder.fullName().length > 0 && oCurrFolder.type() !== Enums.FolderTypes.Drafts;
	}, this);

	this.isCurrentTemplateFolder = ko.computed(function () {
		return MailCache.isTemplateFolder(MailCache.getCurrentFolderFullname());
	}, this);

	this.topControllers = ko.observableArray();
	this.bodyControllers = ko.observableArray();
	this.bottomControllers = ko.observableArray();
	this.controllers = ko.computed(function () {
		return _.union(
			this.topControllers(),
			this.bodyControllers(),
			this.bottomControllers(),
			this.messageToolbarControllers()
		);
	}, this);

	this.disableAllSendTools = ko.computed(function () {
		var bDisable = false;
		_.each(this.controllers(), function (oController) {
			if (_.isFunction(oController.disableAllSendTools) && oController.disableAllSendTools())
			{
				bDisable = true;
			}
		});
		return bDisable;
	}, this);
	this.isVisibleReplyTool = ko.computed(function () {
		return !this.disableAllSendTools() && this.isCurrentNotDraftOrSent() && !this.isCurrentTemplateFolder();
	}, this);
	this.isVisibleResendTool = ko.computed(function () {
		return !this.disableAllSendTools() && this.isCurrentSentFolder() && !this.isCurrentTemplateFolder();
	}, this);
	this.isVisibleForwardTool = ko.computed(function () {
		return !this.disableAllSendTools() && this.isCurrentNotDraftFolder() && !this.isCurrentTemplateFolder();
	}, this);

	this.accountId = ko.observable(0);
	this.folder = ko.observable('');
	this.uid = ko.observable('');
	this.subject = ko.observable('');
	this.emptySubject = ko.computed(function () {
		return ($.trim(this.subject()) === '');
	}, this);
	this.subjectForDisplay = ko.computed(function () {
		return this.emptySubject() ? TextUtils.i18n('%MODULENAME%/LABEL_NO_SUBJECT') : this.subject();
	}, this);
	this.importance = ko.observable(Enums.Importance.Normal);
	this.oFromAddr = ko.observable(null);
	this.from = ko.observable('');
	this.fromEmail = ko.observable('');
	this.fullFrom = ko.observable('');
	this.to = ko.observable('');
	this.aToAddr = ko.observableArray([]);
	this.cc = ko.observable('');
	this.aCcAddr = ko.observableArray([]);
	this.bcc = ko.observable('');
	this.aBccAddr = ko.observableArray([]);
	this.allRecipients = ko.observableArray([]);
	this.currentAccountEmail = ko.observable();
	this.sMeSender = Settings.UseMeRecipientForMessages ? TextUtils.i18n('%MODULENAME%/LABEL_ME_SENDER') : null;
	this.sMeRecipient = Settings.UseMeRecipientForMessages ? TextUtils.i18n('%MODULENAME%/LABEL_ME_RECIPIENT') : null;

	this.fullDate = ko.observable('');
	this.midDate = ko.observable('');

	this.textBody = ko.observable('');
	this.textBodyForNewWindow = ko.observable('');
	this.domTextBody = ko.observable(null);
	this.rtlMessage = ko.observable(false);

	this.contentHasFocus = ko.observable(false);

	App.broadcastEvent('%ModuleName%::RegisterMessagePaneController', _.bind(function (oController, sPlace) {
		this.registerController(oController, sPlace);
	}, this));

	this.fakeHeader = ko.computed(function () {
		var topControllersVisible = !!_.find(this.topControllers(), function (oController) {
			return !!oController.visible && oController.visible();
		});
		return !(this.visiblePicturesControl() || this.visibleConfirmationControl() || topControllersVisible);
	}, this);

	this.sAttachmentsSwitcherViewTemplate = App.isMobile() ? '%ModuleName%_Message_AttachmentsSwitcherView' : '';
	this.sQuickReplyViewTemplate = App.isMobile() || !Settings.AllowQuickReply ? '' : '%ModuleName%_Message_QuickReplyView';

	this.attachments = ko.observableArray([]);
	this.notInlineAttachments = ko.computed(function () {
		return _.filter(this.attachments(), function (oAttach) {
			return !oAttach.linked();
		});
	}, this);
	this.notInlineAttachmentsInString = ko.computed(function () {
		return _.map(this.notInlineAttachments(), function (oAttachment) {
			return oAttachment.fileName();
		}, this).join(', ');
	}, this);

	this.allAttachmentsDownloadMethods = ko.observableArray([]);
	this.visibleDownloadAllAttachmentsSeparately = ko.computed(function () {
		return this.notInlineAttachments().length > 1;
	}, this);
	this.visibleExtendedDownload = ko.computed(function () {
		return this.visibleDownloadAllAttachmentsSeparately() || this.allAttachmentsDownloadMethods().length > 0;
	}, this);
	App.broadcastEvent('%ModuleName%::AddAllAttachmentsDownloadMethod', _.bind(function (oMethod) {
		this.allAttachmentsDownloadMethods.push(oMethod);
	}, this));

	this.detailsVisible = ko.observable(Storage.getData('MessageDetailsVisible') === '1');
	this.detailsTooltip = ko.computed(function () {
		return this.detailsVisible() ? TextUtils.i18n('COREWEBCLIENT/ACTION_HIDE_DETAILS') : TextUtils.i18n('COREWEBCLIENT/ACTION_SHOW_DETAILS');
	}, this);

	this.hasNotInlineAttachments = ko.computed(function () {
		return this.notInlineAttachments().length > 0;
	}, this);

	this.hasBodyText = ko.computed(function () {
		return this.textBody().length > 0;
	}, this);

	this.visibleAddMenu = ko.observable(false);

	// Quick Reply Part

	this.replyText = ko.observable('');
	this.replyTextFocus = ko.observable(false);
	this.replyPaneVisible = ko.computed(function () {
		return this.currentMessage() && this.currentMessage().completelyFilled();
	}, this);
	this.replySendingStarted = ko.observable(false);
	this.replySavingStarted = ko.observable(false);
	this.replyAutoSavingStarted = ko.observable(false);
	this.requiresPostponedSending = ko.observable(false);
	this.replyAutoSavingStarted.subscribe(function () {
		if (!this.replyAutoSavingStarted() && this.requiresPostponedSending())
		{
			SendingUtils.sendPostponedMail(this.replyDraftUid());
			this.requiresPostponedSending(false);
		}
	}, this);
	this.hasReplyAllCcAddrs = ko.observable(false);
	this.placeholderText = ko.computed(function () {
		return this.hasReplyAllCcAddrs() ? TextUtils.i18n('%MODULENAME%/LABEL_QUICK_REPLY_ALL') : TextUtils.i18n('%MODULENAME%/LABEL_QUICK_REPLY');
	}, this);
	this.sendButtonText = ko.computed(function () {
		return this.hasReplyAllCcAddrs() ? TextUtils.i18n('%MODULENAME%/ACTION_SEND_ALL') : TextUtils.i18n('%MODULENAME%/ACTION_SEND');
	}, this);

	ko.computed(function () {
		if (!this.replyTextFocus() || this.replyAutoSavingStarted() || this.replySavingStarted() || this.replySendingStarted())
		{
			this.stopAutosaveTimer();
		}
		if (this.replyTextFocus() && !this.replyAutoSavingStarted() && !this.replySavingStarted() && !this.replySendingStarted())
		{
			this.startAutosaveTimer();
		}
	}, this);

	this.saveButtonText = ko.computed(function () {
		return this.replyAutoSavingStarted() ? TextUtils.i18n('%MODULENAME%/ACTION_SAVE_IN_PROGRESS') : TextUtils.i18n('%MODULENAME%/ACTION_SAVE');
	}, this);
	this.replyDraftUid = ko.observable('');
	this.replyLoadingText = ko.computed(function () {
		if (this.replySendingStarted())
		{
			return TextUtils.i18n('COREWEBCLIENT/INFO_SENDING');
		}
		else if (this.replySavingStarted())
		{
			return TextUtils.i18n('%MODULENAME%/INFO_SAVING');
		}
		return '';
	}, this);

	this.isEnableSendQuickReply = ko.computed(function () {
		return this.isCurrentMessageLoaded() && this.replyText() !== '' && !this.replySendingStarted();
	}, this);
	this.isEnableSaveQuickReply = ko.computed(function () {
		return this.isEnableSendQuickReply() && !this.replySavingStarted() && !this.replyAutoSavingStarted();
	}, this);

	this.saveQuickReplyCommand = Utils.createCommand(this, this.executeSaveQuickReply, this.isEnableSaveQuickReply);
	this.sendQuickReplyCommand = Utils.createCommand(this, this.executeSendQuickReply, this.isEnableSendQuickReply);

	this.domMessageHeader = ko.observable(null);
	this.domQuickReply = ko.observable(null);

	this.domMessageForPrint = ko.observable(null);

	// to have time to take action "Open full reply form" before the animation starts
	this.replyTextFocusThrottled = ko.observable(false).extend({'throttle': 50});

	this.replyTextFocus.subscribe(function () {
		this.replyTextFocusThrottled(this.replyTextFocus());
	}, this);

	this.isQuickReplyActive = ko.computed(function () {
		return this.replyText().length > 0 || this.replyTextFocusThrottled();
	}, this);

	//*** Quick Reply Part

	this.visibleAttachments = ko.observable(false);
	this.showMessage = function () {
		this.visibleAttachments(false);
	};
	this.showAttachments = function () {
		this.visibleAttachments(true);
	};

	this.sDefaultFontName = Settings.DefaultFontName;

	Pulse.registerDayOfMonthFunction(_.bind(this.updateMomentDate, this));

	App.broadcastEvent('%ModuleName%::ConstructView::after', {'Name': 'CMessagePaneView', 'View': this});
}

_.extendOwn(CMessagePaneView.prototype, CAbstractScreenView.prototype);

CMessagePaneView.prototype.ViewTemplate = App.isNewTab() ? '%ModuleName%_MessagePaneScreenView' : '%ModuleName%_MessagePaneView';
CMessagePaneView.prototype.ViewConstructorName = 'CMessagePaneView';

/**
 * @param {object} oData
 * @param {object} oEvent
 */
CMessagePaneView.prototype.resizeDblClick = function (oData, oEvent)
{
	if (oEvent.target.className !== '' && !!oEvent.target.className.search(/add_contact|icon|link|title|subject|link|date|from/))
	{
		Utils.calmEvent(oEvent);
		Utils.removeSelection();
		if (this.expandMessagePaneWidth) {
			this.expandMessagePaneWidth(!this.expandMessagePaneWidth());
		}
	}
};

CMessagePaneView.prototype.notifySender = function ()
{
	if (this.currentMessage() && this.currentMessage().readingConfirmationAddressee() !== '')
	{
		var sText = TextUtils.i18n('%MODULENAME%/LABEL_RETURN_RECEIPT_MAIL_TEXT', {
			'EMAIL': AccountList.getEmail(),
			'SUBJECT': this.subject()
		}).replace(/\\r\\n/g, '\n');
		Ajax.send('SendMessage', {
			'To': this.currentMessage().readingConfirmationAddressee(),
			'Subject': TextUtils.i18n('%MODULENAME%/LABEL_RETURN_RECEIPT_MAIL_SUBJECT'),
			'Text': sText,
			'ConfirmFolder': this.currentMessage().folder(),
			'ConfirmUid': this.currentMessage().longUid()
		});
		this.currentMessage().readingConfirmationAddressee('');
	}
};

CMessagePaneView.prototype.onFolderListSubscribe = function ()
{
	if (App.isNewTab())
	{
		this.onMessagesSubscribe();
	}
};

CMessagePaneView.prototype.onMessagesSubscribe = function ()
{
	if (!this.currentMessage() && this.uid() && this.uid().length > 0)
	{
		MailCache.setCurrentMessage(this.accountId(), this.folder(), this.uid());
	}
};

/**
 * @param {string} sUid
 */
CMessagePaneView.prototype.passReplyDataToNewTab = function (sUid)
{
	if (this.currentMessage() && this.currentMessage().longUid() === sUid && this.replyText() !== '')
	{
		MainTabExtMethods.passReplyData(sUid, {
			'ReplyText': this.replyText(),
			'ReplyDraftUid': this.replyDraftUid()
		});

		this.replyText('');
		this.replyDraftUid('');
	}
};

CMessagePaneView.prototype.onCurrentMessageSubscribe = function ()
{
	var
		oMessage = this.currentMessage(),
		oAccount = oMessage ? AccountList.getAccount(oMessage.accountId()) : null,
		oReplyData = null
	;

	if (MainTab && oMessage)
	{
		oReplyData = MainTab.getReplyData(oMessage.longUid());
		if (oReplyData)
		{
			this.replyText(oReplyData.ReplyText);
			this.replyDraftUid(oReplyData.ReplyDraftUid);
		}
	}
	else if (!oMessage || oMessage.longUid() !== this.displayedMessageUid())
	{
		this.replyText('');
		this.replyDraftUid('');
	}

	if (oMessage && this.uid() === oMessage.uid())
	{
		this.hasReplyAllCcAddrs(SendingUtils.hasReplyAllCcAddrs(oMessage));

		this.subject(oMessage.subject());
		this.importance(oMessage.importance());
		this.from(oMessage.oFrom.getDisplay());
		this.fromEmail(oMessage.oFrom.getFirstEmail());

		this.fullFrom(oMessage.oFrom.getFull());
		if (oMessage.oFrom.aCollection.length > 0)
		{
			this.oFromAddr(oMessage.oFrom.aCollection[0]);
		}
		else
		{
			this.oFromAddr(null);
		}

		this.to(oMessage.oTo.getFull());
		this.aToAddr(oMessage.oTo.aCollection);
		this.cc(oMessage.oCc.getFull());
		this.aCcAddr(oMessage.oCc.aCollection);
		this.bcc(oMessage.oBcc.getFull());
		this.aBccAddr(oMessage.oBcc.aCollection);

		this.currentAccountEmail(oAccount.email());
		this.allRecipients(_.uniq(_.union(this.aToAddr(), this.aCcAddr(), this.aBccAddr())));

		this.midDate(oMessage.oDateModel.getMidDate());
		this.fullDate(oMessage.oDateModel.getFullDate());

		this.isLoading(oMessage.longUid() !== '' && !oMessage.completelyFilled());

		this.setMessageBody();

		if (!Settings.DisableRtlRendering)
		{
			this.rtlMessage(oMessage.rtl());
		}

		if (App.isNewTab())
		{
			/*jshint onevar: false*/
			var aAtachments = [];
			/*jshint onevar: true*/

			_.each(oMessage.attachments(), _.bind(function (oAttach) {
				var oCopy = new CAttachmentModel(oAttach.iAccountId);
				oCopy.copyProperties(oAttach);
				aAtachments.push(oCopy);
			}, this));

			this.attachments(aAtachments);
		}
		else
		{
			this.attachments(oMessage.attachments());
		}

		if (!oMessage.completelyFilled() || oMessage.truncated())
		{
			/*jshint onevar: false*/
			var oSubscribedField = !oMessage.completelyFilled() ? oMessage.completelyFilled : oMessage.truncated;
			/*jshint onevar: true*/
			if (App.isNewTab())
			{
				oMessage.completelyFilledNewTabSubscription = oSubscribedField.subscribe(this.onCurrentMessageSubscribe, this);
			}
			else
			{
				oMessage.completelyFilledSubscription = oSubscribedField.subscribe(this.onCurrentMessageSubscribe, this);
			}
		}
		else if (oMessage.completelyFilledSubscription)
		{
			oMessage.completelyFilledSubscription.dispose();
			oMessage.completelyFilledSubscription = undefined;
		}
		else if (oMessage.completelyFilledNewTabSubscription)
		{
			oMessage.completelyFilledNewTabSubscription.dispose();
			oMessage.completelyFilledNewTabSubscription = undefined;
		}
	}
	else
	{
		this.hasReplyAllCcAddrs(false);

		this.isLoading(false);
		$(this.domTextBody()).empty().data('displayed-message-uid', '');
		this.displayedMessageUid('');
		this.rtlMessage(false);

		// cannot use removeAll, because the attachments of messages are passed by reference
		// and the call to removeAll removes attachments from message in the cache too.
		this.attachments([]);
		this.visiblePicturesControl(false);
		this.visibleShowPicturesLink(false);
	}

	this.doAfterPopulatingMessage();
};

CMessagePaneView.prototype.updateMomentDate = function ()
{
	var oMessage = this.currentMessage();
	if (oMessage && oMessage.oDateModel)
	{
		this.midDate(oMessage.oDateModel.getMidDate());
		this.fullDate(oMessage.oDateModel.getFullDate());
	}
};

CMessagePaneView.prototype.setMessageBody = function ()
{
	if (this.currentMessage())
	{
		var
			oMessage = this.currentMessage(),
			sText = oMessage.text(),
			$body = $(this.domTextBody()),
			oDom = null,
			sHtml = '',
			sLen = sText.length,
			sMaxLen = 5000000,
			aCollapsedStatuses = []
		;

		this.textBody(sText);

		if ($body.data('displayed-message-uid') === oMessage.longUid())
		{
			aCollapsedStatuses = this.getBlockquotesStatus();
		}

		$body.empty();

		if (oMessage.isPlain() || sLen > sMaxLen)
		{
			$body.html(sText);

			this.visiblePicturesControl(false);
		}
		else
		{
			oDom = oMessage.getDomText();
			sHtml = oDom.length > 0 ? oDom.html() : '';

			$body.append(sHtml);

			this.visiblePicturesControl(oMessage.hasExternals() && !oMessage.isExternalsAlwaysShown());
			this.visibleShowPicturesLink(!oMessage.isExternalsShown());

			if (!TextUtils.htmlStartsWithBlockquote(sHtml))
			{
				this.doHidingBlockquotes(aCollapsedStatuses);
			}
		}

		$body.data('displayed-message-uid', oMessage.longUid());
		this.displayedMessageUid(oMessage.longUid());
	}
};

CMessagePaneView.prototype.getBlockquotesStatus = function ()
{
	var aCollapsedStatuses = [];

	$($('blockquote', $(this.domTextBody())).get()).each(function () {
		var $blockquote = $(this);

		if ($blockquote.hasClass('blockquote_before_toggle'))
		{
			aCollapsedStatuses.push($blockquote.hasClass('collapsed'));
		}
	});

	return aCollapsedStatuses;
};

/**
 * @param {Array} aCollapsedStatuses
 */
CMessagePaneView.prototype.doHidingBlockquotes = function (aCollapsedStatuses)
{
	var
		iMinHeightForHide = 120,
		iHiddenHeight = 80,
		iStatusIndex = 0
	;

	$($('blockquote', $(this.domTextBody())).get()).each(function () {
		var
			$blockquote = $(this),
			$parentBlockquotes = $blockquote.parents('blockquote'),
			$switchButton = $('<span class="blockquote_toggle"></span>').html(TextUtils.i18n('%MODULENAME%/ACTION_SHOW_QUOTED_TEXT')),
			bHidden = true
		;
		if ($parentBlockquotes.length === 0)
		{
			if ($blockquote.height() > iMinHeightForHide)
			{
				$blockquote
					.addClass('blockquote_before_toggle')
					.after($switchButton)
					.wrapInner('<div class="blockquote_content"></div>')
				;
				$switchButton.bind('click', function () {
					if (bHidden)
					{
						$blockquote.height('auto');
						$switchButton.html(TextUtils.i18n('%MODULENAME%/ACTION_HIDE_QUOTED_TEXT'));
						bHidden = false;
					}
					else
					{
						$blockquote.height(iHiddenHeight);
						$switchButton.html(TextUtils.i18n('%MODULENAME%/ACTION_SHOW_QUOTED_TEXT'));
						bHidden = true;
					}

					$blockquote.toggleClass('collapsed', bHidden);
				});
				if (iStatusIndex < aCollapsedStatuses.length)
				{
					bHidden = aCollapsedStatuses[iStatusIndex];
					iStatusIndex++;
				}
				$blockquote.height(bHidden ? iHiddenHeight : 'auto').toggleClass('collapsed', bHidden);
			}
		}
	});
};

/**
 * @param {Array} aParams
 */
CMessagePaneView.prototype.onRoute = function (aParams)
{
	var
		oParams = LinksUtils.parseMailbox(aParams),
		sFolder = oParams.Folder,
		sUid = oParams.Uid,
		oIdentifiers = MailCache.getMessageActualIdentifiers(MailCache.currentAccountId(), sFolder, sUid)
	;

	AccountList.changeCurrentAccountByHash(oParams.AccountHash);

	if (this.replyText() !== '' && this.uid() !== oIdentifiers.sUid)
	{
		this.saveReplyMessage(false);
	}

	this.accountId(oIdentifiers.iAccountId);
	this.uid(oIdentifiers.sUid);
	this.folder(oIdentifiers.sFolder);
	MailCache.setCurrentMessage(oIdentifiers.iAccountId, oIdentifiers.sFolder, oIdentifiers.sUid);

	this.contentHasFocus(true);
};

CMessagePaneView.prototype.showPictures = function ()
{
	MailCache.showExternalPictures(false);
	this.visibleShowPicturesLink(false);
	this.setMessageBody();
};

CMessagePaneView.prototype.alwaysShowPictures = function ()
{
	var sEmail = this.currentMessage() ? this.currentMessage().oFrom.getFirstEmail() : '';

	if (sEmail.length > 0)
	{
		Ajax.send('SetEmailSafety', {'Email': sEmail});
	}

	MailCache.showExternalPictures(true);
	this.visiblePicturesControl(false);
	this.setMessageBody();
};

CMessagePaneView.prototype.openInNewWindow = function ()
{
	this.openMessageInNewWindowBound(this.currentMessage());
};

CMessagePaneView.prototype.getReplyHtmlText = function ()
{
	return '<div style="font-family: ' + this.sDefaultFontName + '; font-size: 16px">' + SendingUtils.getHtmlFromText(this.replyText()) + '</div>';
};

/**
 * @param {string} sReplyType
 */
CMessagePaneView.prototype.executeReplyOrForward = function (sReplyType)
{
	if (this.currentMessage())
	{
		SendingUtils.setReplyData(this.getReplyHtmlText(), this.replyDraftUid());

		this.replyText('');
		this.replyDraftUid('');

		ComposeUtils.composeMessageAsReplyOrForward(sReplyType, this.currentMessage().accountId(), this.currentMessage().folder(), this.currentMessage().longUid());
	}
};

CMessagePaneView.prototype.executeDeleteMessage = function ()
{
	if (this.currentMessage())
	{
		if (MainTab)
		{
			MainTab.deleteMessage(this.currentMessage().longUid(), function () { window.close(); });
		}
		else if (App.isMobile())
		{
			MailUtils.deleteMessages([this.currentMessage().longUid()], App);
		}
	}
};

CMessagePaneView.prototype.executePrevMessage = function ()
{
	if (this.isEnablePrevMessage())
	{
		Routing.setHash(LinksUtils.getViewMessage(MailCache.currentAccountId(), MailCache.getCurrentFolderFullname(), this.prevMessageUid()));
	}
};

CMessagePaneView.prototype.executeNextMessage = function ()
{
	if (this.isEnableNextMessage())
	{
		Routing.setHash(LinksUtils.getViewMessage(MailCache.currentAccountId(), MailCache.getCurrentFolderFullname(), this.nextMessageUid()));
	}
};

CMessagePaneView.prototype.executeReply = function ()
{
	this.executeReplyOrForward(Enums.ReplyType.Reply);
};

CMessagePaneView.prototype.executeReplyAll = function ()
{
	this.executeReplyOrForward(Enums.ReplyType.ReplyAll);
};

CMessagePaneView.prototype.executeResend = function ()
{
	this.executeReplyOrForward(Enums.ReplyType.Resend);
};

CMessagePaneView.prototype.executeForward = function ()
{
	this.executeReplyOrForward(Enums.ReplyType.Forward);
};

CMessagePaneView.prototype.executePrint = function ()
{
	var
		oMessage = this.currentMessage(),
		oWin = oMessage ? WindowOpener.open('', this.subject() + '-print') : null,
		sHtml = ''
	;

	if (oMessage && oWin)
	{
		this.textBodyForNewWindow(oMessage.getConvertedHtml(UrlUtils.getAppPath(), true));
		sHtml = $(this.domMessageForPrint()).html();

		$(oWin.document.body).html(sHtml);
		oWin.print();
	}
};

CMessagePaneView.prototype.executeSave = function ()
{
	if (this.isEnableSave() && this.currentMessage())
	{
		UrlUtils.downloadByUrl(this.currentMessage().sDownloadAsEmlUrl, true);
	}
};

CMessagePaneView.prototype.executeForwardAsAttachment = function ()
{
	if (this.currentMessage())
	{
		ComposeUtils.composeMessageWithEml(this.currentMessage());
	}
};

CMessagePaneView.prototype.changeAddMenuVisibility = function ()
{
	var bVisibility = !this.visibleAddMenu();
	this.visibleAddMenu(bVisibility);
};

/**
 * @param {Object} oResponse
 * @param {Object} oRequest
 */
CMessagePaneView.prototype.onSendOrSaveMessageResponse = function (oResponse, oRequest)
{
	var oResData = SendingUtils.onSendOrSaveMessageResponse(oResponse, oRequest, this.requiresPostponedSending());
	switch (oResData.Method)
	{
		case 'SendMessage':
			this.replySendingStarted(false);
			if (oResData.Result)
			{
				this.replyText('');
			}
			break;
		case 'SaveMessage':
			if (oResData.Result)
			{
				this.replyDraftUid(oResData.NewUid);
			}
			this.replySavingStarted(false);
			this.replyAutoSavingStarted(false);
			break;
	}
};

CMessagePaneView.prototype.executeSendQuickReply = function ()
{
	if (this.isEnableSendQuickReply())
	{
		this.replySendingStarted(true);
		this.requiresPostponedSending(this.replyAutoSavingStarted());
		SendingUtils.sendReplyMessage('SendMessage', this.getReplyHtmlText(), this.replyDraftUid(),
			this.onSendOrSaveMessageResponse, this, this.requiresPostponedSending());

		this.replyTextFocus(false);
	}
};

CMessagePaneView.prototype.executeSaveQuickReply = function ()
{
	this.saveReplyMessage(false);
};

/**
 * @param {Boolean} bAutosave
 */
CMessagePaneView.prototype.saveReplyMessage = function (bAutosave)
{
	if (this.isEnableSaveQuickReply())
	{
		if (bAutosave)
		{
			this.replyAutoSavingStarted(true);
		}
		else
		{
			this.replySavingStarted(true);
		}
		SendingUtils.sendReplyMessage('SaveMessage', this.getReplyHtmlText(), this.replyDraftUid(),
			this.onSendOrSaveMessageResponse, this);
	}
};

/**
 * Stops autosave.
 */
CMessagePaneView.prototype.stopAutosaveTimer = function ()
{
	window.clearTimeout(this.autoSaveTimer);
};

/**
 * Starts autosave.
 */
CMessagePaneView.prototype.startAutosaveTimer = function ()
{
	if (this.isEnableSaveQuickReply())
	{
		var fSave = _.bind(this.saveReplyMessage, this, true);
		this.stopAutosaveTimer();
		if (Settings.AllowAutosaveInDrafts)
		{
			this.autoSaveTimer = window.setTimeout(fSave, Settings.AutoSaveIntervalSeconds * 1000);
		}
	}
};

CMessagePaneView.prototype.executeAllAttachmentsDownloadMethod = function (fHandler)
{
	const message = this.currentMessage();
	if (message) {
		const
			notInlineAttachments = message.notInlineAttachments(),
			hashes = notInlineAttachments.map(attach => attach.hash())
		;
		fHandler(message.accountId(), hashes, notInlineAttachments);
	}
};

CMessagePaneView.prototype.downloadAllAttachmentsSeparately = function ()
{
	if (this.currentMessage())
	{
		this.currentMessage().downloadAllAttachmentsSeparately();
	}
};

CMessagePaneView.prototype.onShow = function ()
{
	this.bShown = true;
};

CMessagePaneView.prototype.onHide = function ()
{
	this.bShown = false;
	_.each(this.controllers(), _.bind(function (oController) {
		if ($.isFunction(oController.onHide))
		{
			oController.onHide();
		}
	}, this));
};

/**
 * @param {Object} $MailViewDom
 */
CMessagePaneView.prototype.onBind = function ($MailViewDom)
{
	ModulesManager.run('SessionTimeoutWeblient', 'registerFunction', [_.bind(function () {
		if (this.replyText() !== '')
		{
			this.saveReplyMessage(false);
		}
	}, this)]);

	this.$MailViewDom = _.isUndefined($MailViewDom) ? this.$viewDom : $MailViewDom;

	this.$MailViewDom.on('mousedown', 'a', function (oEvent) {
		if (oEvent && 3 !== oEvent['which'])
		{
			var sHref = $(this).attr('href');
			if (sHref && 'mailto:' === sHref.toString().toLowerCase().substr(0, 7))
			{
				ComposeUtils.composeMessageToAddresses(sHref.toString());
				return false;
			}
		}

		return true;
	});

	if (!App.isMobile())
	{
		this.hotKeysBind();
	}
};

CMessagePaneView.prototype.hotKeysBind = function ()
{
	$(document).on('keydown', $.proxy(function(ev) {

		const allowReply = this.bShown && ev && !(ev.ctrlKey || ev.metaKey) && !ev.shiftKey &&
			!Utils.isTextFieldFocused() && this.isEnableReply();

		if (allowReply && ev.keyCode === Enums.Key.q) {
			ev.preventDefault();
			this.replyTextFocus(true);
		} else if (allowReply && ev.keyCode === Enums.Key.r) {
			ev.preventDefault();
			this.executeReply();
		}
	}, this));
};

CMessagePaneView.prototype.showSourceHeaders = function ()
{
	var
		oMessage = this.currentMessage(),
		oWin = oMessage && oMessage.completelyFilled() ? WindowOpener.open('', this.subject() + '-headers') : null
	;

	if (oWin)
	{
		$(oWin.document.body).html('<pre>' + TextUtils.encodeHtml(oMessage.sourceHeaders()) + '</pre>');
	}
};

CMessagePaneView.prototype.switchDetailsVisibility = function ()
{
	this.detailsVisible(!this.detailsVisible());
	Storage.setData('MessageDetailsVisible', this.detailsVisible() ? '1' : '0');
};

/**
 * @param {Object} oController
 * @param {string} sPlace
 */
CMessagePaneView.prototype.registerController = function (oController, sPlace) {
	switch (sPlace)
	{
		case 'OnMessageToolbar':
			this.messageToolbarControllers.push(oController);
			break
		case 'BeforeMessageHeaders':
			this.topControllers.push(oController);
			break
		case 'BeforeMessageBody':
			this.bodyControllers.push(oController);
			break
		case 'AfterMessageBody':
			this.bottomControllers.push(oController);
			break;
	}

	if ($.isFunction(oController.assignMessagePaneExtInterface))
	{
		oController.assignMessagePaneExtInterface(this.getExtInterface());
	}
};

/**
 * @returns {Object}
 */
CMessagePaneView.prototype.getExtInterface = function ()
{
	return {
		changeText: _.bind(function (sText) {
			var oMessage = this.currentMessage();
			if (oMessage && this.isCurrentMessageLoaded())
			{
				oMessage.changeText(sText);
				this.setMessageBody();
			}
		}, this)
	};
};

CMessagePaneView.prototype.doAfterPopulatingMessage = function ()
{
	var
		oMessage = this.currentMessage(),
		bLoaded = oMessage && !this.isLoading(),
		oMessageProps = bLoaded ? {
			iAccountId: oMessage.accountId(),
			sFolderFullName: oMessage.folder(),
			sMessageUid: oMessage.uid(),
			aToEmails: oMessage.oTo.getEmails(),
			bPlain: oMessage.isPlain(),
			sRawText: oMessage.textRaw(),
			sText: oMessage.text(),
			sAccountEmail: AccountList.getEmail(oMessage.accountId()),
			sFromEmail: oMessage.oFrom.getFirstEmail(),
			iSensitivity: oMessage.sensitivity(),
			aExtend: oMessage.aExtend
		} : null
	;

	_.each(this.controllers(), _.bind(function (oController) {
		if ($.isFunction(oController.doAfterPopulatingMessage))
		{
			oController.doAfterPopulatingMessage(oMessageProps);
		}
	}, this));

	ModulesManager.run('ContactsWebclient', 'applyContactsCards', [this.$MailViewDom.find('span.address')]);
};

CMessagePaneView.prototype.searchBySubject = function ()
{
	if (Settings.AllowSearchMessagesBySubject && this.currentMessage())
	{
		var
			sFolder = this.currentMessage().folder(),
			iPage = 1,
			sUid = this.currentMessage().longUid(),
			sSearch = '',
			sFilters = '',

			sSubject = this.currentMessage().subject(),
			aSubject = sSubject.split(':'),
			aPrefixes = Settings.PrefixesToRemoveBeforeSearchMessagesBySubject,
			aSearch = []
		;

		if (aPrefixes.length === 0)
		{
			sSearch = aSubject;
		}
		else
		{
			_.each(aSubject, function (sSubjPart) {
				if (aSearch.length > 0)
				{
					aSearch.push(sSubjPart);
				}
				else
				{
					var hasPrefix = false;
					var sTrimSubjPart = $.trim(sSubjPart);
					_.each(aPrefixes, function (sPref) {
						var re = new RegExp('^' + sPref + '(\\[\\d*\\]){0,1}$', 'i');
						hasPrefix = hasPrefix || re.test(sTrimSubjPart);
					});
					if (!hasPrefix) {
						aSearch.push(sSubjPart);
					}
				}
			});
			sSearch = $.trim(aSearch.join(':'));
		}

		Routing.setHash(LinksUtils.getMailbox(sFolder, iPage, sUid, sSearch, sFilters));
	}
};

module.exports = new CMessagePaneView();
