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

/**
 * @class Zarafa.plugins.browsercompatibility.ABOUT
 * @extends String
 *
 * The copyright string holding the copyright notice for the Zarafa browsercompatibility Plugin.
 */
Zarafa.plugins.browsercompatibility.ABOUT = ""
	+ "<p>Copyright (C) 2005 - 2015  Zarafa B.V. &lt;info@zarafa.com&gt; and its licensors</p>"

	+ "<p>This program is free software: you can redistribute it and/or modify "
	+ "it under the terms of the GNU Affero General Public License as "
	+ "published by the Free Software Foundation, either version 3 of the "
	+ "License, or (at your option) any later version.</p>"

	+ "<p>This program is distributed in the hope that it will be useful, "
	+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
	+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
	+ "GNU Affero General Public License for more details.</p>"

	+ "<p>You should have received a copy of the GNU Affero General Public License "
	+ "along with this program.  If not, see <a href=\"http://www.gnu.org/licenses/\">http://www.gnu.org/licenses/</a>.</p>";
Ext.namespace('Zarafa.plugins.browsercompatibility');

/**
 * @class Zarafa.plugins.browsercompatibility.BrowserCompatibility
 * @extends Zarafa.core.Plugin
 *
 * Plugin is used to check current name and version of browser that is used by user and if it is
 * not supported then it will show a warning message to user to upgrade the browser or change the browser
 * for better experience.
 */
Zarafa.plugins.browsercompatibility.BrowserCompatibility = Ext.extend(Zarafa.core.Plugin, {
	/**
	 * Object that contains list of base supported browsers.
	 * Key will be browser name and value will indicate least supported version for that browser.
	 * @property
	 * @type Object
	 */
	baseSupportedBrowsers : { 'Firefox' : 5 , 'Safari' : 5.1 , 'Explorer' : 9 , 'ZDI' : 0, 'Chrome' : 28 },

	/**
	 * Add listener for load event of {@link Zarafa.hierarchy.data.HierarchyStore HierarchyStore}.
	 * @protected
	 */
	initPlugin : function()
	{
		Zarafa.plugins.browsercompatibility.BrowserCompatibility.superclass.initPlugin.apply(this, arguments);

		container.getHierarchyStore().on('load', this.checkBrowser, this, { single: true });
	},

	/**
	 * Identify the current browser by which user is accessing WebApp and find out that it is supported by webapp.
	 * if it is not supported by WebApp then a warning message will be shown to user.
	 */
	checkBrowser : function()
	{
		var browserDetect = Zarafa.plugins.browsercompatibility.BrowserDetect;
		var currentBrowser = browserDetect.getCurrentBrowserName();
		var currentOS = browserDetect.getCurrentOS();
		var messageToDisplay = '';

		// Check if we are supporting the browser name
		if(Ext.isDefined(this.baseSupportedBrowsers[currentBrowser])) {
			// if we support the browser then we need to check for browser version
			var currentVersion = browserDetect.getCurrentBrowserVersion();
			// check version should be higher then base supported version for browser
			if(this.baseSupportedBrowsers[currentBrowser] <= parseFloat(currentVersion)) {
				return;
			} else {
				/*
				 * check for browser compatibility mode is currently on for Internet Explorer
				 * IE9 | MSIE 10.0 | Trident/6.0
				 * IE9 | MSIE 9.0  | Trident/5.0
				 * IE8 | MSIE 8.0  | Trident/4.0
				 * IE7 | MSIE 7.0  | No Trident token
				 * IE6 | MSIE 6.0  | No Trident token
				 * Now, whenever detected browser is less than IE9 at that time we have to worry
				 * about browser compatibility mode detection.
				 * Second thing is how to detect compatibility mode?
				 * There are two cases
				 * 1) if detected browser is IE8 ( Trident/4.0 Available ) than actual browsers may be IE9, IE10
				 * 2) if detected browser is IE7 ( No Trident Token Available) than actual browsers may be IE8, IE9, IE10
				 */
				if(currentBrowser == 'Explorer') {
					var currentRenderingEngineVersion = browserDetect.getCurrentRenderingEngineVersion();
					if ( currentVersion == 8 && currentRenderingEngineVersion != 4 ) {
						messageToDisplay = _('Running Internet Explorer in compatibility mode is not supported.');
					} else if ( currentVersion == 7 && currentRenderingEngineVersion >= 4 ) {
						messageToDisplay = _('Running Internet Explorer in compatibility mode is not supported.');
					}
				}

				if (Ext.isEmpty(messageToDisplay)) {
					// version is lower then generate string to indicate user that he needs to upgrade browser
					/*
					 * # TRANSLATORS: {0} is browser name by which user is accessing WebApp,
					 * # {1} is version of browser by which user is accessing WebApp,
					 * # {2} is least supported version number.
					 */
					messageToDisplay = String.format(_('{0} version {1} is not supported by WebApp.<br/>Use version {2} or above.'), currentBrowser, currentVersion, this.baseSupportedBrowsers[currentBrowser]);
				}
			}
		} else {
			var suggestedBrowser = '';

			if(currentOS == 'Mac') {
				suggestedBrowser = 'Apple Safari or Google Chrome';
			} else {
				/*
				 * For linux default browser is firefox, so suggest to use it
				 * For windows default browser is IE but obviously we don't want to suggest it
				 * so suggest firefox here also
				 */
				suggestedBrowser = 'Mozilla Firefox or Google Chrome';
			}

			// generate string to show user recommended browser to use
			/*
			 * # TRANSLATORS: {0} is browser name by which user is accessing WebApp,
			 * # {1} is a suggested browser name to access WebApp,
			 * # {2} is name of user's operating system.
			 */
			messageToDisplay = String.format(_('{0} is not supported by WebApp.<br/>It is recommended to use latest version of {1} on {2}.'), currentBrowser, suggestedBrowser, currentOS);
		}

		container.getNotifier().notify('info.browsercompatibility', _('Unsupported Browser'), messageToDisplay, {
			persistent : true,
			listeners : {
				'click' : this.onNotifierClick,
				'scope': this
			}
		});
	},

	/**
	 * Event handler which is fired when the user clicked on the {@link Zarafa.core.ui.notifier.Notifier notification}.
	 * This will remove the notification.
	 * @param {Ext.Element} element The notification element
	 * @param {Ext.EventObject} event The event object
	 * @private
	 */
	onNotifierClick : function(element, event)
	{
		container.getNotifier().notify('info.browsercompatibility', null, null, {
			reference : element,
			destroy : true
		});
	}
});

Zarafa.onReady(function() {
	container.registerPlugin(new Zarafa.core.PluginMetaData({
		name : 'browsercompatibility',
		displayName : _('Browser Compatibility Plugin'),
		about : Zarafa.plugins.browsercompatibility.ABOUT,
		pluginConstructor : Zarafa.plugins.browsercompatibility.BrowserCompatibility
	}));
});
Ext.namespace('Zarafa.plugins.browsercompatibility');

/**
 * @class Zarafa.plugins.browsercompatibility.BrowserDetect
 * @singleton
 *
 * The Singleton class can be used to get user's browser name, version and OS.
 */
Zarafa.plugins.browsercompatibility.BrowserDetect = function() {
	/**
	 * The browser name by which user is currently accessing WebApp.
	 * @property
	 * @type String
	 * @private
	 */
	var currentBrowser = undefined;

	/**
	 * The browser version of the current browser by which user is currently accessing WebApp.
	 * @property
	 * @type String
	 * @private
	 */
	var currentBrowserVersion = undefined;

	/**
	 * The Operating System of user.
	 * @property
	 * @type String
	 * @private
	 */
	var currentOS = undefined;

	/**
	 * The browser rendering engine version of the current browser by which user is currently accessing WebApp.
	 * @property
	 * @type String
	 * @private
	 */
	var currentRenderingEngineVersion = undefined;

	/**
	 * The array which contains list of browsers identification information.
	 * @property
	 * @type Array
	 */
	var browsersIdentificationData = [{
			string: navigator.userAgent,
			subString: 'ZDI',
			identity: 'ZDI',
			versionSearch: 'ZDI'
		}, {
			// new version of opera > v12
			string: navigator.userAgent,
			subString : 'OPR',
			identity: 'Opera',
			versionSearch: 'OPR',
			renderingEngineVersion: 'AppleWebKit'
		}, {
			string: navigator.userAgent,
			subString: 'Chromium',
			identity: 'Chromium',
			renderingEngineVersion: 'AppleWebKit'
		}, {
			string: navigator.userAgent,
			subString: 'Chrome',
			identity: 'Chrome',
			renderingEngineVersion: 'AppleWebKit'
		}, {
			string: navigator.userAgent,
			subString: 'OmniWeb',
			versionSearch: 'OmniWeb/',
			identity: 'OmniWeb'
		}, {
			string: navigator.userAgent,
			subString: 'Apple',
			identity: 'Safari',
			versionSearch: 'Version',
			renderingEngineVersion: 'AppleWebKit'
		}, {
			// old version of opera < v12
			prop: window.opera,
			identity: 'Opera',
			versionSearch: 'Version',
			renderingEngineVersion: 'Presto'
		}, {
			string: navigator.vendor,
			subString: 'iCab',
			identity: 'iCab',
			renderingEngineVersion: 'AppleWebKit'
		}, {
			string: navigator.vendor,
			subString: 'KDE',
			identity: 'Konqueror',
			renderingEngineVersion: 'KHTML'
		}, {
			string: navigator.userAgent,
			subString: 'Firefox',
			identity: 'Firefox',
			renderingEngineVersion: 'Gecko'
		}, {
			string: navigator.vendor,
			subString: 'Camino',
			identity: 'Camino',
			renderingEngineVersion: 'Gecko'
		}, {
			// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: 'Netscape',
			identity: 'Netscape',
			renderingEngineVersion: 'Gecko'
		}, {
			string: navigator.userAgent,
			subString: 'MSIE',
			identity: 'Explorer',
			versionSearch: 'MSIE',
			renderingEngineVersion: 'Trident'
		}, {
			string: navigator.userAgent,
			subString: 'Trident',
			identity: 'Explorer',
			versionSearch: 'rv',
			renderingEngineVersion: 'Trident'
		}, {
			string: navigator.userAgent,
			subString: 'Gecko',
			identity: 'Mozilla',
			versionSearch: 'rv',
			renderingEngineVersion: 'Gecko'
		}, {
			// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: 'Mozilla',
			identity: 'Netscape',
			versionSearch: 'Mozilla',
			renderingEngineVersion: 'Gecko'
		}
	];

	/**
	 * The array which contains list of OS identification information.
	 * @property
	 * @type Array
	 */
	var osIdentificationData = [{
			string: navigator.platform,
			subString: 'Win',
			identity: 'Windows'
		}, {
			string: navigator.platform,
			subString: 'Mac',
			identity: 'Mac'
		}, {
			string: navigator.userAgent,
			subString: 'iPhone',
			identity: 'iPhone/iPod'
		}, {
			string: navigator.platform,
			subString: 'Linux',
			identity: 'Linux'
		}
	];

	/**
	 * It detects current browser name by using available identification information respect to the browser itself.
	 * Iteratively checks that {@link #browsersIdentificationData[].string}
	 * contains {@link #browsersIdentificationData[].subString} or not.
	 * @param {Array} data Contains browsers identification information.
	 */
	var detectBrowserName = function(data)
	{
		for (var i=0, len=data.length; i<len; i++) {
			var dataString = data[i].string;
			var dataProp = data[i].prop;

			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1) {
					return data[i].identity;
				}
			} else if (dataProp) {
				return data[i].identity;
			}
		}
	};

	/**
	 * It detects current browser version by using available identification information respect to the browser version itself.
	 * Iteratively checks that {@link #browsersIdentificationData[].string}
	 * contains {@link #browsersIdentificationData[].versionSearch} or not,
	 * Extracts version information and returns it back.
	 * @param {Array} data Contains browsers identification information.
	 */
	var detectBrowserVersion = function(data)
	{
		for (var i=0, len=data.length; i<len; i++) {
			var dataString = data[i].string;
			var dataProp = data[i].prop;

			var versionSearchString = data[i].versionSearch || data[i].identity;

			if (dataString) {
				var index = dataString.indexOf(versionSearchString);
				if (index != -1) {
					return parseFloat(dataString.substring(index + versionSearchString.length + 1));
				}
			}
			else if (dataProp) {
				return dataString.version();
			}
		}
	};

	/**
	 * It detects current browser Rendering Engine version by using available identification information
	 * respect to the browser Rendering Engine version itself.
	 * Iteratively checks that {@link #browsersIdentificationData[].string}
	 * contains {@link #browsersIdentificationData[].renderingEngineVersion} or not,
	 * Extracts version information and returns it back.
	 * @param {Array} data Contains browsers identification information.
	 */
	var detectRenderingEngineVersion = function(data)
	{
		for (var i=0, len=data.length; i<len; i++) {
			var dataString = data[i].string;

			var renderingEngineVersionSearchString = data[i].renderingEngineVersion;

			if (dataString) {
				var index = dataString.indexOf(renderingEngineVersionSearchString);

				if (index != -1) {
					return parseFloat(dataString.substring(index + renderingEngineVersionSearchString.length + 1));
				}
			}
		}
	};

	/**
	 * It detects current OperatingSystem by using available Operating System identification information.
	 * Iteratively checks that {@link #osIdentificationData[].string}
	 * contains {@link #browsersIdentificationData[].subString} or not.
	 * @param {Array} data Contains Operating System identification information.
	 */
	var detectBrowserOS = function(data)
	{
		for (var i=0, len=data.length; i<len; i++) {
			var dataString = data[i].string;
			var dataProp = data[i].prop;

			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1) {
					return data[i].identity;
				}
			} else if (dataProp) {
				return data[i].identity;
			}
		}
	};

	return {
		/**
		 * Returns {@link #currentBrowser} if it is defined otherwise detect browser by {@link #detectBrowserName},
		 * assign it to the {@link #currentBrowser} and returns back.
		 */
		getCurrentBrowserName : function()
		{
			return currentBrowser || (currentBrowser = detectBrowserName(browsersIdentificationData));
		},

		/**
		 * Returns {@link #currentBrowserVersion} if it is defined otherwise detect browser by {@link #detectBrowserVersion},
		 * assign it to the {@link #currentBrowserVersion} and returns back.
		 */
		getCurrentBrowserVersion : function()
		{
			return currentBrowserVersion || (currentBrowserVersion = detectBrowserVersion(browsersIdentificationData));
		},

		/**
		 * Returns {@link #currentRenderingEngineVersion} if it is defined otherwise detect browser by {@link #detectRenderingEngineVersion},
		 * assign it to the {@link #currentRenderingEngineVersion} and returns back.
		 */
		getCurrentRenderingEngineVersion : function()
		{
			return currentRenderingEngineVersion || (currentRenderingEngineVersion = detectRenderingEngineVersion(browsersIdentificationData));
		},

		/**
		 * Returns {@link #currentOS} if it is defined otherwise detect browser by {@link #detectBrowserOS},
		 * assign it to the {@link #currentOS} and returns back.
		 */
		getCurrentOS : function()
		{
			return currentOS || (currentOS = detectBrowserOS(osIdentificationData));
		}
	}
};

Zarafa.plugins.browsercompatibility.BrowserDetect = new Zarafa.plugins.browsercompatibility.BrowserDetect();