/**
 * eGroupware Framework browser object
 * @package framework
 * @author Hadi Nategh <hn@stylite.de>
 * @copyright Stylite AG 2014
 * @description Framework browser object, is implementation of browser class in order to display application content
 */

/*egw:uses
	vendor.bower-asset.jquery.dist.jquery;
	egw_action.egw_action_common;
	egw_inheritance.js;
*/

import '../egw_action/egw_action_common';
import '../jsapi/egw_inheritance.js';
import '../etemplate/etemplate2';	// otherwise et2_load json-response-handler is not (yet) available

/**
 * Constants definition
 */
window.EGW_BROWSER_TYPE_NONE = 0;
window.EGW_BROWSER_TYPE_IFRAME = 1;
window.EGW_BROWSER_TYPE_DIV = 2;

window.fw_browser = (function(){ "use strict"; return Class.extend(
{
	/**
	 * @param {string} _app
	 * @param {function} _heightCallback
	 * Framework browser class constructor
	 */
	init: function (_app, _heightCallback){
		//Create a div which contains both, the legacy iframe and the contentDiv
		this.baseDiv = document.createElement('div');
		this.type = EGW_BROWSER_TYPE_NONE;
		this.iframe = null;
		this.contentDiv = null;
		this.heightCallback = _heightCallback;
		this.app = _app;
		this.currentLocation = '';
		this.ajaxLoaderDiv = null;
		this.loadingDeferred = null;
	},

	/**
	 * Triggers resize event on window
	 */
	callResizeHandler: function()
	{
		var wnd = window;
		if (this.iframe)
		{
			wnd = this.iframe.contentWindow;
		}

		// Call the resize handler (we have to use the jquery object of the iframe!)
		try {
			if (wnd && typeof wnd.jQuery != "undefined") {
				wnd.jQuery(wnd).trigger("resize");
			}
		} catch(e) {}	// ignore if iframe runs of a different origin
	},

	/**
	* Resizes both, the contentDiv and the iframe to the size returned from the heightCallback
	*/
	resize: function()
	{
		var height = this.heightCallback.call(this.iframe) + 'px';

		//Set the height of the content div or the iframe
		if (this.contentDiv)
		{
			this.contentDiv.style.height = height;
		}
		if (this.iframe)
		{
			this.iframe.style.height = height;
		}
	},

	/**
	 * Sets browser type either DIV or IFRAME
	 *
	 * @param {int} _type
	 */
	setBrowserType: function(_type)
	{
		//Only do anything if the browser type has changed
		if (_type != this.type)
		{
			//Destroy the iframe and/or the contentDiv
			jQuery(this.baseDiv).empty();
			this.iframe = null;
			this.contentDiv = null;
			if(this.loadingDeferred && this.type)
			{
				this.loadingDeferred.reject();
			}

			switch (_type)
			{
				//Create the div for displaying the content
				case EGW_BROWSER_TYPE_DIV:
					this.contentDiv = document.createElement('div');
					jQuery(this.contentDiv).addClass('egw_fw_content_browser_div');
					jQuery(this.baseDiv).append(this.contentDiv);

					break;

				case EGW_BROWSER_TYPE_IFRAME:
					//Create the iframe
					this.iframe = document.createElement('iframe');
					this.iframe.style.width = "100%";
					this.iframe.style.borderWidth = 0;
					this.iframe.frameBorder = 0;
					this.iframe.name = 'egw_app_iframe_' + this.app.appName;
					jQuery(this.iframe).addClass('egw_fw_content_browser_iframe');
					jQuery(this.baseDiv).append(this.iframe);

					break;
			}

			this.resize();
			this.type = _type;
		}
	},

	/**
	 * Sets url to browse and load the content in proper content browser
	 * @param {string} _url
	 * @return {Deferred} Returns a Deferred promise object
	 */
	browse: function(_url)
	{
		// check if app has its own linkHandler and it accepts the link (returns true), or returns different url instead
		if (typeof app == 'object' && typeof app[this.app.appName] == 'object' &&
				typeof app[this.app.appName].linkHandler == 'function')
		{
			var ret = app[this.app.appName].linkHandler.call(app[this.app.appName], _url);
			{
				if (ret === true) return this.loadingDeferred.promise();
				if (typeof ret === 'string')
				{
					_url = ret;
				}
			}
		}
		var useIframe = true;
		var targetUrl = _url;
		if(_url == this.currentLocation && this.loadingDeferred != null)
		{
			// Still loading
			return this.loadingDeferred.promise();
		}

		// Show loader div, start blocking
		var self = this;
		this.ajaxLoaderDiv = egw.loading_prompt(this.app.appName,true,egw.lang('please wait...'),this.baseDiv, egwIsMobile()?'horizental':'spinner');
		this.loadingDeferred = new jQuery.Deferred();

		// Try to escape from infinitive not resolved loadingDeferred
		// At least user can close the broken tab and work with the others.
		// Define a escape timeout for 5 sec
		this.ajaxLoaderDivTimeout = setTimeout(function(){
			(self.ajaxLoaderDiv || jQuery('div.loading')).hide().remove();
			self.ajaxLoaderDiv = egw.loading_prompt(self.app.appName,false);
		},5000);

		this.loadingDeferred.always(function() {
			framework.firstload_animation(self.app.appName,
				framework.activeApp.appName == self.app.appName
				&& !self.app.browser.contentDiv? 100 : null);
			if(self.ajaxLoaderDiv)
			{

				self.ajaxLoaderDiv = egw.loading_prompt(self.app.appName,false);
				// Remove escape timeout
				clearTimeout(self.ajaxLoaderDivTimeout);
			}


		});

		// Check whether the given url is a pseudo url which should be executed
		// by calling the ajax_exec function
		// we now send whole url back to server, so apps can use $_GET['ajax']==='true'
		// to detect app-icon was clicked and eg. further reset filters
		var matches = _url.match(/\/index.php\?menuaction=([A-Za-z0-9_\.]*.*&ajax=true.*)$/);
		if (matches) {
			// Matches[1] contains the menuaction which should be executed - replace
			// the given url with the following line. This will be evaluated by the
			// jdots_framework ajax_exec function which will be called by the code
			// below as we set useIframe to false.
			targetUrl = "index.php?menuaction=" + matches[1];
			useIframe = false;
		}

		// Destroy application js
		if(app[this.app.appName] && app[this.app.appName].destroy)
		{
			app[this.app.appName].destroy();
			delete app[this.app.appName];	// really delete it, so new object get constructed and registered for push
		}

		// Unload etemplate2, if there
		if(typeof etemplate2 == "function")
		{
			// Clear all etemplates on this tab, regardless of application, by using DOM nodes
			jQuery('.et2_container',this.contentDiv||this.baseDiv).each(function() {
				var et = etemplate2.getById(this.id);
				if(et !== null)
				{
					et.clear();
					// Clean up DOM nodes that are outside the etemplate2
					const domContainer = et.DOMContainer;
					domContainer.parentNode?.querySelector("[name='egw_iframe_autocomplete_helper']")?.remove();
					domContainer.remove();
					et._DOMContainer = null;
				}
			});
		}
		else if(this.iframe && typeof this.iframe.contentWindow.etemplate2 == "function")
		{
			try
			{
				if(typeof this.iframe.contentWindow.etemplate2 == "function")
				{
					// Clear all etemplates on this tab, regardless of application, by using DOM nodes
					var content = this.iframe.contentWindow;
					jQuery('.et2_container',this.iframe.contentDocument).each(function() {
						var et = content.etemplate2.getById(this.id);
						if(et !== null)
						{
							et.clear();
						}
					});
				}
			}
			catch(e) {}	// catch error if eg. SiteMgr runs a different origin, otherwise tab cant be closed
		}

		// Save the actual url which has been passed as parameter
		this.currentLocation = _url;

		//Set the browser type
		if (useIframe)
		{
			this.setBrowserType(EGW_BROWSER_TYPE_IFRAME);

			//Postpone the actual "navigation" - gives some speedup with internet explorer
			//as it does no longer blocks the complete page until all frames have loaded.
			window.setTimeout(function() {
				//set iframe resource permissions
				self.iframe.setAttribute('allow', 'fullscreen');
				self.iframe.setAttribute('allowfullscreen', true); // for older browsers

				// for own origin: bind load handler to set overflow-y: auto on body of contentDocument to allow vertical scrolling
				if (_url[0] === '/' || top.location.origin === _url.replace(/^(https?:\/\/[^/]+)\/.*$/, '$1'))
				{
					self.iframe.addEventListener('load', (ev) => {
						const body = self.iframe.contentDocument.getElementsByTagName('body')[0];
						body.style.overflowY = 'auto';
					});
				}

				//Load the iframe content
				self.iframe.src = _url;

				//Set the "_legacy_iframe" flag to allow link handlers to easily determine
				//the type of the link source
				if (self.iframe && self.iframe.contentWindow) {
					try {
						self.iframe.contentWindow._legacy_iframe = true;

						// Focus the iframe of the current application
						if (self.app == framework.activeApp)
						{
							self.iframe.contentWindow.focus();
						}
					}
					catch (e) {
						// ignore SecurityError: Blocked a frame ..., caused by different origin
					}
				}

				if(self.loadingDeferred)
				{
					self.loadingDeferred.resolve();
					self.loadingDeferred = null;
				}
			}, 1);
		}
		else
		{
			this.setBrowserType(EGW_BROWSER_TYPE_DIV);

			//Special treatement of "about:blank"
			if (targetUrl == "about:blank")
			{
				if (this.app.sidemenuEntry)
					this.app.sidemenuEntry.hideAjaxLoader();

				egw_widgetReplace(this.app.appName, this.contentDiv, '');
			}
			else
			{
				//Perform an AJAX request loading application output
				if (this.app.sidemenuEntry)
					this.app.sidemenuEntry.showAjaxLoader();
				this.data = "";
				jQuery(this.contentDiv).empty();
				var self_egw = egw(this.app.appName);
				var req = self_egw.json(
					this.app.getMenuaction('ajax_exec', targetUrl),
					[targetUrl], this.browse_callback,this, true, this
				);
				req.sendRequest();
			}
		}
		return this.loadingDeferred.promise();
	},

	/**
	 *
	 * @param {type} _data
	 * @return {undefined} return undefined if data is not from the right response
	 */
	browse_callback: function(_data)
	{
		// Abort if data is from wrong kind of response - only 'data'
		if(!_data || _data.type != undefined) return;

		this.data = _data[0];
		this.browse_finished();
	},

	/**
	 *  Get call via browse_callback in order to attaching nodes to the DOM
	 */
	browse_finished: function()
	{
		if (this.app.sidemenuEntry)
			this.app.sidemenuEntry.hideAjaxLoader();
	//	egw_widgetReplace(this.app.appName, this.contentDiv, this.data);
		var content = {
			html: this.data,
			js: ''
		};

		if (this.app == framework.activeApp)
		{
			window.focus();
		}

		egw_seperateJavaScript(content);

		// Insert the content
		jQuery(this.contentDiv).append(content.html);

		// Run the javascript code
		//console.log(content.js);
		jQuery(this.contentDiv).append(content.js);

		if(this.loadingDeferred)
		{
			this.loadingDeferred.resolve();
		}
	},

	/**
	 * REload the content of the browser object
	 */
	reload: function()
	{
		switch (this.type)
		{
			case EGW_BROWSER_TYPE_DIV:
				this.browse(this.currentLocation);
				break;

			case EGW_BROWSER_TYPE_IFRAME:
				//Do a simple reload in the iframe case
				this.iframe.contentWindow.location.reload();
				break;
		}
	},

	/**
	 *
	 */
	blank: function()
	{
		this.browse('about:blank', this.type == EGW_BROWSER_TYPE_IFRAME);
	}
});}).call(window);