Ext.namespace('Zarafa.plugins.spreedwebrtc');

/**
 *
 * @class Zarafa.plugins.spreedwebrtc.SpreedPresence
 * @extends Zarafa.core.Plugin
 *
 */
Zarafa.plugins.spreedwebrtc.SpreedPresence = Ext.extend(Zarafa.core.PresencePlugin, {

	/**
	 * @cfg {String} url
	 * The url used to send the requests to. defaults to presence.
	 */
	url : 'presence',

	/**
	 * @cfg {String} cmd
	 * The GET attribute to send to the server. defaults to 'presence'
	 */
	cmd : 'ping',

	/**
	 * @cfg {Object} headers
	 * The default headers to be applied to the request. defaults to
	 *      'Content-Type' => 'application/json; charset=utf-8;'
	 */
	headers : undefined,

	/**
	 * @cfg {Object} authenticationToken
	 * The authenticationToken to be passed on with the request. 
	 */
	authenticationToken : undefined,

	/**
	 * @cfg {Object} lastAction
	 * The last presence call type sent to the server. 
	 */
	lastAction : undefined,

	/**
	 * @cfg {Number} timeout The polling interval timeout value for the call
	 * to {@link #sendPresence}.
	 */
	interval : 60000,

	/**
	 * @cfg {Number} timeout The polling getdelay timeout value for the call
	 * to {@link #sendGetPresence}.
	 */
	getdelay : 3000,

	/**
	 * @cfg {Number} timeout The initial timeout value for the call
	 * to {@link #sendPresence}. This will be incremented by {@link #getNextTimeout}.
	 */
	timeout : 1000,

	/**
	 * @cfg {Number} maxTimeout The maximum timeout value which can be used
	 * and returned by {@link #getNextTimeout}.
	 */
	maxTimeout : 300000,

	/**
	 * The DelayedTask which will be used to defer the {@link #sendPresence}
	 * function call to periodically update the presence to the server.
	 * @property
	 * @type Ext.util.DelayedTask
	 * @private
	 */
	presenceTask : undefined,

	/**
	 * The DelayedTask which will be used to delay the {@link #sendGetPresence}
	 * function.
	 * @property
	 * @type Ext.util.DelayedTask
	 * @private
	 */
	presenceGetTask : undefined,

	/**
	 * The current timeout value for the {@link #retryTask}.
	 * This is obtained (and incremented) through {@link #getNextTimeout}.
	 * @property
	 * @type Number
	 * @private
	 */
	currentTimeout : undefined,

	/**
	 * True if the Presence has been send to the server, and the PresenceService
	 * is currently awaiting the response from the server.
	 * @property
	 * @type Boolean
	 * @private
	 */
	presencePending : false,

	/**
	 * Reference to the address book store
	 *
	 * @type {object}
	 * @private
	 */
	addressBookStore: null,

	/**
	 * Maintains the list of Kopano emails being monitored
	 *
	 * @type {object}
	 * @private
	 */
	presenceWatchingList : [],

	/**
	 * Maintains the list of Kopano emails being monitored
	 *
	 * @type {object}
	 * @private
	 */
	presenceWatchingListChanged : false,

	/**
	 * Maintains the presence data from the last presence server check
	 *
	 * @type {object}
	 * @private
	 */
	presenceData: undefined,

	/**
	 * Maintains the the known presence user EntryId to Kopano email address mapping
	 *
	 * @type {object}
	 * @private
	 */
	presenceEntryIdEmailAddressMap: {},

	/**
	 * Maintains the known presence user smtp address to Kopano email address mapping
	 *
	 * @type {object}
	 * @private
	 */
	presenceSmtpAddressEmailAddressMap: {},

	/**
	 * Maintains the known userids being displayed in UI
	 *
	 * @type {object}
	 * @private
	 */
	userids: {},

	/**
	 * Maintains the state if WebApp Presence UI Support is available
	 *
	 * @type {object}
	 * @private
	 */
	webappPresenceUiSupport: undefined,

	/**
	 * Constructor
	 * @protected
	 */
	constructor: function (config) {
		config = config || {};

		Ext.apply(config, {
			// Apply here instead of class prototype, to prevent
			// accidental sharing of object between all instances.
			headers : {
				'Content-Type' : 'application/json; charset=utf-8;'
			}
		});

		Ext.apply(this, config);

		Zarafa.plugins.spreedwebrtc.SpreedPresence.superclass.constructor.call(this, config);

		var spreed_enabled = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/enable');
		if (! spreed_enabled ) { return; }

		// Instantiate the delayed task for the polling updatePresence function
		this.presenceTask = new Ext.util.DelayedTask(this.updatePresence, this);

		// Instantiate the delayed task for the sendGetPresence retry function
		this.presenceGetTask = new Ext.util.DelayedTask(this.sendGetPresence, this);

		// start the service
		this.start();
	},

	/**
	 * Called after constructor.
	 * Registers insertion points.
	 * @protected
	 */
	initPlugin: function () {
		var spreed_enabled = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/enable');
		this.webappPresenceUiSupport = Ext.isDefined(Zarafa.core.PresencePlugin) && Ext.isDefined(Zarafa.core.data.UserIdObject);
		if ( spreed_enabled ) {
			if (!this.webappPresenceUiSupport) {
				this.registerInsertionPoint('context.addressbook.gridpanel', this.createPresenceColumn, this);
				this.registerInsertionPoint('previewpanel.toolbar.recipientlinks', this.onRecipientLinksShow.createDelegate(this), this);
				this.registerInsertionPoint('context.mail.gridrow', this.createMailGridStatusIcon, this);

				// Listen to creation of a new content panel so we can know if there is a new GAB content panel
				Zarafa.core.data.ContentPanelMgr.on('createcontentpanel', this.onNewContentPanel.createDelegate(this));
			}
		}
		Zarafa.plugins.spreedwebrtc.SpreedPresence.superclass.initPlugin.apply(this, arguments);
	},

	/**
	 * This will add a presence status icon to the mail grid
	 *
	 * @param {String} insertionName
	 * @param {Ext.data.Record} record The {@link Ext.data.Record Record} corresponding to the current row.
	 * @returns {String} A formatted string with icon layout
	 */
	createMailGridStatusIcon: function(insertionName, record) {
		var entryId = record.get('sender_entryid'),
			email_address = record.get('sender_email_address'),
			icon = this.getMailGridStatusIcon(email_address);

		return String.format('<td style="width: 24px;"><div class="grid_compact zarafa_mailgrid_presence_status {0}" style="height: 24px; width: 24px;">&nbsp;</div></td>', icon);
	},

	/**
	 * This will create an extra column in the address book
	 *
	 * @returns {Object} Object with the column definition of the column
	 * @private
	 */
	 createPresenceColumn: function () {
	 	this.refresh();
		return  [{
			dataIndex: 'status_spreed',
			header: _('Spreed'),
			width: 50,
			fixed: true,
			renderer: this.presenceSpreedColumnRenderer
		}]
	},

	/**
	 * This will render the presence (status_spreed) column in the address book
	 *
	 * @param {Object} value The data value for the cell.
	 * @param {Object} p An object with metadata
	 * @param {Ext.data.record} record The {Ext.data.Record} from which the data was extracted.
	 * @private
	 */
	presenceSpreedColumnRenderer: function (value, p, record) {
		p.css += value === 'online' ? 'icon_spreed_status_online' : 'icon_spreed_status_offline';
	},

	/**
	 * This will render the presence (status_xmpp) column in the address book
	 *
	 * @param {Object} value The data value for the cell.
	 * @param {Object} p An object with metadata
	 * @param {Ext.data.record} record The {Ext.data.Record} from which the data was extracted.
	 * @private
	 */
	presenceXmppColumnRenderer: function (value, p, record) {
		if (value === 'online') {
			p.css += 'icon_xmpp_status_available';
		} else if (value === 'available') {
			p.css += 'icon_xmpp_status_available';
		} else if (value === 'away') {
			p.css += 'icon_xmpp_status_away';
		} else if (value === 'busy') {
			p.css += 'icon_xmpp_status_busy';
		} else {
			p.css += 'icon_xmpp_status_unavailable';
		}
	},

	/**
	 * Start the Presence Service and schedule the first run of {@link #presenceTask}.
	 */
	start : function()
	{
		// Schedule the first call
		this.sendPresence();
	},

	/**
	 * Stop the Presence Service and cancel the {@link #presenceTask}.
	 */
	stop : function()
	{
		this.presenceTask.cancel();
	},

	/**
	 * Interrupt the current timeout for {@link #presenceTask} and manually
	 * invoke {@link #sendPresence} causing a new request to be send out right now.
	 */
	update : function()
	{
		this.presenceTask.cancel();
		this.sendPresence();
	},

	/**
	 * Interrupt the current timeout for {@link #presenceTask} and manually
	 * invoke {@link #sendPresence} causing a new request to be send out right now.
	 */
	refresh : function()
	{
		this.presenceGetTask.cancel();
		this.sendGetPresence();
	},

	/**
	 * Check if the watch list changed and refresh if necessary and manually
	 * invoke {@link #refresh} causing a new request to be send out right now.
	 */
	refreshIfPresenceWatchingListChanged : function()
	{
		if (this.presenceWatchingListChanged) {
			this.presenceWatchingListChanged = false;
			this.refresh();
		}
	},

	/**
	 * Obtain the next timeout value for the {@link #presenceTask}. If
	 * {@link #currentTimeout} is initialized this will double the value
	 * (restricted by {@link #maxTimeout}, or otherwise it will take {@link #timeout}.
	 * @return {Number} The timeout for the {@link #presenceTask}
	 * @private
	 */
	getNextTimeout : function()
	{
		this.currentTimeout = this.currentTimeout ? (2 * this.currentTimeout) : this.timeout;
		this.currentTimeout = Math.min(this.maxTimeout, this.currentTimeout);
		return this.currentTimeout;
	},

	/**
	 * Will update the list with online presence users in GAB, links in the mail preview and in the mail grid
	 *
	 * @param {Array} list The list with entry id's of online users
	 * @public
	 */
	updatePresenceUI: function(list) {
		// check if webapp is already initialized, if not then welcome screen is displayed and we return
		if (container.mainPanel === null || typeof container.mainPanel === 'undefined') {
			return;
		}

		if (this.webappPresenceUiSupport) {
			return;
		}

		// update presence in the address book content panel
		if(Ext.isObject(this.addressBookStore)) {
			this.updateGABContentPanel();
		}

		// update presence in the recipient links from the mail preview panel
		var recipientLinks = container.getMainPanel().findByType('zarafa.recipientlinks');

		// loop through 'to', 'cc' and 'bcc'
		recipientLinks.forEach(function(recipientType) {
			if(recipientType.isVisible()) {
				this.setStatusToRecipients(recipientType);
			}
		}, this);

		// update presence in the mail grid
		var mailGrid = container.getMainPanel().findByType('zarafa.mailgrid')[0];

		if(Ext.isObject(mailGrid)) {
			var records = mailGrid.store.getRange(),
				view = mailGrid.view;

			records.forEach(function(record, index) {
				var entryId = record.get('sender_entryid'),
					email_address = record.get('sender_email_address'),
					presenceCell = view.getRow(index).querySelector('.zarafa_mailgrid_presence_status');
				this.updatePresenceWatchingList(email_address, entryId);
				if (Ext.isObject(presenceCell)) {
					this.setMailGridStatusIcon(presenceCell, email_address, entryId);
				}
			}, this);
		}
	},

	/**
	 * Will set the icon to represent the status of spreed and xmpp
	 *
	 * @param {presenceCell} the presence cell to set the status icon on
	 * @param {String} email_address the email address for which to get the status 
	 * @private
	 */
	setMailGridStatusIcon: function(presenceCell, email_address, entryId) {
		var icon = this.getMailGridStatusIcon(email_address, entryId);

		presenceCell.classList.remove('icon_spreed_status_online_');
		presenceCell.classList.remove('icon_spreed_status_offline');

		// user is online
		if(icon) {
			presenceCell.classList.add(icon);
		}
	},

	/**
	 * Will get the icon to represent the status of spreed and xmpp
	 *
	 * @param {String} email_address the email address to get the status icon 
	 * @private
	 */
	getMailGridStatusIcon: function(email_address, entryId) {
		var online = this.isUserOnline(email_address, entryId, 'spreed');

		if(online) {
			var status_spreed = this.getUserPresence(email_address, entryId, 'spreed');
			if (status_spreed === 'available') {
				return 'icon_spreed_status_online';
			} else {
				return 'icon_spreed_status_offline';
			}
		}
	},


	/**
	 * This will check if a myself is online in Spreed.WebRTC
	 *
	 * @returns {boolean} Whether the user is online in Spreed or not
	 * @private
	 */
	myselfIsOnlineInSpreed: function() {
		var spreedwebrtcPlugin = container.getPluginByName('spreedwebrtc');

		if(Ext.isObject(spreedwebrtcPlugin)) {
			return spreedwebrtcPlugin.isOnlineInSpreed();
		} else {
			return false;
		}
	},

	/**
	 * Will either add or remove an email_address to the watch list
	 *
	 * @param {String} email_address The email address to remove or add
	 * @param {String} remove optionally remove the user from the watch list
	 * @private
	 */
	updatePresenceWatchingList: function(email_address, entryId, smtp_address, remove) {
		if (!email_address || 0 === email_address.length) { return; }
		// skip non-Kopano email addresses
		if (email_address.indexOf('@') > -1) { return; }
		var index = this.presenceWatchingList.indexOf(email_address);

		if(index === -1 && !remove) {
			this.presenceWatchingList.push(email_address);
			this.presenceWatchingListChanged = true;
		}
		else if(index > -1 && remove) {
			this.presenceWatchingList.splice(index, 1);
		}

		if (!entryId || 0 === entryId.length) { return; }
		if (Ext.isObject(this.presenceEntryIdEmailAddressMap)) {
			if (!(entryId in this.presenceEntryIdEmailAddressMap)) {
				this.presenceEntryIdEmailAddressMap[entryId] = email_address;
			}
		}

		if (!smtp_address || 0 === smtp_address.length) { return; }
		if (Ext.isObject(this.presenceSmtpAddressEmailAddressMap)) {
			if (!(smtp_address in this.presenceSmtpAddressEmailAddressMap)) {
				this.presenceSmtpAddressEmailAddressMap[smtp_address] = email_address;
			}
		}
	},

	/**
	 * This will check the user's presence status
	 *
	 * @param {String} email_address The user's email_address
	 * @returns {String} presence status string
	 * @private
	 */
	getUserPresence: function(email_address, entryId, source) {
		if (Ext.isObject(this.presenceData)) {
			if (!email_address || !email_address.length || email_address.indexOf('@') > -1) {
				// this is an empty value or a smtp address, check if we can map the entryId to a Kopano email address
				if (Ext.isObject(this.presenceEntryIdEmailAddressMap)) {
					if (entryId in this.presenceEntryIdEmailAddressMap) {
						email_address = this.presenceEntryIdEmailAddressMap[entryId];
					}
				}
			}

			if (email_address in this.presenceData) {
				if (source in this.presenceData[email_address]) {
					return this.presenceData[email_address][source]['status'];
				}
			}
		}
		return 'unknown';
	},

	/**
	 * This will check the user's presence status
	 *
	 * @param {String} email_address The user's email_address
	 * @returns {String} presence status string
	 * @private
	 */
	getUserEmailAddressFromEntryId: function(email_address, entryId) {
		if (Ext.isObject(this.presenceData)) {
			if (!email_address || !email_address.length || email_address.indexOf('@') > -1) {
				// this is an empty value or a smtp address, check if we can map the entryId to a Kopano email address
				if (Ext.isObject(this.presenceEntryIdEmailAddressMap)) {
					if (entryId in this.presenceEntryIdEmailAddressMap) {
						email_address = this.presenceEntryIdEmailAddressMap[entryId];
					}
				}
			}

		}
		return email_address;
	},

	/**
	 * This will check if the user's presence status is known
	 *
	 * @param {String} email_address The user's email_address
	 * @returns {String} presence status string
	 * @private
	 */
	isUserOnline: function(email_address, entryId, source) {
		if (Ext.isObject(this.presenceData)) {
			if (!email_address || !email_address.length || email_address.indexOf('@') > -1) {
				// this is an empty value or a smtp address, check if we can map the entryId to a Kopano email address
				if (Ext.isObject(this.presenceEntryIdEmailAddressMap)) {
					if (entryId in this.presenceEntryIdEmailAddressMap) {
						email_address = this.presenceEntryIdEmailAddressMap[entryId];
					}
				}
			}

			if (email_address in this.presenceData) {
				if (source in this.presenceData[email_address]) {
					return this.presenceData[email_address][source]['status'] !== 'unavailable';
				}
			}
		}
		return false;
	},

	/**
	 * This adds a show event handler to the recipient links for the insertion point
	 *
	 * @param {String} insertionName insertion point name that is currently populated
	 * @param {Zarafa.common.ui.messagepanel.RecipientLinks} recipientLinks The recipient links
	 * @private
	 */
	onRecipientLinksShow: function(insertionName, recipientLinks) {
		recipientLinks.on('show', this.setStatusToRecipientsHandler, this);
	},

	/**
	 * This will set the presence status of users in the recipient links and refresh status if necessary
	 *
	 * @param {Zarafa.common.ui.messagepanel.RecipientLinks} recipientLinks The recipient links
	 * @private
	 */

	setStatusToRecipientsHandler: function(recipientLinks) {
		this.setStatusToRecipients(recipientLinks);

		this.refresh();
	},

	/**
	 * This will set the presence status of users in the recipient links
	 *
	 * @param {Zarafa.common.ui.messagepanel.RecipientLinks} recipientLinks The recipient links
	 * @private
	 */
	setStatusToRecipients: function(recipientLinks) {
		var recipientLinkElements = recipientLinks.el.query('.zarafa-recipient-link');
		if (Ext.isObject(recipientLinks.store)) {
			var recipients = recipientLinks.store.getRange();

			// set recipients statuses
			recipients.forEach(function(recipient) {
				var name = recipient.get('display_name'),
					email_address = recipient.get('email_address'),
					smtp_address = recipient.get('smtp_address'),
					entryId = recipient.get('entryid');

				this.updatePresenceWatchingList(email_address, entryId, smtp_address);

				recipientLinkElements.forEach(function(element) {
					var text = element.innerHTML;
					if(text.indexOf(name) > -1 && text.indexOf(smtp_address) > -1) {
						this.setLinkStatusIcon(element, entryId, email_address);
					}
				}, this);

			}, this);
		}

		this.setStatustoSentLink();
	},

	/**
	 * This will set the status to the sent link
	 *
	 * @private
	 */
	// FIXME: this function is triggerd when the recipient links are shown but should have its own trigger
	setStatustoSentLink: function() {
		// set sender status
		var sentinfolink = container.getMainPanel().findByType("zarafa.sentinfolinks")[0];

		if(Ext.isDefined(sentinfolink)) {
			var sender = sentinfolink.record,
				entryId = sender.get('sender_entryid'),
				email_address = sender.get('sender_email_address');
				sentLinkElement = sentinfolink.el.query('.zarafa-sentinfo-link')[0];

			this.setLinkStatusIcon(sentLinkElement, entryId, email_address);
		}
	},

	/**
	 * This will set the class status for the element that hold the link in the mail preview panel
	 *
	 * @param {HtmlElement} linkElement The element for which to change the online status
	 * @param {String} entryId The user entry id
	 * @private
	 */
	setLinkStatusIcon: function(linkElement, entryId, email_address) {
		this.updatePresenceWatchingList(email_address, entryId);
		var online = this.isUserOnline(email_address, entryId, 'spreed');
		linkElement.classList.remove('icon_spreed_status_online_link');
		linkElement.classList.remove('icon_spreed_status_offline_link');
		// user is online
		if(online) {
			var status_spreed = this.getUserPresence(email_address, entryId, 'spreed');
			var status_xmpp = this.getUserPresence(email_address, entryId, 'xmpp');
			if (status_spreed === 'available') {
				linkElement.classList.add('icon_spreed_status_online_link');
			} else {
				linkElement.classList.add('icon_spreed_status_offline_link');
			}
		}
	},

	/**
	 * This will update the status of a user in the global address book content panel
	 *
	 * @private
	 */
	updateGABContentPanel: function () {
		var records = this.addressBookStore.getRange();

		for (var i = 0; i < records.length; i++) {
			var entryId = records[i].get('entryid');
			var email_address = records[i].get('email_address');
			var smtp_address = records[i].get('smtp_address');
			this.updatePresenceWatchingList(email_address, entryId);
			var online = this.isUserOnline(email_address, entryId, 'spreed');

			this.updateGABUserStatus(entryId, online ? 'online' : 'offline');
		}
	},

	/**
	 * This will update the presence status of a user in the global address book content panel
	 *
	 * @param {String} entryId The entry id of the user to update
	 * @param {String} newSpreedStatus The user status to update to: online|offline
	 * @private
	 */
	updateGABUserStatus: function (entryId, newSpreedStatus) {
		if (Ext.isObject(this.addressBookStore)) {
			var user = this.addressBookStore.find('entryid', entryId);

			if (user > -1) {
				this.addressBookStore.getAt(user).set('status_spreed', newSpreedStatus);
			}
		}
	},

	/**
	 * Event handler which is called when a new {@link Zarafa.core.ui.ContentPanel contentPanel} is created. It is used
	 * to see if it is an instance of the address book, so we can listen to its load' event.
	 *
	 * @param {Zarafa.core.ui.ContentPanel} contentPanel the new created {@link Zarafa.core.ui.ContentPanel contentPanel}
	 * @private
	 */
	onNewContentPanel: function (contentPanel) {
		var spreedPanel = contentPanel.findByType('zarafa.addressbookcontentpanel')[0];

		if (Ext.isDefined(spreedPanel)) {
			this.addressBookStore = spreedPanel.findByType('zarafa.addressbookgrid')[0].store;

			spreedPanel.mon(this.addressBookStore, 'load', this.updateGABContentPanel.createDelegate(this));
			spreedPanel.on('destroy', this.onDestroyAddressBook.createDelegate(this));
		}
	},

	/**
	 * Event handler which is called when the the address book content panel is destroyed to set the addressbook store
	 * back to null
	 */
	onDestroyAddressBook: function() {
		this.addressBookStore = null;
	},

	/**
	 * Returns the status of a user according to this plugin.	
	 * @param {Array} userInfos An object with information about the user for whom a presence
	 * status is requested.
	 * @return {Number} One of the statusses in {@link Zarafa.core.data.PresenceStatus}
	 */
	getPresenceStatuses : function(userInfos) {
		var presenceStatuses = [];
		var presenceStatus;

		for ( var i=0; i<userInfos.length; i++ ){
			if ( userInfos[i].type === 'ZARAFA' ){
				this.updatePresenceWatchingList(userInfos[i].username, userInfos[i].entryid);

				var presenceServerStatus = this.getUserPresence(userInfos[i].username, userInfos[i].entryid, 'spreed');
				if (presenceServerStatus === 'available') {
					presenceStatus = Zarafa.core.data.PresenceStatus.ONLINE;
				} else if (presenceServerStatus === 'unavailable') {
					presenceStatus = Zarafa.core.data.PresenceStatus.OFFLINE;
				} else if (presenceServerStatus === 'unknown') {
					presenceStatus = Zarafa.core.data.PresenceStatus.UNKNOWN;
				} else {
					presenceStatus = Zarafa.core.data.PresenceStatus.UNKNOWN;
				}
				this.userids[userInfos[i].username] = new Zarafa.core.data.UserIdObject({
						username: userInfos[i].username,
						type: userInfos[i].type,
						entryid: userInfos[i].entryid,
						email_address: userInfos[i].email_address
					});
			} else {
				presenceStatus = Zarafa.core.data.PresenceStatus.UNKNOWN;
			}
			//console.log(userInfos[i].username + " | " + userInfos[i].type + " | " + userInfos[i].entryid +  " | " + userInfos[i].email_address + " get " + presenceStatus)

			presenceStatuses.push(presenceStatus);
		}
		//console.log(presenceStatuses);
		return presenceStatuses;
	},

	sendUpdates : function()
	{
		var userInfos = [];

		this.presenceWatchingList.forEach(function(email_address) {
			var entryid = null;
			if (this.userids[email_address]) {
				entryid = this.userids[email_address].entryid;
			}
			var presenceServerStatus = this.getUserPresence(email_address, entryid, 'spreed');
			if (presenceServerStatus === 'available') {
				presenceStatus = Zarafa.core.data.PresenceStatus.ONLINE;
			} else if (presenceServerStatus === 'unavailable') {
				presenceStatus = Zarafa.core.data.PresenceStatus.OFFLINE;
			} else if (presenceServerStatus === 'unknown') {
				presenceStatus = Zarafa.core.data.PresenceStatus.UNKNOWN;
			} else {
				presenceStatus = Zarafa.core.data.PresenceStatus.UNKNOWN;
			}
			if (this.userids[email_address]) {
				var userInfo = {
					user: new Zarafa.core.data.UserIdObject({
						username: this.userids[email_address].username,
						type: this.userids[email_address].type,
						entryid: this.userids[email_address].entryid,
						email_address: this.userids[email_address].email_address
					}),
					status: presenceStatus
				}
				userInfos.push(userInfo);
				//console.log(email_address + " send " + presenceStatus);
			}
		}, this);


		Zarafa.core.PresenceManager.updateStatuses(this.getName(), userInfos);
	},
	/**
	 * Is called to request an authentication token
	 * @private
	 */
	requestAuthentication: function () {
		var responseHandler = new Zarafa.plugins.spreedwebrtc.data.PresenceResponseHandler();

		responseHandler.presence = this;
		container.getRequest().singleRequest('pluginspreedwebrtcmodule', "presenceauth", null, responseHandler);
	},
	/**
	 * prepareHttpRequest prepares xmlHttpRequest object
	 */
	prepareHttpRequest : function(requestData, encoded, url, method, headers, authenticationToken)
	{
		var xmlHttpRequest = new XMLHttpRequest();

		if (!url) {
			//url = this.defaultUrl;
			url = "http://192.168.112.130:1234/"
		}

		xmlHttpRequest.open(method, url, true);
		xmlHttpRequest.requestUrl = url;

		// Apply header from argument, or apply the default headers
		headers = Ext.apply({}, this.requestHeaders, headers || this.defaultHeaders);
		for (var key in headers) {
			xmlHttpRequest.setRequestHeader(key, headers[key]);
		}
		xmlHttpRequest.requestHeaders = headers;

		// Store requestData into the xmlHttpRequest, when the request failed,
		// we can still determine report the failure back to the requestee.
		xmlHttpRequest.requestData = requestData;
		xmlHttpRequest.requestDataEncoded = encoded;
		//xmlHttpRequest.queuedRequests = this.dequeueRequests();

		return xmlHttpRequest;
	},

	/**
	 * sendHttpRequest sends xmlHttpRequest object
	 */
	sendHttpRequest : function(xmlHttpRequest)
	{
		var requestData = xmlHttpRequest.requestData;
		// Register the onready StateChange event handler
		xmlHttpRequest.onreadystatechange = this.stateChange.createDelegate(this, [xmlHttpRequest]);

		// send request
		xmlHttpRequest.send(requestData);
	},

	/**
	 * Send an update Presence request 
	 * @private
	 */
	updatePresence : function()
	{
		this.authenticationToken = undefined;
		this.sendPresence();
	},

	/**
	 * Send an update Presence request 
	 * @private
	 */
	scheduleUpdatePresence : function()
	{
		// get a fresh authenticationToken
		this.authenticationToken = undefined;
		// reset the current timeout
		delete this.currentTimeout;
		// Obtain a new timeout and start polling
		var timeout = this.getNextTimeout();

		this.presenceTask.delay(this.interval);
	},

	/**
	 * Send an update Presence request 
	 * @private
	 */
	scheduleGetPresence : function()
	{
		// reset the current timeout
		delete this.currentTimeout;
		// Obtain a new timeout and start polling
		var timeout = this.getNextTimeout();

		this.presenceGetTask.delay(this.getdelay);
	},

	/**
	 * Send a Presence request to the configured {@link #url}.
	 * {@link #onStateChange} will handle the response as received from the server.
	 * @private
	 */
	sendPresence : function()
	{
		// A Presence request was already sent,
		// we will not send another one simultaneously.
		if (this.presencePending) {
			return;
		}

		if (this.authenticationToken===undefined) {
			this.requestAuthentication();
			return;
		}

		var status;

		if (this.myselfIsOnlineInSpreed()) {
			status = "available";
		} else {
			status = "unavailable";
		}

		var presenceRequest = {
			"AuthenticationToken": this.authenticationToken,
		    "Type": "UserStatus",
		    "UserStatus": [
		        {
		            "user_id": container.getUser().getUserName(),
		            "spreed": {
		                "status": status, 
		                "message": ""
		            }
		        }
		    ]
		};

		var xmlHttpRequest = this.prepareHttpRequest(Ext.encode(presenceRequest), true,this.url, 'PUT', this.headers);

		// Mark that the Presence request is currently pending.
		this.presencePending = true;

		// set the last action for this REST call
		this.lastAction = 'sendPresence';

		// Send the request
		this.sendHttpRequest(xmlHttpRequest)
	},

	/**
	 * Send a Presence request to the configured {@link #url}.
	 * {@link #onStateChange} will handle the response as received from the server.
	 * @private
	 */
	sendGetPresence : function()
	{
		// A Presence request was already sent,
		// we will not send another one simultaneously.
		if (this.presencePending) {
			return;
		}

		if (this.authenticationToken===undefined) {
			this.requestAuthentication();
			return;
		}

		var status;

		// collect the visible email addresses
		this.updatePresenceUI();

		var user_id_data = [];

		// reset the dirty flag
		this.presenceWatchingListChanged = false;

		this.presenceWatchingList.forEach(function(email_address) {
			user_id_data.push({
				"user_id": email_address
			});
		}, this);	 


		var presenceRequest = {
			"AuthenticationToken": this.authenticationToken,
		    "Type": "UserStatus",
		    "UserStatus": user_id_data
		};

		var xmlHttpRequest = this.prepareHttpRequest(Ext.encode(presenceRequest), true, this.url, 'POST', this.headers);

		// Mark that the Presence request is currently pending.
		this.presencePending = true;

		// set the last action for this REST call
		this.lastAction = 'sendGetPresence';

		// Send the request
		this.sendHttpRequest(xmlHttpRequest)
	},

	/**
	 * Called by XMLHttpRequest when a response from the server is coming in. When the entire response has been
	 * completed it calls {@link Zarafa.core.ResponseRouter#receive receive}} which handles the rest of the process.
	 * @param {Object} xmlHttpRequest The raw HTTP request object that is used for communication.
	 * @private
	 */
	stateChange : function(xmlHttpRequest)
	{
		var requestIds = xmlHttpRequest.queuedRequests;
		var responseRouter = container.getResponseRouter();
		var response;

		// The readyState can be 4 values:
		//  0 - Object is created, but not initialized
		//  1 - Request has been opened, but send() has not been called yet
		//  2 - send() has been called, no data available yet
		//  3 - Some data has been received, responseText nor responseBody are available
		//  4 - All data has been received
		//
		// readyState 0 - 3 can be completely ignored by us, as they are only updates
		// about the current progress. Only on readyState 4, should we continue and
		// start checking for the response status.
		if (xmlHttpRequest.readyState != 4) {
			return;
		}

		// Regardless of the state, the Presence request
		// is no longer pending.
		this.presencePending = false;

		// HTTP request must have succeeded
		switch (xmlHttpRequest.status) {
			case 401: /* Unauthorized */
				// Indicate that the user is no longer authenticated with a valid token
				this.failure();
				return;
			case 500: /* Internal Server Error */
				// Indicate that the request failed
				// inside the server and exit the function.
				this.failure();
				return;
			case 200: /* OK */
				break;
			default: /* Connection errors */
				this.failure();
				return;
		}

		// Depending on the response type, convert it into a data Object.
		if (xmlHttpRequest.responseText) {
			// JSON response
			response = Ext.decode(xmlHttpRequest.responseText);
		} else {
			// XML response is not supported
		}

		// PUT request responds without any data.
		if (!Ext.isEmpty(response)) {
			if (this.presenceData === undefined) {
				this.presenceData = {};
			}
			if (this.myselfIsOnlineInSpreed()) {
				response['UserStatus'].forEach(function (userdata) {
					// map data returned
					this.presenceData[userdata['user_id']] = userdata;
				}, this);
				this.sendUpdates();
			} else {
				// do not display presence info if user is not online in spreed
				this.presenceData = {};
			}
		}

		if (this.lastAction === 'sendPresence') {
			// after updating my status get user status of watched email_addresses
			// schedule the GetPresence poll
			this.scheduleGetPresence();
		} else if (this.lastAction === 'sendGetPresence') {
			// process response
			this.lastAction = undefined;

			// update the UI
			this.updatePresenceUI();

			// schedule the next poll
			this.scheduleUpdatePresence();
		}
//		responseRouter.receive(response);
	},

	/**
	 * Called when the link connection has not been restored and will be
	 * retried later. 
	 * @param {Object} response The response, if any, as received by the server
	 * @private
	 */
	failure : function(response)
	{
		var timeout = this.getNextTimeout();
		this.presenceTask.delay(timeout);
	}

});

Zarafa.onReady(function () {
	container.registerPlugin(new Zarafa.core.PluginMetaData({
		name: 'spreedpresence',
		displayName: _('SpreedPresence Plugin'),
		allowUserVisible : false,
		allowUserDisable : false,
		pluginConstructor: Zarafa.plugins.spreedwebrtc.SpreedPresence
	}));
});

Ext.namespace('Zarafa.plugins.spreedwebrtc');

/**
 *
 * @class Zarafa.plugins.spreedwebrtc.SpreedWebRTC
 * @extends Zarafa.core.Plugin
 *
 */
Zarafa.plugins.spreedwebrtc.SpreedWebRTC = Ext.extend(Zarafa.core.Plugin, {
	whatsNew : {
		version: '3.0',
		features: [{
			title: 'Web Meetings',
			description: 'Kopano Web Meetings has been enabled. You can use it to have face-to-face video calls with anyone in- and outside your organization. You can access Web Meetings by clicking the green video icon.<BR>This icon also shows your online status when you log in.',
			image_url: 'resources/img/introduction_c.jpg',
			icon_url: 'resources/icons/webmeetings_icon.png'
		},{
			title: 'Pop out to new browser window',
			description: 'Web Meetings can now be used in a separate browser window! Using this enables you to have your meeting window side-by-side with any other application and makes it easy to access your email or calendar, or work in any other application while in your web meeting!',
			image_url: 'resources/img/pop_out_c.jpg',
			icon_url: 'resources/icons/webmeetings_icon.png'
		},{
			title: 'Control panel',
			description: 'The Web Meetings button has been extended with sound control and direct meeting room access features.',
			image_url: 'resources/img/control_panel_c.jpg',
			icon_url: 'resources/icons/webmeetings_icon.png'
		}]
	},

	/**
	 * Reference to the spreed plugin button
	 *
	 * @type {object}
	 * @private
	 */
	spreedButton: null,

	/**
	 * Reference to the spreed plugin external window
	 *
	 * @type {object}
	 * @private
	 */
	spreedExternalWindow: null,

	/**
	 * Reference to the spreed plugin window for Main
	 *
	 * @type {object}
	 * @private
	 */
	spreedWebRTCWindowRoomMain: null,

	/**
	 * Reference to the spreed plugin window for Meeting Request
	 *
	 * @type {object}
	 * @private
	 */
	spreedWebRTCWindowRoomMeetingRequest: null,

	/**
	 * Reference to the spreed plugin window for Instant Meetings
	 *
	 * @type {object}
	 * @private
	 */
	spreedWebRTCWindowRoomInstantMeeting: null,

	/**
	 * List of references to the spreed plugin windows
	 *
	 * @type {object}
	 * @private
	 */
	spreedWebRTCWindows: null,

	/**
	 * Reference to the spreed plugin volume button
	 *
	 * @type {object}
	 * @private
	 */
	spreedVolumeButton: null,

	/**
	 * The domain origin of the spreed server
	 * (used for postMessage origin check)
	 *
	 * @type {string}
	 * @private
	 */
	spreedDomain: '',

	/**
	 * Maintains a list of persistent notifiers
	 *
	 * @type {object}
	 * @private
	 */
	persistentNotifiers: {},

	/**
	 * Maintains a list of spreed users that are online
	 *
	 * @type {Array}
	 * @private
	 */
	presenceList: [],

	/**
	 * notification element for meeting URL request
	 *
	 * @property
	 * @type Ext.Element
	 * @private
	 */
	notifyEl: undefined,

	/**
	 * Maintains the state is we are running in DeskApp
	 *
	 * @type {boolean}
	 * @private
	 */
	isRunningInDeskapp: false,

	/**
	 * Maintains the state if we are performing a popout
	 *
	 * @type {boolean}
	 * @private
	 */
	popingOut: false,

	/**
	 * Maintains the state if we are going offline
	 *
	 * @type {boolean}
	 * @private
	 */
	goingOffline: false,

	/**
	 * Maintains the state if we should show the iframe
	 *
	 * @type {boolean}
	 * @private
	 */
	showSpreedWebRTC: false,

	/**
	 * Constructor
	 * @protected
	 */

	constructor: function (config) {
		config = config || {};

		Zarafa.plugins.spreedwebrtc.SpreedWebRTC.superclass.constructor.call(this, config);
	},

	/**
	 * Called after constructor.
	 * Registers insertion points.
	 * @protected
	 */
	initPlugin: function () {
		if (!window.location.origin) {
			// Polyfill for IE which does not support location.origin.
			window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
		}

		var spreedDomain = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/domain/');
		this.spreedDomain = spreedDomain ? spreedDomain : window.location.origin;
		this.registerInsertionPoint('context.settings.categories', this.createSettingCategories, this);
		this.registerInsertionPoint('main.toolbar.actions.last', this.createToolBarButton, this);
		this.registerInsertionPoint('context.addressbook.contextmenu.actions', this.createContextItemSpreedChat, this);
		this.registerInsertionPoint('context.addressbook.contextmenu.actions', this.createContextItemSpreedMessage, this);
		this.registerInsertionPoint('context.common.recipientfield.contextmenu.actions', this.createContextItemSpreedChat.createDelegate(this), this);
		this.registerInsertionPoint('context.common.recipientfield.contextmenu.actions', this.createContextItemSpreedMessage.createDelegate(this), this);
		this.registerInsertionPoint('context.mail.contextmenu.options', this.createContextItemSpreedChat, this);
		this.registerInsertionPoint('context.mail.contextmenu.options', this.createContextItemSpreedMessage, this);
		this.registerInsertionPoint('context.calendar.appointmentcontentpanel.toolbar.actions', this.createNewSpreedWebRTCMeetingURLFromAppointmentButton, this);
		this.registerInsertionPoint('context.calendar.appointmentcontentpanel.toolbar.actions', this.createOpenSpreedWebRTCMeetingURLFromAppointmentButton, this);
		this.registerInsertionPoint('context.mail.mailcreatecontentpanel.toolbar.actions', this.createNewSpreedWebRTCMeetingURLFromMailcreateButton, this);

		// Change the tinyMCE config a little, because we want to be able to style <a> tags
		this.registerInsertionPoint('common.htmleditor.tinymceconfig', this.setTinymceConfig, this);

		Zarafa.core.data.SharedComponentType.addProperty('plugin.spreedwebrtc.dialog.spreedwindow');

		// Listen to post message events from Spreed
		window.addEventListener('message', this.onPostMessage.bind(this));

		// When the browser is unloading, all external spreed.webrtc windows will be closed.
		window.addEventListener('unload', this.onUnload.createDelegate(this));

		Zarafa.plugins.spreedwebrtc.SpreedWebRTC.superclass.initPlugin.apply(this, arguments);
	},

	/**
	 * Create the files {@link Zarafa.settings.SettingsMainCategory Settings Category}
	 * to the {@link Zarafa.settings.SettingsContext}. This will create new
	 * {@link Zarafa.settings.ui.SettingsCategoryTab tabs} for the
	 * {@link Zarafa.plugins.spreedwebrtc.settings.SettingsWebmeetingsCategory Webmeetings Plugin}.
	 * @return {Object} configuration object for the categories to register
	 */
	createSettingCategories: function () {
		return {
			xtype: 'spreedwebrtc.settingsmaincategory'
		}
	},

	/**
	 * As soon as the spreed button is rendered this will do some initialization. It will also automatically start the
	 * plugin if set in config.php
	 *
	 * @param {Ext.Button} button The spreed button
	 */
	initSpreed: function (button) {
		this.spreedButton = button;
		if (Ext.isDefined(window.deskappOpenWindow)) {
			this.isRunningInDeskapp = true;
		}

		if (container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/autostart/')) {
			var button_menu_items = button.menu.items;
			this.spreedWebRTCWindowRoomMain           = new Zarafa.plugins.spreedwebrtc.SpreedWebRTCWindow;
			this.spreedWebRTCWindowRoomMain.setButton(button_menu_items.get('spreed_main_room_menu_item'));
			this.spreedWebRTCWindowRoomMain.setSpreedDomain(this.spreedDomain);
			this.spreedWebRTCWindowRoomMeetingRequest = new Zarafa.plugins.spreedwebrtc.SpreedWebRTCWindow;
			this.spreedWebRTCWindowRoomMeetingRequest.setButton(button_menu_items.get('spreed_meeting_request_room_menu_item'));
			this.spreedWebRTCWindowRoomMeetingRequest.setSpreedDomain(this.spreedDomain);
			this.spreedWebRTCWindowRoomInstantMeeting = new Zarafa.plugins.spreedwebrtc.SpreedWebRTCWindow;
			this.spreedWebRTCWindowRoomInstantMeeting.setButton(button_menu_items.get('spreed_instant_meeting_room_menu_item'));
			this.spreedWebRTCWindowRoomInstantMeeting.setSpreedDomain(this.spreedDomain);
			this.spreedWebRTCWindows = [
				this.spreedWebRTCWindowRoomMain,
				this.spreedWebRTCWindowRoomMeetingRequest,
				this.spreedWebRTCWindowRoomInstantMeeting
				];

			this.spreedVolumeButton = button_menu_items.get('spreed_webrtc_volume');
			this.setSpreedWebRTCWindowsSoundSettings();

			this.createOpenSpreedWebRTC();

			// Workaround to hide close button because panel.tools not mapped in UIFactoryWindowLayer.js
			// this.spreedWindow.ownerCt.closable=false;
			// this.spreedWindow.ownerCt.tools.close.hide();
			// Note: for the spreed iframe to be constructed the show method of the window in UIFactoryWindowLayer
			// needs so called. Here we hide it again immediately. It's not pretty but it works.
			this.spreedWebRTCWindowRoomMain.hideSpreedWebRTC();
		}
	},

	/**
	 * This wil reset some properties when the user closes the spreed window
	 *
	 * @public
	 */
	reset: function() {
		this.spreedWebRTCWindowRoomMain.spreedWindow = null;
		this.spreedButton.setIconClass('icon_spreed_webrtc');
		this.presenceList = [];
		this.updatePresenceList();
	},

	/**
	 * Update spreed button in the main toolbar to indicate if call in progress
	 *
	 */
	updateInCallState: function() {
		var callInProgress = false;
		var spreedWindowOpen = false;
		this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
			if (spreedWebRTCWindow.isInCall()) {
				callInProgress = true;
			}
			if (spreedWebRTCWindow.isWindowOpen()) {
				spreedWindowOpen = true;
			}
		}, this);
		if (callInProgress) {
			this.spreedButton.setIconClass('icon_spreed_webrtc_incall');
		} else {
			if (spreedWindowOpen) {
				this.spreedButton.setIconClass('icon_spreed_webrtc_active');
			} else {
				this.spreedButton.setIconClass('icon_spreed_webrtc');
			}
		}
	},

	/**
	 * Creates a button in the main toolbar to create/open the spreed plugin
	 *
	 * @return {Object} Object with the spreed button definition
	 * @private
	 */
	createToolBarButton: function () {
		return  [{
			newMenuIndex: 10,
			xtype: 'splitbutton',
			scale: 'large',
			listeners: {
				afterrender: function (button) {
					container.getPluginByName('spreedwebrtc').initSpreed(button);
				}
			},
			tooltip: _('Kopano Web Meetings'),
			iconCls: 'icon_spreed_webrtc',
			handler: this.createOpenSpreedWebRTC,
			scope: this,
			menu: [{
					id: 'spreed_main_room_menu_item',
					overflowText: _('Kopano Web Meetings'),
					iconCls: 'icon_spreed_webrtc_menu_inactive',
					text: _('Kopano Web Meetings'),
					handler: this.focusSpreedWebRTCMeetingRoomMain,
					disabled: true,
					scope: this
				},{
					id: 'spreed_meeting_request_room_menu_item',
					overflowText: _('Kopano Web Meetings meeting request room'),
					iconCls: 'icon_spreed_webrtc_menu_inactive',
					text: _('Meeting request room'),
					handler: this.focusSpreedWebRTCMeetingRoomMeetingRequest,
					disabled: true,
					scope: this
				},{
					id: 'spreed_instant_meeting_room_menu_item',
					overflowText: _('Kopano Web Meetings instant meeting room'),
					iconCls: 'icon_spreed_webrtc_menu_inactive',
					text: _('Instant meetings room'),
					handler: this.focusSpreedWebRTCMeetingRoomInstantMeeting,
					disabled: true,
					scope: this
				},{
					id: 'spreed_webrtc_volume',
					overflowText: _('Sound control'),
					iconCls: 'icon_spreed_webrtc_volume_high',
					text: _('Sound control'),
					scope: this,
					menu: [{
							id: 'spreed_webrtc_volume_high',
							overflowText: _('All notifications'),
							iconCls: 'icon_spreed_webrtc_volume_high',
							text: _('All sounds'),
							handler: this.onWebmeetingsSelectVolume,
							scope: this
						},{
							id: 'spreed_webrtc_volume_low',
							overflowText: _('Only incoming sounds'),
							iconCls: 'icon_spreed_webrtc_volume_low',
							text: _('Only incoming sounds'),
							handler: this.onWebmeetingsSelectVolume,
							scope: this
						},{
							id: 'spreed_webrtc_volume_mute',
							overflowText: _('No sounds'),
							iconCls: 'icon_spreed_webrtc_volume_mute',
							text: _('No sounds'),
							handler: this.onWebmeetingsSelectVolume,
							scope: this
						}]

				}]
			}];
	},

	/**
	 * Will add an extra item to some context menu's for starting a spreed chat
	 *
	 * @returns {Object} insertionName The context menu item
	 * @private
	 */
	createContextItemSpreedChat: function(insertionName) {
		return {
			xtype: 'zarafa.conditionalitem',
			text: _('Start video call'),
			overflowText : _('Start video call'),
			iconCls : 'icon_spreed_videocall_context_menu_item',
			singleSelectOnly: true,
			handler: this.startSpreedMeeting,
			insertionName: insertionName,
			beforeShow: this.setContextItemVisibility,
			scope: this
		};
	},

	/**
	 * Will add an extra item to some context menu's for sending a spreed message
	 *
	 * @returns {Object} insertionName The context menu item
	 * @private
	 */
	createContextItemSpreedMessage: function(insertionName) {
		return {
			xtype: 'zarafa.conditionalitem',
			text: _('Start chat'),
			overflowText : _('Start chat'),
			iconCls : 'icon_spreed_textchat_context_menu_item',
			singleSelectOnly: true,
			handler: this.sendSpreedMessage,
			insertionName: insertionName,
			beforeShow: this.setContextItemVisibility,
			scope: this
		};
	},

	/**
	 * Will set the visibility of the spreed conditional menu button
	 *
	 * @param {Zarafa.core.ui.menu.ConditionalItem} item The item which is about to be shown.
	 * @param {Zarafa.core.data.MAPIRecord} record The record which is being shown for this menu
	 * @private
	 */
	setContextItemVisibility: function(item, records) {
		var record = records[0] || records,
			online = false,
			// for the mail grid context menu get the 'from id' instead of entry id
			entryId = item.insertionName === "context.mail.contextmenu.options"  ? record.get('sender_entryid') : record.get('entryid'),
			email_address = item.insertionName === "context.mail.contextmenu.options"  ? record.get('sender_email_address') : record.get('email_address'),
			userId = container.getUser().meta.entryid,
			presencePlugin = container.getPluginByName('spreedpresence');

		if(Ext.isObject(presencePlugin)) {
			online = presencePlugin.isUserOnline(email_address, entryId, 'spreed');
		}
		item.setVisible(online && entryId !== userId);
	},

	/**
	 * Create a button in action toolbar of the Appointment dialog. This will set the
	 * location to the URL of the registered meeting.
	 *
	 * @return {Ext.Button} Button instance
	 * @private
	 */
	createNewSpreedWebRTCMeetingURLFromAppointmentButton : function()
	{
		return {
			xtype : 'button',
			text : _('Add web meeting'),
			iconCls : 'icon_spreed_webmeeting_button',
			handler : this.createNewSpreedWebRTCMeetingURLFromAppointment,
			scope : this,
			plugins : ['zarafa.recordcomponentupdaterplugin'],
			update : function(record, contentReset) {
				this.record = record;
			}
		};
	},

	isNewSpreedWebRTCMeetingURLFromAppointmentButtonVisible : function(record)
	{
		return true;
	},

	createNewSpreedWebRTCMeetingURLFromAppointment : function(btn)
	{
		var appointment = btn.record;
		var editorField = btn.ownerCt.ownerCt.appointmentTab.editorField
		var subject = appointment.get('subject');
		var commonstart = appointment.get('commonstart');
		var commonstart_time = commonstart ? commonstart.getTime() : null;
		var responseHandler = new Zarafa.plugins.spreedwebrtc.data.SpreedWebrtcResponseHandler();

		// no longer force user to enter a subject
		if (false && !subject) {
			Ext.MessageBox.show({
				title: _('Kopano Web Meetings'),
				msg: _('Please set a subject before creating an Web Meetings meeting request.'),
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.INFO
			});
			return;
		}

		responseHandler.appointment = appointment;
		responseHandler.editorField = editorField;
		responseHandler.plugin = this;
		responseHandler.scope = this.spreedWebRTCWindowRoomMeetingRequest;
		this.displayInfoMask();
		container.getRequest().singleRequest('pluginspreedwebrtcmodule', "meetingurl", {'start': commonstart_time}, responseHandler);
	},

	/**
	 * Create a button in action toolbar of the Appointment dialog. This will open the
	 * location of the URL of the registered meeting in an external window.
	 *
	 * @return {Ext.Button} Button instance
	 * @private
	 */
	createOpenSpreedWebRTCMeetingURLFromAppointmentButton : function()
	{
		return {
			xtype : 'button',
			ref : 'openSpreedWebRTCMeetingBtn',
			text : _('Join web meeting'),
			iconCls : 'icon_spreed_webmeeting_button',
			handler : this.openSpreedWebRTCMeetingURLFromAppointment,
			scope : this,
			plugins : ['zarafa.recordcomponentupdaterplugin'],
			update : function(record, contentReset) {
				this.record = record;
				var appointment = record;

				if (appointment.get('location')) {
					this.setDisabled(false);
				} else {
					this.setDisabled(true);
				}
			}
		};
	},

	/**
	 * Updates the config for tinymce. We need to make sure that we can add styling to a-tags,
	 * because we need to style the Web Meetings invitation.
	 * @param {String} insertionPoint The insertionpoint that called this function
	 * @param {Object} tinymceConfig The configuration object that WebApp will use to initialize
	 * the tinymce editor.
	 */
	setTinymceConfig : function(insertionPoint, tinymceConfig){
		var anchorRe = /(^|\s|,)(a\[(.*?)\])/;

		if ( Ext.isEmpty(tinymceConfig.config.extended_valid_elements) ){
			tinymceConfig.config.extended_valid_elements = '';
		}

		var matches = tinymceConfig.config.extended_valid_elements.match(anchorRe);
		if ( Ext.isEmpty(matches) ){
			if ( !Ext.isEmpty(tinymceConfig.config.extended_valid_elements) ){
				tinymceConfig.config.extended_valid_elements += ',';
			}
			tinymceConfig.config.extended_valid_elements += 'a[class|name|href|target|title|onclick|style]';
		} else {
			if ( matches[3].match(/\bstyle\b/gi) ){
				// style is already allowed as attribute for a-tags
				return;
			}
			tinymceConfig.config.extended_valid_elements = tinymceConfig.config.extended_valid_elements.replace(matches[2], 'a['+matches[3]+'|style]');
		}

	},

	isOpenSpreedWebRTCMeetingURLFromAppointmentButtonVisible : function(record)
	{
		var appointment = record;

		if (appointment.get('location')) {
			return true;
		} else {
			return false;
		}
	},

	openSpreedWebRTCMeetingURLFromAppointment : function(btn)
	{
		var appointment = btn.record;
		var subject = appointment.get('subject');
		var location = appointment.get('location');

		if (!subject) {
			// default subject to Untitled
			subject = _('Untitled');
		}

		if (!this.spreedWebRTCWindowRoomMeetingRequest.isWindowOpen()) {
			this.spreedWebRTCWindowRoomMeetingRequest.createOpenSpreedWebRTC(subject, location);
		} else {
			Ext.MessageBox.show({
				title: _('Kopano Web Meetings'),
				msg: _('Your Web Meetings meeting request room is currently in use.'),
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.INFO
			});
			return;
		}
	},

	/**
	 * this will display to the user that the web meetings URL is being requested.
	 * @protected
	 */
	displayInfoMask : function()
	{
		if (!this.notifyEl) {
			this.notifyEl = container.getNotifier().notify('info.saving', _('Web meetings'), _('requesting web meetings URL, please be patient ...'), {
				persistent : true
			});
		}
	},

	/**
	 * If {@link #displayInfoMask} has been called, this will remove the notification again.
	 * if the request has been successfull, a new notification will be shown to display that
	 * the location is set to the URL.
	 * @param {Boolean} success false to disable the display of the URL created message.
	 * @protected
	 */
	hideInfoMask : function(success)
	{
		if (this.notifyEl) {
			container.getNotifier().notify('info.saving', null, null, {
				destroy : true,
				reference : this.notifyEl
			});
			delete this.notifyEl;

			if (success !== false) {
				var notifyEl = container.getNotifier().notify('info.saved', _('The URL for your web meeting is created.'), _('The link is pasted into your mail and the ‘Location’ field. You can open the URL in a new window in case your browser is blocking pop-ups.'), {
					persistent : true
				});
				setTimeout(function() {
					if (notifyEl) {
						container.getNotifier().notify('info.saved', null, null, {
							destroy : true,
							reference : notifyEl
						});
						delete notifyEl;
					}
				}, 10000);
			}
		}
	},

	/**
	 * Create a button in action toolbar of the Mailcreate dialog. This will set the
	 * location to the URL of the registered meeting.
	 *
	 * @return {Ext.Button} Button instance
	 * @private
	 */
	createNewSpreedWebRTCMeetingURLFromMailcreateButton : function()
	{
		return {
			xtype : 'button',
			text : _('Add web meeting'),
			iconCls : 'icon_spreed_webmeeting_button',
			handler : this.createNewSpreedWebRTCMeetingURLFromMailcreate,
			scope : this,
			plugins : ['zarafa.recordcomponentupdaterplugin'],
			update : function(record, contentReset) {
				this.record = record;
			}
		};
	},

	isNewSpreedWebRTCMeetingURLFromMailcreateButtonVisible : function(record)
	{
		return true;
	},

	createNewSpreedWebRTCMeetingURLFromMailcreate : function(btn)
	{
		var mailcreate = btn.record;
		var editorField = btn.ownerCt.ownerCt.editorField;
		var subject = mailcreate.data.subject;
		var start = new Date();
		var start_time = start.getTime();
		var responseHandler = new Zarafa.plugins.spreedwebrtc.data.SpreedWebrtcResponseHandler();

		// no longer force user to enter a subject
		if (false && !subject) {
			Ext.MessageBox.show({
				title: _('Kopano Web Meetings'),
				msg: _('Please set a subject before creating an instant meeting.'),
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.INFO
			});
			return;
		} else if (!subject) {
			// default subject to Untitled
			subject = _('Untitled');
		}

		if (!this.spreedWebRTCWindowRoomInstantMeeting.isWindowOpen()) {
			this.spreedWebRTCWindowRoomInstantMeeting.createOpenSpreedWebRTC(subject, '');
			responseHandler.openSpreedWebRTCMeetingURLForMailcreate = this.spreedWebRTCWindowRoomInstantMeeting.setSpreedWebRTCUrlAndFocus;
		} else {
			Ext.MessageBox.show({
				title: _('Kopano Web Meetings'),
				msg: _('Your instant meeting room is currently in use.'),
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.INFO
			});
			return;
		}
		responseHandler.editorField = editorField;
		responseHandler.plugin = this;
		responseHandler.scope = this.spreedWebRTCWindowRoomInstantMeeting;
		this.displayInfoMaskMailcreate();
		container.getRequest().singleRequest('pluginspreedwebrtcmodule', "meetingurl", {'start': start_time}, responseHandler);
	},

	/**
	 * this will display to the user that the web meetings URL is being requested.
	 * @protected
	 */
	displayInfoMaskMailcreate : function()
	{
		if (!this.notifyEl) {
			this.notifyEl = container.getNotifier().notify('info.saving', _('Web meetings'), _('requesting web meetings URL, please be patient ...'), {
				persistent : true
			});
		}
	},

	/**
	 * If {@link #displayInfoMask} has been called, this will remove the notification again.
	 * if the request has been successfull, a new notification will be shown to display that
	 * the location is set to the URL.
	 * @param {Boolean} success false to disable the display of the URL created message.
	 * @protected
	 */
	hideInfoMaskMailcreate : function(success)
	{
		if (this.notifyEl) {
			container.getNotifier().notify('info.saving', null, null, {
				destroy : true,
				reference : this.notifyEl
			});
			delete this.notifyEl;

			if (success !== false) {
				var notifyEl = container.getNotifier().notify('info.saved', _('The URL for your web meeting is created.'), _('The link is pasted into your mail. You can open the URL in a new window in case your browser is blocking pop-ups.'), {
					persistent : true
				});
				setTimeout(function() {
					if (notifyEl) {
						container.getNotifier().notify('info.saved', null, null, {
							destroy : true,
							reference : notifyEl
						});
						delete notifyEl;
					}
				}, 10000);
			}
		}
	},

	/**
	 * this will display to the user that the web meetings is offline
	 * @protected
	 */
	displayInfoWebmeetingsIsOffline : function()
	{
		var notifyEl = container.getNotifier().notify('info.saved', _('Web meetings'), _('You are offline in Web Meetings'), {
			persistent : true
		});
		setTimeout(function() {
			if (notifyEl) {
				container.getNotifier().notify('info.saved', null, null, {
					destroy : true,
					reference : notifyEl
				});
				delete notifyEl;
			}
		}, 10000);
	},

	/**
	 * checks if the user is online in spreed
	 */
	isOnlineInSpreed: function(list) {
		// set this user's status to available only if he is online in spreed
		if(this.spreedWebRTCWindowRoomMain && this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
			// TODO: set online status by postMessage API from Spreed.WebRTC
			return true;
		} else {
			return false;
		}
	},

	/**
	 * Handles the post message data from spreed when it updates the list with online users
	 *
	 * @param {Array} list The list with entry id's
	 * @private
	 */
	refreshPresenceList: function(list) {
		var presencePlugin = container.getPluginByName('spreedpresence');

		if(Ext.isObject(presencePlugin)) {
			this.presenceList = list.slice();
			// add the user to the online list only if he is online
			if(this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
				this.presenceList.push(container.getUser().meta.entryid);
			}
			presencePlugin.updatePresence(this.presenceList);
		}
	},

	/**
	 * Will either remove an entry id or add it, depending on the status (resp: offline & online)
	 *
	 * @param {String} entryId The entry id to remove or add
	 * @param {String} status The status of the user
	 * @private
	 */
	updatePresenceList: function(entryId, status) {
		var presencePlugin = container.getPluginByName('spreedpresence'),
			index = this.presenceList.indexOf(entryId);

		if(Ext.isObject(presencePlugin)) {
			if(index === -1 && status === 'online') {
				this.presenceList.push(entryId);
			}
			else if(index > -1 && status === 'offline') {
				this.presenceList.splice(index, 1);
			}
			presencePlugin.updatePresence(this.presenceList);
			presencePlugin.update();
		}
	},

	/**
	 * Is called when the plugin on the spreed server requests authorisation
	 * @private
	 */
	requestAuthentication: function () {
		var responseHandler = new Zarafa.plugins.spreedwebrtc.data.SpreedWebrtcResponseHandler();

		responseHandler.spreedWebRTCWindow = this.spreedWebRTCWindowRoomMain;
		container.getRequest().singleRequest('pluginspreedwebrtcmodule', "authenticate", null, responseHandler);
	},

	/**
	 * Notifies the user of spreed events, which are sent through postMessage calls.
	 * These events are about chat messages and calls.
	 *
	 * @param {string} notificationType The type of notification we're dealing with
	 * @param {object} from An object containing info about the 'from' user, like name and id
	 * @private
	 */
	notify: function (notificationType, from, roomid) {
		if(Ext.isDefined(from)) {
			var name = from.displayName;
			var notifierId = notificationType + '_' + from.id + '_' + roomid;
		}

		switch (notificationType) {
			case "chatmessage":
				this.displayNotification(_('New chat message from ') + name, notifierId, true, true, roomid);
				break;
			case "incomingpickuptimeout":
				this.displayNotification(_('Missed call from ') + name, notifierId, true, true, roomid);
				this.destroyNotifier('incoming_' + from.id, this.persistentNotifiers['incoming_' + from.id + '_' + roomid].element);
				break;
			case "incoming":
				this.displayNotification(_('Incoming call from ') + name, notifierId, true, false, roomid);
				break;
			case "busy":
				this.displayNotification(name  + _(' is busy'), notifierId, false, false, roomid);
				break;
			case "reject":
				this.displayNotification(name  + _(' rejected your call'), notifierId, false, false, roomid);
				break;
			case "pickuptimeout":
				this.displayNotification(name  + _(' does not pick up'), notifierId, false, false, roomid);
				break;
			case 'refusedoraccepted':
				this.destroyIncomingNotifiers();
				break;
		}
	},

	/**
	 * This will set the notification messages
	 * *
	 * @param {String} message The message to display
	 * @param {String} notifierId The id by which the notifier is referenced
	 * @param {Boolean} persistent True if the notifier needs to be persistent
	 * @param {Boolean} [displayCount] True if the notifier needs to show a count of the notify event
	 * @param {String} roomid The roomid from which the notification came from
	 * @private
	 */
	displayNotification: function(message, notifierId, persistent, displayCount, roomid) {
		if (persistent) {
			// We have a persistent notification. Applies to missed calls and chat messages
			if (!Ext.isDefined(this.persistentNotifiers[notifierId])) {
				this.persistentNotifiers[notifierId] = {};
				this.persistentNotifiers[notifierId].updateCount = 1;
				this.persistentNotifiers[notifierId].roomid = roomid;
			}

			if(displayCount) {
				message += ' (' + this.persistentNotifiers[notifierId].updateCount + ')';
			}

			this.persistentNotifiers[notifierId].updateCount += 1;
			this.persistentNotifiers[notifierId].element = container.getNotifier().notify('info.spreednotifier', _('Web Meetings'), message, {
				persistent: true,
				update: this.persistentNotifiers[notifierId].element,
				reference: this.persistentNotifiers[notifierId].element,
				listeners: {
					click: this.destroyNotifier.bind(this, notifierId)
				}
			});
		}
		else {
			// For the other types of notifications we just have disappearing notifications
			container.getNotifier().notify('info.spreednotifier', _('Web Meetings'), message, {
				persistent: false,
				listeners: {
					click: this.destroyNotifier.bind(this, notifierId)
				}
			});
		}
	},

	/**
	 * Event handler for destroying notifiers
	 *
	 * @param {String} notifierId The id of the notifier
	 * @param {Element} element The notifier element
	 * @private
	 */
	destroyNotifier: function (notifierId, element) {
		var roomid;
		if (this.persistentNotifiers[notifierId]) {
			roomid = this.persistentNotifiers[notifierId].roomid;
			this.persistentNotifiers[notifierId] = null;
			delete this.persistentNotifiers[notifierId];
		}

		this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
			if (spreedWebRTCWindow.inRoomid(roomid)) {
				spreedWebRTCWindow.focusSpreedWebRTC(true);
			}
		}, this);

		container.getNotifier().notify('info.spreednotifier', null, null, {
			reference: element,
			destroy: true
		});
	},

	/**
	 * This function will destroy the notifiers for incoming calls. These notifiers are persistent and will only close
	 * once the call has been accepted or rejected
	 *
	 * @private
	 */
	destroyIncomingNotifiers: function() {
		var notifiers = this.persistentNotifiers;

		for (id in notifiers) {
			if(id.indexOf('incoming') === 0) {
				this.destroyNotifier(id, notifiers[id].element);
			}
		}
	},

	/**
	 * Event handler for opening the Spreed WebRTC in the requested iframe or external window
	 *
	 * @param {Ext.Button} button The button which was clicked
	 * @private
	 */
	createOpenSpreedWebRTC: function (button) {
		var last_start_in_iframe = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe');
		var last_start_in_external_window = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window');

		if (!this.isRunningInDeskapp) {
			last_start_in_iframe = true;
			last_start_in_external_window = false;
		} else if (!last_start_in_iframe && !last_start_in_external_window) {
			if (button && !this.spreedWebRTCWindowRoomMain.isInCallActivity()) {
				this.showSpreedWebRTC = true;
				if(!this.spreedWebRTCWindowRoomMain.isWindowVisible()) {
					if (!this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
						this.initSpreedInIFrame(true);
					} else {
						this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC();
					}
					this.requestInitSpreedInExternalBrowserWindow();
					return;
				}
			} else {
				last_start_in_iframe = true;
				last_start_in_external_window = false;
			}
		}

		if (!last_start_in_iframe) { // open in external window
			if (!this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
				if (this.isRunningInDeskapp) {
					this.initSpreedInExternalBrowserWindow(this.spreedButton);
				} else {
					if (!button) {
						this.displayInfoWebmeetingsIsOffline();
					} else if (!last_start_in_external_window && !last_start_in_iframe) {
						this.requestInitSpreedInExternalBrowserWindow();
					} else {
						this.initSpreedInExternalBrowserWindow(this.spreedButton);
					}
				}
			} else {
				this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC();
			}
		} else {    // open in iframe
			if (!this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
				this.initSpreedInIFrame(true);
			} else {
				this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC();
			}
		}
	},

	/**
	 * Check if necessary to configure settings for opening the Spreed WebRTC in the requested iframe or external window
	 *
	 */
	checkRequestInitSpreedInExternalBrowserWindow: function () {
		var last_start_in_iframe = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe');
		var last_start_in_external_window = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window');

		if (this.isRunningInDeskapp && !last_start_in_iframe && !last_start_in_external_window &&
				!this.spreedWebRTCWindowRoomMain.isInCallActivity()) {
			this.showSpreedWebRTC = this.spreedWebRTCWindowRoomMain.isWindowVisible();
			this.requestInitSpreedInExternalBrowserWindow();
		}
	},

	/**
	 * This will check if the user wishes to load Web Meetings in an external window or not.
	 * @private
	 */
	requestInitSpreedInExternalBrowserWindow : function()
	{
		var message = "";
		var last_start_in_iframe = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe');
		var last_start_in_external_window = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window');
		if (last_start_in_iframe) {
			message += _('You selected Web Meetings to be launched inside WebApp during the previous launch.') +'<br>';
		} else if (last_start_in_external_window) {
			message += _('You selected Web Meetings to be launched in a new browser window during the previous launch.') +'<br>';
		} else {
			message += _('The latest version of Kopano Web Meetings has a new feature.') +'<br>';
		}

		message = message + _('You can now choose where to open Web Meetings by default.') + '<br>';
		message = message + '<br>';
		message = message + _('Open your webmeeting by default in a:');

		Zarafa.plugins.spreedwebrtc.dialogs.SettingsMessageBox.settingsMessageBox(
			_('Kopano Web Meetings'),
			_('The latest version of Kopano Web Meetings has a new feature.'), // + "\n" +
			_('You can now choose where to open Web Meetings by default:'),
			[{
				boxLabel: _('In Deskapp') + ' <span class="k-spreed-transparency50">(' + _('current behaviour') + ')</span>',
				id : 'iframe',
				name: 'select',
				checked: true
			},{
				boxLabel: _('In a new window'),
				id : 'popout',
				name: 'select'
			}],
			null,
			_('You can always edit this configuration in : Settings -> Web Meetings'),
			[{
				text : _('Apply'),
				name : 'apply'
			}],
			this.onRequestInitSpreedInExternalBrowserWindow,
			this
		);
	},

	/**
	 * Event handler for {@link #requestInitSpreedInExternalBrowserWindow}.
	 * This will check if the user wishes to load Web Meetings in an external window or not.
	 * @param {String} button The button which the user pressed^
	 * @private
	 */
	onRequestInitSpreedInExternalBrowserWindow : function(button, message_box) {
		// save do not show this message again choice
		if(button === 'apply') {
			var radioGroupValue = message_box.radioGroup.getValue().id;
			if (radioGroupValue == 'popout') {
				container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe', false);
				container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window', true);
				if (!this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
					this.initSpreedInExternalBrowserWindow(this.spreedButton);
				} else if (this.spreedWebRTCWindowRoomMain.isIFrameWindow()) {
					this.popoutSpreedInExternalBrowserWindow();
				} else if (this.showSpreedWebRTC && !this.spreedWebRTCWindowRoomMain.isWindowVisible()) {
					this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC();
				}
			} else {
				container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe', true);
				container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window', false);
				if (!this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
					this.initSpreedInIFrame(this.showSpreedWebRTC);
				} else if(this.showSpreedWebRTC && !this.spreedWebRTCWindowRoomMain.isWindowVisible()) {
					this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC();
				}
			}
		} else {
			if (!this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
				this.initSpreedInIFrame(this.showSpreedWebRTC);
			} else if(this.showSpreedWebRTC && !this.spreedWebRTCWindowRoomMain.isWindowVisible()) {
				this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC();
			}
		}
		this.showSpreedWebRTC = false;
	},

	/**
	 * This will check if the user wishes to reopen Web Meetings and choose in external window or not.
	 * @private
	 */
	requestToReopenSpreedWindow : function()
	{
		var message = _('You have closed Web Meetings and are now offline.') +'<br>'+ _(' Do you wish to reopen and choose where to open Web Meetings or do you wish to remain offline?');

		Zarafa.common.dialogs.MessageBox.addCustomButtons({
			title: _('Kopano Web Meetings'),
			msg : message,
			icon : Ext.MessageBox.QUESTION,
			fn : this.onRequestToReopenSpreedWindow,
			customButton : [{
				text : _('Choose where to reopen Web Meetings'),
				name : 'reopen'
			}, {
				text : _('Stay offline'),
				name : 'offline'
			}],
			scope : this
		});
	},

	/**
	 * Event handler for {@link #requestToReopenSpreedWindow}.
	 * This will check if the user wishes to load Web Meetings in an external window or not.
	 * @param {String} button The button which the user pressed
	 * @private
	 */
	onRequestToReopenSpreedWindow : function(button)
	{
		if(button === 'reopen') {
			this.requestInitSpreedInExternalBrowserWindow();
		}
	},

	/**
	 * initialize Spreed WebRTC in an iFrame
	 *
	 * @param {Ext.Button} button The spreed button
	 */
	initSpreedInIFrame: function (showSpreedWebRTC) {
		var debug = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/debug'),
			language = container.getSettingsModel().get('zarafa/v1/main/language').substr(0, 2),
			spreedURL = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/url/') + '?lang=' + (language || 'en') + (debug ? '&debug' : '');

		this.spreedWebRTCWindowRoomMain.useIFrame(true);
		if (!this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
			this.spreedButton.setIconClass('icon_spreed_webrtc');
		}
		this.spreedWebRTCWindowRoomMain.createOpenSpreedWebRTC(null, spreedURL);
		if (!showSpreedWebRTC) {
			this.spreedWebRTCWindowRoomMain.hideSpreedWebRTC();
		}
	},

	/**
	 * initialize Spreed WebRTC in an external browser window
	 *
	 * @param {Ext.Button} button The spreed button
	 */
	initSpreedInExternalBrowserWindow: function (button) {
		var debug = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/debug'),
			language = container.getSettingsModel().get('zarafa/v1/main/language').substr(0, 2),
			spreedURL = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/url/') + '?lang=' + (language || 'en') + (debug ? '&debug' : '');

		this.spreedWebRTCWindowRoomMain.useIFrame(false);
		this.spreedButton.setIconClass('icon_spreed_webrtc');
		this.spreedWebRTCWindowRoomMain.createOpenSpreedWebRTC(null, spreedURL);
	},

	/**
	 * popout Spreed WebRTC in an external browser window
	 *
	 * @param {Ext.Button} button The spreed button
	 */
	requestPopoutSpreedInExternalBrowserWindow: function (button) {
		if (!this.spreedWebRTCWindowRoomMain.isInCallActivity()) {
			if (!container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/popout_info_lost_data_do_not_show')) {
				Zarafa.plugins.spreedwebrtc.dialogs.MessageBox.checkboxMessageBox(
					_('Pop out Kopano Web Meetings'),
					_('Be aware that Web Meetings restarts and data will be lost (chat & video call) when opening this window into a new browser window.'),
					_('Do not show this message again'),
					//icon : Ext.MessageBox.QUESTION,
					this.onRequestPopoutSpreedInExternalBrowserWindow,
					[{
						text : _('Open in browser window'),
						name : 'popout'
					}, {
						text : _('Cancel'),
						name : 'cancel'
					}],
					this,
					false
				);
			} else {
				this.popoutSpreedInExternalBrowserWindow();
			}
		} else {
			Ext.MessageBox.show({
				title: _('Kopano Web Meetings'),
				msg: _('Unable to pop-out during a video call.'),
				buttons: Ext.MessageBox.OK,
				icon: Ext.MessageBox.INFO
			});
		}
	},

	onRequestPopoutSpreedInExternalBrowserWindow: function (button, message_box) {
		// save do not show this message again choice
		var checkbox_checked = message_box.checkbox.checked;
		if (checkbox_checked) {
			container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/popout_info_lost_data_do_not_show', true);
		}
		if(button === 'popout') {
			this.popoutSpreedInExternalBrowserWindow();
		} else {
		}
	},

	popoutSpreedInExternalBrowserWindow: function () {
		this.popingOut = true;
		this.spreedWebRTCWindowRoomMain.popoutWindow();
	},

	goOffline: function () {
		this.goingOffline = true;
		this.spreedWebRTCWindowRoomMain.closeWindow();
	},

	/**
	 * Event handler for opening the Spreed WebRTC Main Room window
	 *
	 * @param {Ext.Button} button The button which was clicked
	 * @private
	 */
	focusSpreedWebRTCMeetingRoomMain: function (button) {
		this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC();
	},

	/**
	 * Event handler for opening the Spreed WebRTC Meeting Request Room window
	 *
	 * @param {Ext.Button} button The button which was clicked
	 * @private
	 */
	focusSpreedWebRTCMeetingRoomMeetingRequest: function (button) {
		this.spreedWebRTCWindowRoomMeetingRequest.focusSpreedWebRTC();
	},

	/**
	 * Event handler for opening the Spreed WebRTC Instant Meeting Room window
	 *
	 * @param {Ext.Button} button The button which was clicked
	 * @private
	 */
	focusSpreedWebRTCMeetingRoomInstantMeeting: function (button) {
		this.spreedWebRTCWindowRoomInstantMeeting.focusSpreedWebRTC();
	},

	/**
	 * Event handler for setting the Spreed WebRTC Sound settings
	 *
	 * @param {Ext.Button} button The button which was clicked
	 * @private
	 */
	onWebmeetingsSelectVolume: function(btn) {
		switch (btn.id) {
			case "spreed_webrtc_volume_high":
				container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/sound_settings', "high");
				break;
			case "spreed_webrtc_volume_low":
				container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/sound_settings', "low");
				break;
			case "spreed_webrtc_volume_mute":
				container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/sound_settings', "mute");
				break;
		}

		this.setSpreedWebRTCWindowsSoundSettings();
	},

	/**
	 * get last sound settings from WebApp plugin settings
	 *
	 * @private
	 */
	getSpreedWebRTCWindowsSoundSettings: function () {
		var sound_settings = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/sound_settings');
		return sound_settings;
	},

	/**
	 * Sends a request to spreed to set sound settings, with postMessage API
	 *
	 * @private
	 */
	setSpreedWebRTCWindowsSoundSettings: function () {
		var sound_settings = this.getSpreedWebRTCWindowsSoundSettings();
		switch (sound_settings) {
			case 'mute':
				this.spreedVolumeButton.setIconClass('icon_spreed_webrtc_volume_mute');
				break;
			case 'high':
				this.spreedVolumeButton.setIconClass('icon_spreed_webrtc_volume_high');
				break;
			case 'low':
			default:
				this.spreedVolumeButton.setIconClass('icon_spreed_webrtc_volume_low');
				break;
		}
		this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
			if (spreedWebRTCWindow.isWindowOpen()) {
				spreedWebRTCWindow.setSpreedWebRTCSoundSettings(sound_settings);
			}
		}, this);

	},
	/**
	 * When the browser is unloading, all external spreed.webrtc windows will be closed.
	 * @private
	 */
	onUnload: function () {
		this.closeExternalSpreedWebRTCWindows();
	},

	closeExternalSpreedWebRTCWindows: function() {
		this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
			if (!spreedWebRTCWindow.isIFrameWindow()) {
				spreedWebRTCWindow.closeWindow();
			}
		}, this);
	},

	/**
	 * Event handler for starting a spreed call when clicking on an online user
	 *
	 * @param {Ext.button} button The context menu button
	 * @private
	 */
	startSpreedMeeting: function(button) {
		var records = button.getRecords(),
			record = records[0] || records,
			entryId = record.store instanceof Zarafa.mail.MailStore ? record.get('sender_entryid') : record.get('entryid'),
			presencePlugin = container.getPluginByName('spreedpresence'),
			email_address = presencePlugin.getUserEmailAddressFromEntryId('', entryId),
			activeWindow = Ext.WindowMgr.getActive();

		this.sendPostMessage({'type': 'startCall', userId: email_address});

		// Hide the address book if it is opened
		if(Ext.isObject(activeWindow) && activeWindow.findByType('zarafa.addressbookcontentpanel').length > 0) {
			activeWindow.close();
		}

		// Show the spreed window if it is closed
		this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC(true);
	},

	/**
	 * Event handler for sending a spreed message when clicking on an online user
	 *
	 * @param {Ext.button} button The context menu button
	 * @private
	 */
	sendSpreedMessage: function(button) {
		var records = button.getRecords(),
				record = records[0] || records,
				entryId = record.store instanceof Zarafa.mail.MailStore ? record.get('sender_entryid') : record.get('entryid'),
				presencePlugin = container.getPluginByName('spreedpresence'),
				email_address = presencePlugin.getUserEmailAddressFromEntryId('', entryId),
				activeWindow = Ext.WindowMgr.getActive();

		this.sendPostMessage({'type': 'startChat', userId: email_address});

		// Hide the address book if it is opened
		if(Ext.isObject(activeWindow) && activeWindow.findByType('zarafa.addressbookcontentpanel').length > 0) {
			activeWindow.close();
		}

		// Show the spreed window if it is closed
		this.spreedWebRTCWindowRoomMain.focusSpreedWebRTC(true);
	},

	/**
	 * Sends messages to the spreed app
	 *
	 * @param {Object} data An object with the data to send
	 * @private
	 */
	sendPostMessage: function(data) {
		if(this.spreedWebRTCWindowRoomMain.isWindowOpen()) {
			this.spreedWebRTCWindowRoomMain.sendPostMessage(data, this.spreedDomain);
		}
	},

	/**
	 * Sends a request to spreed for the buddy list, with postMessage API
	 *
	 * @private
	 */
	requestUsersStatusFromSpreed: function () {
		this.sendPostMessage({'type': 'requestBuddyList'});
	},

	/**
	 * Bid for the type of shared component and the given record.
	 * This will bid on plugin.spreedwebrtc.dialog.spreedwindow
	 *
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Number} The bid for the shared component
	 * @private
	 */
	bidSharedComponent: function (type, record) {
		var bid = -1;

		switch (type) {
			case Zarafa.core.data.SharedComponentType['plugin.spreedwebrtc.dialog.spreedwindow']:
				bid = 1;
				break;
		}
		return bid;
	},

	/**
	 * Will return the reference to the shared component that is requested
	 *
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Ext.Component} Component
	 * @private
	 */
	getSharedComponent: function (type, record) {
		var component;

		switch (type) {
			case Zarafa.core.data.SharedComponentType['plugin.spreedwebrtc.dialog.spreedwindow']:
				component = Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel;
				break;
		}

		return component;
	},

	/**
	 * Event handler which is called when a post message is received from spreed
	 *
	 * @param {event} e The postMessage event
	 * @private
	 */
	onPostMessage: function (e) {
		var message = e.data;

		// check if the message comes from a valid origin
		if (e.origin != this.spreedDomain) {
			return;
		}

		switch (message.type) {
			case "requestAuthentication":
				this.requestAuthentication();
				this.updatePresenceList();
				break;
			case 'chat':
				this.notify(message.chat, message.from, message.roomid);
				if (message.chat == "incoming") {
					this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
						if (spreedWebRTCWindow.inRoomid(message.roomid)) {
							spreedWebRTCWindow.onIncoming(message.userId, message.chat);
						}
					}, this);
				} else if (message.chat == "refusedoraccepted") {
					this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
						if (spreedWebRTCWindow.inRoomid(message.roomid)) {
							spreedWebRTCWindow.callRefusedOrAccepted(message.userId, message.chat);
						}
					}, this);
				}
				break;
			case 'authenticationchanged':
				break;
			case 'authentication':
				if (message.authentication == "success") {
					if (!message.roomid) {
						this.popingOut = false;
						this.spreedButton.setIconClass('icon_spreed_webrtc_active');
						this.spreedWebRTCWindowRoomMain.onReadySpreedWebRTC();
					}
					this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
						if (spreedWebRTCWindow.inRoomid(message.roomid)) {
							spreedWebRTCWindow.onReadySpreedWebRTC();
							var sound_settings = this.getSpreedWebRTCWindowsSoundSettings();
							spreedWebRTCWindow.setSpreedWebRTCSoundSettings(sound_settings);
						}
					}, this);
				}
				break;
			case 'userStatusChanged':
				this.updatePresenceList(message.userId, message.newStatus);
				this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
					if (spreedWebRTCWindow.inRoomid(message.roomid)) {
						spreedWebRTCWindow.onUserEnteredRoom(message.userId, message.newStatus);
					}
				}, this);
				break;
			case 'callEstablished':
				this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
					if (spreedWebRTCWindow.inRoomid(message.roomid)) {
						spreedWebRTCWindow.onCallEstablished(message.userId, message.callEstablished);
					}
				}, this);
				this.updateInCallState();
				break;
			case 'calling':
				this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
					if (spreedWebRTCWindow.inRoomid(message.roomid)) {
						spreedWebRTCWindow.onCalling(message.userId, message.calling);
					}
				}, this);
				break;
			case 'callDone':
				this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
					if (spreedWebRTCWindow.inRoomid(message.roomid)) {
						spreedWebRTCWindow.onCallDone(message.userId, message.callDone);
					}
				}, this);
				this.updateInCallState();
				if (!message.roomid) {
					this.checkRequestInitSpreedInExternalBrowserWindow();
				}
				break;
			case 'sendBuddyList':
				this.refreshPresenceList(message.list);
				break;
			case 'roomChanged':
				// intended for presence status, will give the new room name -> message.newRoom
				this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
					if (spreedWebRTCWindow.inRoomid(message.roomid)) {
						spreedWebRTCWindow.onReadySpreedWebRTC();
					}
				}, this);
				break;
			case 'unload':
				var last_start_in_iframe = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe');
				var last_start_in_external_window = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window');
				var roomMainWasReady = this.spreedWebRTCWindowRoomMain.wasReady();
				this.spreedWebRTCWindows.forEach(function(spreedWebRTCWindow) {
					if (spreedWebRTCWindow.inRoomid(message.roomid)) {
						spreedWebRTCWindow.updateMenuOnUnload();
					}
				}, this);
				if (!message.roomid) {
					this.spreedButton.setIconClass('icon_spreed_webrtc');
					if (!this.isRunningInDeskapp) {
						if (!this.popingOut && !this.goingOffline) {
							this.initSpreedInIFrame();
						}
						if (this.goingOffline) {
							this.goingOffline = false;
							this.displayInfoWebmeetingsIsOffline();
						}
					} else if (roomMainWasReady) {
						if (!this.popingOut && last_start_in_external_window) {
							this.displayInfoWebmeetingsIsOffline();
						} else 	if (!this.popingOut && !this.goingOffline) {
							this.initSpreedInIFrame();
						}
						if (this.goingOffline) {
							this.goingOffline = false;
							this.displayInfoWebmeetingsIsOffline();
						}
					}
					if (false && !this.isRunningInDeskapp) {
						this.requestToReopenSpreedWindow();
					}
				}
				break;
		}
	}

});

Zarafa.onReady(function () {
	container.registerPlugin(new Zarafa.core.PluginMetaData({
		name: 'spreedwebrtc',
		displayName: _('Web Meetings Plugin'),
		pluginConstructor: Zarafa.plugins.spreedwebrtc.SpreedWebRTC
	}));
	if (!container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/enable')) {
		container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe', false);
		container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window', false);
		container.getSettingsModel().set('zarafa/v1/plugins/spreedwebrtc/popout_info_lost_data_do_not_show', false);
	}
});
Ext.namespace('Zarafa.plugins.spreedwebrtc');

/**
 *
 * @class Zarafa.plugins.spreedwebrtc.SpreedWebRTCWindow
 * @extends Object
 *
 */
Zarafa.plugins.spreedwebrtc.SpreedWebRTCWindow = Ext.extend(Object, {
	/**
	 * The SpreedWebRTC window's subject.
	 * @property
	 * @type String
	 */
	subject : undefined,

	spreedWebRTCWindow: null,

	button: null,

	base_text: null,

	url: null,

	roomid: null,

	isIFrame: false,

	spreedDomain: null,

	spreedWindow: null,

	wasopen: false,

	wasready: false,

	incoming: false,

	calling: false,

	inCall: false,

	runningInDeskApp: false,

	userIds: [],

	init : function() {
	},

	setButton : function(button) {
		this.button = button;
		this.base_text = button.text;
		return this;
	},

	useIFrame : function(use_iframe) {
		this.isIFrame = use_iframe;
	},

	setSpreedDomain: function(spreedDomain) {
		this.spreedDomain = spreedDomain;
	},

	isIFrameWindow : function() {
		return this.isIFrame;
	},

	isWindowOpen : function() {
		if (!this.isIFrame) {
			return this.spreedWebRTCWindow && !this.spreedWebRTCWindow.closed;
		} else {
			return this.spreedWindow != null;
		}
	},

	isWindowVisible : function() {
		if (!this.isIFrame) {
			return this.isWindowOpen();
		} else {
			return this.spreedWindow != null && this.spreedWindow.ownerCt.isVisible();
		}
	},

	inRoomid : function(roomid) {
		return (this.roomid !== null && roomid == this.roomid) || (this.roomid == "" && roomid == null);
	},

	isIncoming : function() {
		return this.incoming;
	},

	isCalling : function() {
		return this.calling;
	},

	isInCall : function() {
		return this.inCall;
	},

	isInCallActivity : function() {
		return this.isIncoming() || this.isCalling() || this.isInCall();
	},

	wasOpen : function() {
		return this.wasopen;
	},

	wasReady : function() {
		return this.wasready;
	},

	createOpenSpreedWebRTC : function(subject, url) {
		var urlparsed, splits;
		this.subject = subject;
		if (Ext.isDefined(window.deskappOpenWindow)) {
			this.runningInDeskApp = true;
			if (url.substr(0,1) == '/') {
				// relative URL to webmeetings, make it full qualified for DeskApp
				url = window.location.origin + url;
			}
		}
		if (url) {
			this.url = url;
			var location = document.createElement("a");
			location.href = url;
			if (!location.pathname) {
				this.roomid = '';
			} else {
				splits = location.pathname.split('/');
				if (splits) {
					this.roomid = splits.slice(-1)[0];
				}
			}
		}
		if (this.isIFrame) {
			if (this.spreedWindow == null) {
				Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugin.spreedwebrtc.dialog.spreedwindow'], null, {
					manager: Ext.WindowMgr
				});
				this.enablePopout();
				this.spreedWindow.enableTool('offline');
			} else {
				this.focusSpreedWebRTC();
			}
		} else {
			if (!this.isWindowOpen()) {
				var newDeskAppWindow = this;
				if (this.runningInDeskApp) {
					if (this.button) {
						if (this.subject) {
							this.button.setText(this.subject);
						} else {
							this.button.setText(this.base_text);
						}
					}
					if (url) {
						this.wasopen = true;
						window.deskappOpenWindow(url, function(separateWindowInstance){
							if ( separateWindowInstance ) {
								newDeskAppWindow.spreedWebRTCWindow = separateWindowInstance;
								newDeskAppWindow.wasopen = true;
							}
						}, {height:768,width:1024, 'inject_js_start': "inject_start.js", 'inject_js_end': "inject_webmeetings_end.js"});
					}
				} else {
					this.spreedWebRTCWindow = window.open(url, '_blank', 'location=no,height=768,width=1024,scrollbars=yes,status=yes');
				}
				if (this.button) {
					if (this.subject) {
						this.button.setText(this.subject);
					} else {
						this.button.setText(this.base_text);
					}
				}
			} else {
				this.spreedWebRTCWindow.location.href = url;
				if (this.runningInDeskApp) {
					this.spreedWebRTCWindow.nw.Window.get().focus();
				} else {
					this.spreedWebRTCWindow.focus();
				}
			}
		}
		this.wasopen = true;
	},

	setSpreedWebRTCUrlAndFocus : function(url, roomid) {
		if (this.spreedWebRTCWindow) {
			if (this.runningInDeskApp) {
				this.spreedWebRTCWindow.nw.Window.get().focus();
			} else {
				this.spreedWebRTCWindow.focus();
			}
		}
		if (url) {
			this.url = url;
			this.roomid = roomid;
			if (this.spreedWebRTCWindow) {
				this.spreedWebRTCWindow.location.href = url;
			} else {
				if (this.runningInDeskApp) {
					var newDeskAppWindow = this;
					window.deskappOpenWindow(url, function(separateWindowInstance){
						if ( separateWindowInstance ) {
							newDeskAppWindow.spreedWebRTCWindow = separateWindowInstance;
						}
					}, {height:768,width:1024, 'inject_js_start': "inject_start.js", 'inject_js_end': "inject_webmeetings_end.js"});
				}
			}
		}
	},

	focusSpreedWebRTC : function(do_not_toggle) {
		if (this.isIFrame) {
			if (this.spreedWindow == null) {
				this.createOpenSpreedWebRTC();
			}
			else if(this.spreedWindow.ownerCt.isVisible() && !do_not_toggle) {
				this.spreedWindow.ownerCt.hide();
			}
			else {
				this.spreedWindow.ownerCt.show();
			}
		} else {
			if (this.runningInDeskApp) {
				this.spreedWebRTCWindow.nw.Window.get().focus();
			} else {
				this.spreedWebRTCWindow.focus();
			}
		}
	},

	hideSpreedWebRTC : function() {
		if (this.isIFrame) {
			this.spreedWindow.ownerCt.hide();
		}
	},

	disablePopout : function() {
		if (this.isIFrame) {
			this.spreedWindow.disableTool('popout');
			this.spreedWindow.setToolTipForTool('popout', _('Unable to pop-out during a video call'));
		}
	},

	enablePopout : function() {
		if (this.isIFrame) {
			this.spreedWindow.enableTool('popout');
			this.spreedWindow.setToolTipForTool('popout', _('Pop out Kopano Web Meetings'));
		}
	},

	onReadySpreedWebRTC : function() {
		this.button.setDisabled(false);
		this.wasopen = true;
		this.wasready = true;
	},

	onUserEnteredRoom : function(userId, newStatus) {
		var button_text = this.subject;
		if (!button_text) {
			return;
		}
		for(var i = this.userIds.length - 1; i >= 0; i--) {
			if(this.userIds[i] === userId) {
				this.userIds.splice(i, 1);
			}
		}
		if (newStatus == "online") {
			this.userIds.push(userId);
		}
		if (this.userIds.length > 0) {
			button_text += " - " + this.userIds[0];
		}
		if (this.userIds.length == 2) {
			button_text += _(" and 1 other");
		}
		if (this.userIds.length > 2) {
			var others = this.userIds.length -1;
			button_text += String.format(_(" and {0} others"), others.toString());
		}
		this.button.setText(button_text);
	},

	onIncoming : function() {
		this.incoming = true;
		this.disablePopout();
	},

	callRefusedOrAccepted : function() {
		this.incoming = false;
		this.enablePopout();
	},

	onCalling : function() {
		this.calling = true;
		this.disablePopout();
	},

	onCallEstablished : function() {
		this.button.setIconClass('icon_spreed_webrtc_menu_opened');
		this.inCall = true;
		this.disablePopout();
	},

	onResetCallState : function() {
		this.incoming = false;
		this.calling = false;
		this.inCall = false;
	},

	onCallDone : function() {
		this.button.setIconClass('icon_spreed_webrtc_menu_inactive');
		this.onResetCallState();
		this.enablePopout();
	},

	updateMenuOnUnload : function() {
		if (this.wasopen) {
			this.button.setDisabled(true);
			this.button.setText(this.base_text);
			this.wasopen = false;
			this.wasready = false;
		}
	},

	/**
	 * Sends messages to the spreed app
	 *
	 * @param {Object} data An object with the data to send
	 * @private
	 */
	sendPostMessage: function(data, domain) {
		if (!domain) {
			domain = this.spreedDomain;
		}
		if (this.isIFrame) {
			if(Ext.isObject(this.spreedWindow)) {
				this.spreedWindow.spreedIFrame.getEl().dom.contentWindow.postMessage(data, domain);
			}
		} else {
			if (this.isWindowOpen()) {
				this.spreedWebRTCWindow.postMessage(data, domain);
			}
		}
	},

	setSpreedWebRTCSoundSettings: function (sound_settings) {
		var soundSettings;
		if (this.isWindowOpen()) {
			switch (sound_settings) {
				case 'mute':
					soundSettings = {
						incomingMessages: false,
						incomingCall: false,
						roomJoinLeave: false
					}
					break;
				case 'high':
					soundSettings = {
						incomingMessages: true,
						incomingCall: true,
						roomJoinLeave: true
					}
					break;
				case 'low':
				default:
					soundSettings = {
						incomingMessages: true,
						incomingCall: true,
						roomJoinLeave: false
					}
					break;
			}

			this.sendPostMessage({'type': 'soundSettings', soundSettings: soundSettings});
		}
	},

	popoutWindow: function() {
		if (this.isIFrame && this.isWindowOpen() && !this.isInCallActivity()) {
			spreedWindow = this.spreedWindow;
			this.spreedWindow = null;
			this.useIFrame(false);
			this.createOpenSpreedWebRTC(this.subject, this.url);
			spreedWindow.close();
		}
	},

	closeWindow: function() {
		if (!this.isIFrame) {
			if (this.isWindowOpen()) {
				this.spreedWebRTCWindow.close();
				this.onResetCallState();
			}
		} else {
			if (this.isWindowOpen()) {
				this.spreedWindow.close();
				this.onResetCallState();
			}
		}
	}

});
Ext.namespace('Zarafa.plugins.spreedwebrtc.data');

/**
 * @class Zarafa.plugins.spreedwebrtc.data.PresenceResponseHandler
 * @extends Zarafa.core.data.AbstractResponseHandler
 *
 * Presence specific response handler.
 */
Zarafa.plugins.spreedwebrtc.data.PresenceResponseHandler = Ext.extend(Zarafa.core.data.AbstractResponseHandler, {

	/**
	 * Stores the Authentication Token in the Presence service
	 * @param {Object} response Object contained the response data.
	 */
	doInfo: function (response) {
		if (response.presenceauth) {
			var presenceauth = response.presenceauth;

			this.presence.authenticationToken = presenceauth.timestamp + ':' + presenceauth.emailaddress + ':' + presenceauth.authtoken.toUpperCase();
			this.presence.sendPresence();
		}
	}
});

Ext.reg('spreedwebrtc.presenceresponsehandler', Zarafa.plugins.spreedwebrtc.data.PresenceResponseHandler);
Ext.namespace('Zarafa.plugins.spreedwebrtc.data');

/**
 * @class Zarafa.plugins.spreedwebrtc.data.SpreedWebrtcResponseHandler
 * @extends Zarafa.core.data.AbstractResponseHandler
 *
 * Spreedwebrtc specific response handler.
 */
Zarafa.plugins.spreedwebrtc.data.SpreedWebrtcResponseHandler = Ext.extend(Zarafa.core.data.AbstractResponseHandler, {

	/**
	 * Opens the window with the url returned from server or show error msg box in case of error.
	 * @param {Object} response Object contained the response data.
	 */
	doInfo: function (response) {
		var spreedDomain = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/domain');
		if (!spreedDomain) {
			spreedDomain = window.location.origin;
		}

		if (response.authentication) {
			var authentication = response.authentication;

			this.spreedWebRTCWindow.sendPostMessage({
				type: "authentication",
				authentication: {
					userid: authentication.emailaddress,
					timestamp: authentication.timestamp,
					secret: authentication.secret,
					fullname: container.getUser().getFullName(),
					buddyPicture: authentication.buddyPicture || '',
					turn_ttl: authentication.turn_ttl,
					turn_username: authentication.turn_username,
					turn_password: authentication.turn_password,
					turn_urls: authentication.turn_urls
				}
			},
			spreedDomain);

		} else if (response.meetingurl) {
			var x=document.createElement("a");
			x.href = response.meetingurl.url;
			var meetingurl = x.href;
			if ( !Ext.isEmpty(this.appointment) ){
				// We are adding a the invitation to an appointment. Let's set the location
				// of the appointment to the url of the Webmeetings room.
				this.appointment.set('location', meetingurl);
			}
			if (this.editorField.isHtmlEditor()) {
				this.addHtmlInvitation(meetingurl);
			} else {
				this.addPlainTextInvitation(meetingurl);
			}
			this.plugin.hideInfoMaskMailcreate(true);
			this.openSpreedWebRTCMeetingURLForMailcreate.call(this.scope, meetingurl, response.meetingurl.roomid);

		}
	},

	/**
	 * Adds an invitation for a web meeting to a HTML editor based on the invitationData object
	 * @param {Object} invitationData Contains the text and url for the invitation
	 */
	addHtmlInvitation : function(meetingurl){
		var htmlEditor = this.editorField.getEditor();
		var fontName = htmlEditor.defaultFontFamily;
		var fontSize = htmlEditor.defaultFontSize;
		// The icon is pure css. Because an image (dataURI) would need the user to allow images, and SVG is not supported by most e-mail clients.
		// Note that the icon is not displayed in Outlook (because Outlook sucks)
		var cssIcon = 	'<span style="padding:3px 6px 3px 0; height:12px; width:18px; display:inline-block;" data-mce-style="padding:2px 6px 0 0; height:12px; display:inline-block;">'+
							'<span 	style="width: 12px;height: 12px;background: #23cb02;border-radius: 3px;display:inline-block;" ' +
									'data-mce-style="width: 12px;height: 12px;background: #23cb02;border-radius: 3px;display:inline-block;"></span>' +
							'<span 	style="width: 0px;height: 4px;border-top-width:4px;border-top-style:solid;border-top-color:transparent;border-bottom-width:4px;border-bottom-style:solid;border-bottom-color:transparent;border-right-width:6px;border-right-style:solid;border-right-color:#23cb02;display:inline-block;" ' +
									'data-mce-style="width: 0px;height: 4px;border-top-width:4px;border-top-style:solid;border-top-color:transparent;border-bottom-width:4px;border-bottom-style:solid;border-bottom-color:transparent;border-right-width:6px;border-right-style:solid;border-right-color:#23cb02;display:inline-block;"></span>' +
						'</span>';
		var html =	'<style>span.webmeetings-invitation a{text-decoration:none;}</style>' + // Added to style in Outlook
					 '<p style="margin: 0px; padding: 0px; data-mce-style="margin: 0px; padding: 0px;">' +
						'<span class="webmeetings-invitation" style="font-family:' + fontName + '; font-size:'+ fontSize +'; data-mce-style="font-family:' + fontName + '; font-size:' + fontSize + ';>' +
							_("I'd like to invite you to join my web meeting. You can join the meeting by clicking this button:") + '<br><br>' +
								'<a target="_blank" href="' + meetingurl + '">' +
									'<span style="border-bottom:1px solid #d5d5d5; display:inline-block;">' + // gmail does not support box-shadow, so we will use borders to create sort of a shadow
									'<span style="border-right:1px solid #d5d5d5; border-bottom:1px solid #a6a6a6; display:inline-block;">' + // gmail does not support box-shadow, so we will use borders to create sort of a shadow
										'<span style="border-width:9px;border-style:solid;border-color:#e6e6e6;display:inline-block; height: 18px; font-family: tahoma,arial,helvetica,sans-serif; font-size:0; color: black; text-decoration:none; background: #e6e6e6;"' +
										' data-mce-style="border-width:9px;border-style:solid;border-color:#e6e6e6;display:inline-block; height: 18px;font-family: tahoma,arial,helvetica,sans-serif; font-size:0; color: black; text-decoration:none; background: #e6e6e6;">' +
											cssIcon +
											'<span 	style="font-size: 10pt;line-height: 18px;display: inline-block;height: 18px;" ' +
													'data-mce-style="font-size: 10pt;line-height: 18px;display: inline-block;height: 18px;">' +
												 _('Join Web Meeting') +
											'</span>' +
										'</span>' +
									'</span>' +
									'</span>' +
								'</a>' +
							'<br><br>' +
							_("{{Kopano Web Meetings}} provides the best experience in Google Chrome, Firefox, Chromium or Iridium.")
								.replace(/{{(.*)}}/, '<a target="_blank" href="https://kopano.com/products/webmeetings/" style="text-decoration:none;"><span style="color:#00b4f1; font-weight:bold; text-decoration:none;" data-mce-style="color:#00b4f1; font-weight:bold; text-decoration:none;">$1</span></a>') +
						'</span>' +
					'</p>';
		this.editorField.insertAtCursor(html);
	},

	/**
	 * Adds an invitation for a web meeting to a plain text editor based on the invitationData object
	 * @param {Object} invitationData Contains the text and url for the invitation
	 */
	addPlainTextInvitation : function(meetingurl){
		this.editorField.insertAtCursor(
			'\n' +
			_("﻿I'd like to invite you to join my web meeting. You can join the meeting by copying this link to your browsers address bar:") + '\n\n' +
			meetingurl + '\n\n' +
			_("Kopano Web Meetings provides the best experience in Google Chrome, Firefox, Chromium or Iridium.") + '\n\n' +
			_("https://kopano.com/products/webmeetings") + '\n'
		);
	}
});

Ext.reg('spreedwebrtc.responsehandler', Zarafa.plugins.spreedwebrtc.data.SpreedWebrtcResponseHandler);
Ext.namespace('Zarafa.plugins.spreedwebrtc.dialogs');

/**
 * @class Zarafa.plugins.spreedwebrtc.dialogs.MessageBox
 * @extends Ext.MessageBox
 *
 * Extension to the default {@link Ext.MessageBox MessageBox} which
 * offers some special features like displaying a checkbox.
 */
// Use Ext.apply instead of Ext.extend because Ext.MessageBox is not
// a class but an instantiated object. The Ext.apply({}, a, b) trick
// is used to create a full copy of Ext.MessageBox instead of changing
// the existing object.
Zarafa.plugins.spreedwebrtc.dialogs.MessageBox = Ext.apply({}, Ext.MessageBox, {
	/**
	 * The custom buttons which are added in {@link Ext.MessageBox messagebox}.
	 * it will be removed when {@link Ext.MessageBox messagebox} gets hide.
	 * 
	 * @property
	 * @type Array
	 * @private
	 */
	customButton : undefined,

	/**
	 * Initialize the {@link Ext.MessageBox.dlg Dialog}.
	 * Because the {@link Ext.MessageBox MessageBox} hides the usable
	 * interface from use, we must apply a hack to access the Dialog
	 * before it is displayed to the user.
	 *
	 * This function will add a list of {@link Ext.Component Components}
	 * to the dialog, which can be used to fine-tune the look&feel.
	 *
	 * @param {Array} items The array of items which must be added to the
	 * MessageBox.
	 * @private
	 */
	initDialog : function(items)
	{
		var dlg = Ext.MessageBox.getDialog();

		// Automatically remove all items which we had added.
		// This makes sure we can use the same Dialog multiple times
		dlg.on('hide', function(dlg) {
			dlg.removeAll();
		}, dlg, {single: true});

		// In case the 'hide' event was not fired,
		// we also listen to the destroy event as fallback.
		dlg.on('destroy', function(dlg) {
			dlg.removeAll();
		}, dlg, {single: true});

		// Before showing the dialog, we must first
		// add all items to the dialog.
		dlg.on('beforeshow', function(dlg) {
			dlg.add(items);
		}, dlg, {single: true});
	},

	checkboxMessageBox : function(title, msg, checkbox_label, fn, custom_button, scope, value)
	{
		var label = Ext.create({
			xtype: 'displayfield',
			autoHeight: true,
			autoWidth: true,
			value: msg,
			hideLabel : true,
			htmlEncode : true
		});
		var checkbox = Ext.create({
			xtype: 'checkbox',
			name: 'do_not_show_again',
			boxLabel: checkbox_label,
			value: value
		});

		this.initDialog([{
			xtype: 'container',
			anchor: '100% 100%',
			items: [ label, checkbox ]
		}]);

		var dlg = Ext.MessageBox.getDialog();
		this.customButton = dlg.getFooterToolbar().add(custom_button);
		this.checkbox = checkbox;

		Ext.MessageBox.show({
			title : title,
			fn: function(button) {
				Ext.callback(fn, scope || window, [button, checkbox.getValue()], 1);
			},
			customButton: custom_button,
			minWidth: 480,
			scope : scope,
			prompt: false,
			value: value
		});

		if(!Ext.isEmpty(this.customButton)) {
			Ext.each(this.customButton, function(button) {
				dlg.mon(button, 'click', Ext.createDelegate(this.onButtonClick, this, [fn, checkbox.checked, scope], true), this);
			}, this);
		}

		dlg.on('hide', this.onDestroy, this, {single : true});
		dlg.on('destroy', this.onDestroy, this, {single : true});

		return this;
	},

	/**
	 * Event handler triggered when custom button is clicked. 
	 * it will hide the {@link Ext.MessageBox messagebox}.
	 * @param {Ext.Button}  button The button which user pressed.
	 * @param {Ext.EventObject} event the event object
	 * @parma {Function} callback The callback function to call when button is pressed.
	 */
	onButtonClick : function(button, event, callback, checkbox_checked, scope)
	{
		var buttonName = button.name || 'cancel';
		Ext.MessageBox.hide();
		callback.call(scope, buttonName, this);
	},

	/**
	 * Event handler which is triggered when {@link Ext.MessageBox messagebox} gets hide.
	 * also it will remove all custom buttons from message box.
	 * @param {Ext.Window} dlg The window
	 */
	onDestroy : function(dlg)
	{
		if(!Ext.isEmpty(this.customButton)) {
			for(var i = 0; i < this.customButton.length; i++) {
				dlg.getFooterToolbar().remove(this.customButton[i]);
			}
			this.customButton = [];
		}
	}
});
Ext.namespace('Zarafa.plugins.spreedwebrtc.dialogs');

/**
 * @class Zarafa.plugins.spreedwebrtc.dialogs.SettingsMessageBox
 * @extends Ext.MessageBox
 *
 * Extension to the default {@link Ext.MessageBox MessageBox} which
 * offers some special features like displaying a checkbox.
 */
// Use Ext.apply instead of Ext.extend because Ext.MessageBox is not
// a class but an instantiated object. The Ext.apply({}, a, b) trick
// is used to create a full copy of Ext.MessageBox instead of changing
// the existing object.
Zarafa.plugins.spreedwebrtc.dialogs.SettingsMessageBox = Ext.apply({}, Ext.MessageBox, {
	/**
	 * The custom buttons which are added in {@link Ext.MessageBox messagebox}.
	 * it will be removed when {@link Ext.MessageBox messagebox} gets hide.
	 *
	 * @property
	 * @type Array
	 * @private
	 */
	customButton : undefined,

	/**
	 * Initialize the {@link Ext.MessageBox.dlg Dialog}.
	 * Because the {@link Ext.MessageBox MessageBox} hides the usable
	 * interface from use, we must apply a hack to access the Dialog
	 * before it is displayed to the user.
	 *
	 * This function will add a list of {@link Ext.Component Components}
	 * to the dialog, which can be used to fine-tune the look&feel.
	 *
	 * @param {Array} items The array of items which must be added to the
	 * MessageBox.
	 * @private
	 */
	initDialog : function(items)
	{
		var dlg = Ext.MessageBox.getDialog();

		// Automatically remove all items which we had added.
		// This makes sure we can use the same Dialog multiple times
		dlg.on('hide', function(dlg) {
			dlg.removeAll();
		}, dlg, {single: true});

		// In case the 'hide' event was not fired,
		// we also listen to the destroy event as fallback.
		dlg.on('destroy', function(dlg) {
			dlg.removeAll();
		}, dlg, {single: true});

		// Before showing the dialog, we must first
		// add all items to the dialog.
		dlg.on('beforeshow', function(dlg) {
			dlg.add(items);
		}, dlg, {single: true});
	},

	settingsMessageBox : function(title, msg, radio_group_label, selections, value, msg_footer, custom_button, fn, scope)
	{
		var label = Ext.create({
			xtype: 'displayfield',
			cls: 'k-spreed-label1',
			autoHeight: true,
			autoWidth: true,
			value: msg,
			hideLabel : true,
			htmlEncode : true,
            renderer: function(value){
                return value.replace(/\n/g, '<br>');
            }
		});
		var radioGroupLabel = Ext.create({
			xtype: 'displayfield',
			cls: 'k-spreed-label2',
			autoHeight: true,
			autoWidth: true,
			value: radio_group_label,
			hideLabel : true,
			htmlEncode : true,
            renderer: function(value){
                return value.replace(/\n/g, '<br>');
            }
		});
		var radioGroup = Ext.create({
			xtype: 'radiogroup',
			cls: 'k-spreed-radiogroup',
			hideLabel: true,
			columns: 1,
			items: selections,
			value: value
		});
		var labelFooter = Ext.create({
			xtype: 'displayfield',
			cls: 'k-spreed-label3',
			autoHeight: true,
			autoWidth: true,
			value: msg_footer,
			hideLabel : true,
			htmlEncode : true,
            renderer: function(value){
                return value.replace(/\n/g, '<br>');
            }
		});

		this.initDialog([{
			xtype: 'container',
			anchor: '100% 100%',
			items: [ label, radioGroupLabel, radioGroup, labelFooter ]
		}]);

		var dlg = Ext.MessageBox.getDialog();
		dlg.getEl().addClass('k-spreed-settings-messagebox');
		this.customButton = dlg.getFooterToolbar().add(custom_button);
		this.radioGroup = radioGroup;

		Ext.MessageBox.show({
			title : title,
			fn: function(button) {
				Ext.callback(fn, scope || window, [button, radioGroup.getValue()], 1);
			},
			customButton: custom_button,
			minWidth: 480,
			scope : scope,
			prompt: false,
			value: value
		});

		if(!Ext.isEmpty(this.customButton)) {
			Ext.each(this.customButton, function(button) {
				dlg.mon(button, 'click', Ext.createDelegate(this.onButtonClick, this, [fn, radioGroup.getValue(), scope], true), this);
			}, this);
		}

		dlg.on('hide', this.onDestroy, this, {single : true});
		dlg.on('destroy', this.onDestroy, this, {single : true});

		return this;
	},

	/**
	 * Event handler triggered when custom button is clicked.
	 * it will hide the {@link Ext.MessageBox messagebox}.
	 * @param {Ext.Button}  button The button which user pressed.
	 * @param {Ext.EventObject} event the event object
	 * @parma {Function} callback The callback function to call when button is pressed.
	 */
	onButtonClick : function(button, event, callback, checkbox_checked, scope)
	{
		var buttonName = button.name || 'cancel';
		Ext.MessageBox.hide();
		callback.call(scope, buttonName, this);
	},

	/**
	 * Event handler which is triggered when {@link Ext.MessageBox messagebox} gets hide.
	 * also it will remove all custom buttons from message box.
	 * @param {Ext.Window} dlg The window
	 */
	onDestroy : function(dlg)
	{
		if(!Ext.isEmpty(this.customButton)) {
			for(var i = 0; i < this.customButton.length; i++) {
				dlg.getFooterToolbar().remove(this.customButton[i]);
			}
			this.customButton = [];
		}

		dlg.getEl().removeClass('k-spreed-settings-messagebox');
	}
});
Ext.namespace('Zarafa.plugins.spreedwebrtc.dialogs');

/**
 * @class Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel
 * @extends Zarafa.core.ui.ContentPanel
 *
 * The content panel which contains the spreed application
 * @xtype spreedwebrtc.window
 */
Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel = Ext.extend(Zarafa.core.ui.ContentPanel, {
	/**
	 * The class that will be added to a tool in the titlebar when it is disabled.
	 * @property
	 * @type String
	 */
	toolDisabledClass : 'k-tool-disabled',

	/**
	 * @constructor
	 * @param config Configuration structure
	 */
	constructor: function (config) {
		var debug = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/debug'),
			language = container.getSettingsModel().get('zarafa/v1/main/language').substr(0, 2),
			spreedURL = container.getSettingsModel().get('zarafa/v1/plugins/spreedwebrtc/url/') + '?lang=' + (language || 'en') + (debug ? '&debug' : '');

		config = config || {};
		Ext.applyIf(config, {
			layout: 'fit',
			title: _('Kopano Web Meetings'),
			width: 800,
			height: 500,
			listeners: {
				scope: this,
				beforerender: this.onBeforeRenderWindow,
				render: this.onRenderWindow,
				close: this.onCloseWindow
			},
			items: [
				{
					autoEl: {
						tag: "iframe",
						height: '100%',
						src: spreedURL,
						allowfullscreen: true
					},
					ref: 'spreedIFrame'
				}
			]
		});
		Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel.superclass.constructor.call(this, config);
	},

	/**
	 * initialize component
	 * This will create a reference in the {@link Zarafa.plugins.spreedwebrtc.SpreedWebRTC plugin}, so the
	 * plugin can access its properties
	 * @protected
	 */
	initComponent: function () {
		Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel.superclass.initComponent.call(this);

		container.getPluginByName('spreedwebrtc').spreedWebRTCWindowRoomMain.spreedWindow = this;
	},

	/**
	 * Event handler for the beforerender event of this window. Will add an offline and a popout
	 * tool to the window's titlebar
	 *
	 * @param {Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel} this
	 */
	onBeforeRenderWindow : function(win) {
		win.tools = [
			{
				id: 'offline',
				qtip: _('Go offline'),
				handler: this.onGoOfflineClick,
				scope: this
			},
			{
				id: 'popout',
				handler: this.onPopoutClick,
				scope: this
			},
			{
				id: 'close',
				handler: this.onCloseClick,
				scope: this
			}
		];
	},

	/**
	 * Event handler for the render event of this window. Will add text to the offline
	 * tool to the window's titlebar
	 *
	 * @param {Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel} this
	 */
	onRenderWindow : function(win) {
		if ( Ext.isDefined(win.tools) && Ext.isDefined(win.tools.offline) ){
			win.tools.offline.dom.innerText = _('Go offline');
		}
	},

	/**
	 * Event handler for the close event of this window.
	 *
	 * @param {Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel} this
	 */
	onCloseWindow : function(win) {
		container.getPluginByName('spreedwebrtc').reset();
	},

	/**
	 * Event handler for the click event of the 'offline' tool button
	 *
	 * @param {Ext.EventObj} event The normalized event object
	 * @param {Ext.Element} toolEl The tool element that was clicked
	 */
	onGoOfflineClick : function(event, toolEl) {
		// Return if the tool is disabled
		if ( toolEl.hasClass(this.toolDisabledClass) ){
			return;
		}

		console.log('offline');
		container.getPluginByName('spreedwebrtc').goOffline();
	},

	/**
	 * Event handler for the click event of the 'popout' tool button
	 *
	 * @param {Ext.EventObj} event The normalized event object
	 * @param {Ext.Element} toolEl The tool element that was clicked
	 */
	onPopoutClick : function(event, toolEl) {
		if ( toolEl.hasClass(this.toolDisabledClass) ){
			return;
		}

		console.log('popout');
		container.getPluginByName('spreedwebrtc').requestPopoutSpreedInExternalBrowserWindow();
	},

	/**
	 * Event handler for the click event of the 'popout' tool button
	 *
	 * @param {Ext.EventObj} event The normalized event object
	 * @param {Ext.Element} toolEl The tool element that was clicked
	 */
	onCloseClick : function(event, toolEl) {
		if ( toolEl.hasClass(this.toolDisabledClass) ){
			return;
		}

		console.log('close');
		this.ownerCt.hide();
	},

	/**
	 * Disables a tool button in the window's titlebar
	 *
	 * @param {String} toolId The id of the tool that should be disabled
	 */
	disableTool : function(toolId) {
		var tools = this.ownerCt.tools;
		tools[toolId].addClass(this.toolDisabledClass);
	},

	/**
	 * Enables a tool button in the window's titlebar
	 *
	 * @param {String} toolId The id of the tool that should be enabled
	 */
	enableTool : function(toolId) {
		var tools = this.ownerCt.tools;
		tools[toolId].removeClass(this.toolDisabledClass);
	},

	/**
	 * Sets the text of the tooltip for a tool button in the window's titlebar
	 *
	 * @param {String} toolId The id of the tool for which the tooltip text is set
	 * @param {String} text The text of the tooltip
	 */
	setToolTipForTool : function(toolId, text) {
		var tools = this.ownerCt.tools;
		tools[toolId].dom.qtip = text;
	},

	/**
	 * Removes the tooltip of a tool button in the window's titlebar
	 *
	 * @param {String} toolId The id of the tool for which the tooltip text will be removed
	 */
	removeToolTipForTool : function(toolId) {
		var tools = this.ownerCt.tools;
		tools[toolId].dom.qtip = undefined;
	}
});

Ext.reg('spreedwebrtc.window', Zarafa.plugins.spreedwebrtc.dialogs.SpreedContentPanel);
Ext.namespace('Zarafa.plugins.spreedwebrtc.settings');

/**
 * @class Zarafa.plugins.spreedwebrtc.settings.SettingsMainCategory
 * @extends Zarafa.settings.ui.SettingsCategory
 * @xtype spreedwebrtc.settingsmaincategory
 *
 * The files category for users which will
 * allow the user to configure Webmeetings related settings
 */
Zarafa.plugins.spreedwebrtc.settings.SettingsMainCategory = Ext.extend(Zarafa.settings.ui.SettingsCategory, {

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor: function (config) {
		config = config || {};

		Ext.applyIf(config, {
			title        : dgettext('plugin_spreedwebrtc', 'Web Meetings'),
			categoryIndex: 1,
			iconCls      : 'icon_webmeetings_settings_category',
			items        : [{
				xtype: 'spreedwebrtc.settingswebmeetingswidget'
			},
				container.populateInsertionPoint('context.settings.category.spreedwebrtc', this)
			]
		});

		Zarafa.plugins.spreedwebrtc.settings.SettingsMainCategory.superclass.constructor.call(this, config);
	}
});

Ext.reg('spreedwebrtc.settingsmaincategory', Zarafa.plugins.spreedwebrtc.settings.SettingsMainCategory);
Ext.namespace('Zarafa.plugins.spreedwebrtc.settings');

/**
 * @class Zarafa.plugins.spreedwebrtc.settings.SettingsWebmeetingsWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 * @xtype zarafa.settingswebmeetingswidget
 *
 * The {@link Zarafa.settings.ui.SettingsWidget widget} for configuring
 * the general webmeetings options in the {@link Zarafa.plugins.spreedwebrtc.settings.SettingsWebmeetingsCategory webmeetings category}.
 */
Zarafa.plugins.spreedwebrtc.settings.SettingsWebmeetingsWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config)
	{
		config = config || {};

		Ext.applyIf(config, {
			title : _('Web Meetings settings'),
			layout : 'form',
			items : []
		});

		// Display the popout settings only if supported.
		if (Ext.isDefined(window.deskappOpenWindow)) {
			config.items.splice(0, 0, {
				xtype : 'displayfield',
				hideLabel : true,
				value : _('You can now choose where to open Web Meetings by default in DeskApp') + ':'
			},{
				xtype : 'radiogroup',
				name : 'location',
				ref : 'openingWebmeetingsField',
				columns : 1,
				hideLabel : true,
				items : [{
					xtype : 'radio',
					name : 'openingWebmeetings',
					inputValue : 'iframe',
					boxLabel : _('In Deskapp')
				},{
					xtype : 'radio',
					name : 'openingWebmeetings',
					inputValue : 'popout',
					boxLabel : _('In a new window')
				}],
				listeners : {
					change : this.onRadioChange,
					scope : this
				}
			});
		} else {
			config.items.splice(0, 0, {
				xtype: 'box',
				autoEl: {tag: 'a', href: 'https://www.spreed.me/extension/', target: '_blank', html: 'Install Spreed.Me Extension'},
				ref : 'screenshareExtensionDownload',
				fieldLabel : _('Download location of the screen sharing extension'),
				width : 200
			});
		}

		Zarafa.plugins.spreedwebrtc.settings.SettingsWebmeetingsWidget.superclass.constructor.call(this, config);
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategory Category} when
	 * it has been called with {@link zarafa.settings.ui.SettingsCategory#update}.
	 * This is used to load the latest version of the settings from the
	 * {@link Zarafa.settings.SettingsModel} into the UI of this category.
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to load
	 */
	update : function(settingsModel)
	{
		this.model = settingsModel;

		var last_start_in_iframe = settingsModel.get('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe');
		var last_start_in_external_window = settingsModel.get('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window');

		// There is popout settings only for Deskapp.
		if (Ext.isDefined(window.deskappOpenWindow)) {
			if (last_start_in_iframe) {
				this.openingWebmeetingsField.setValue('iframe');
			}
			if (last_start_in_external_window) {
				this.openingWebmeetingsField.setValue('popout');
			}
		}
	},

	/**
	 * Called by the {@link Zarafa.settings.ui.SettingsCategory Category} when
	 * it has been called with {@link zarafa.settings.ui.SettingsCategory#updateSettings}.
	 * This is used to update the settings from the UI into the {@link Zarafa.settings.SettingsModel settings model}.
	 * @param {Zarafa.settings.SettingsModel} settingsModel The settings to update
	 */
	updateSettings : function(settingsModel)
	{
		// There is popout settings only in Deskapp.
		if (Ext.isDefined(window.deskappOpenWindow)) {
			var radioGroupValue = this.openingWebmeetingsField.getValue().inputValue;
			if (radioGroupValue == 'popout') {
				settingsModel.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe', false);
				settingsModel.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window', true);
			} else {
				settingsModel.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe', true);
				settingsModel.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window', false);
			}
		}
	},

	/**
	 * Event handler which is called when a selection has been made in the
	 * Preview Panel type {@link Ext.form.ComboBox combobox}.
	 * @param {Ext.form.ComboBox} field The field which fired the event
	 * @param {Ext.data.Record} record The selected record
	 */
	onPreviewSelect : function(field, record)
	{
		if (this.model) {
			var set = record.get(field.valueField);

			// FIXME: The settings model should be able to detect if
			// a change was applied
			if (this.model.get(field.name) !== set) {
				this.model.set(field.name, set);
			}
		}
	},

	/**
	 * Event handler called when checkbox has been modified
	 *
	 * @param {Ext.form.CheckBox} checkbox Checkbox element from which the event originated
	 * @param {Boolean} checked State of the checkbox
	 * @private
	 */
	onCheck : function(checkbox, checked)
	{
		if(this.model) {
			// FIXME: The settings model should be able to detect if
			// a change was applied
			if (this.model.get(checkbox.name) !== checked) {
				this.model.set(checkbox.name, checked);
			}
		}
	},

	/**
	 * Event handler which is fired when a {@link Ext.form.Radio} in the
	 * {@link Ext.form.RadioGroup} has been changed. This will set the value
	 * selected by user in settingsModel.
	 * @param {Ext.form.RadioGroup} group The radio group which fired the event
	 * @param {Ext.form.Radio} radio The radio which was enabled
	 * @private
	 */
	onRadioChange : function(group, radio)
	{
		if (radio.inputValue == 'popout') {
			this.model.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe', false);
			this.model.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window', true);
		} else {
			this.model.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_iframe', true);
			this.model.set('zarafa/v1/plugins/spreedwebrtc/last_start_in_external_window', false);
		}
	}
});

Ext.reg('spreedwebrtc.settingswebmeetingswidget', Zarafa.plugins.spreedwebrtc.settings.SettingsWebmeetingsWidget);
