/* --------------------------------------------------------------
 fallback.js 2016-09-08
 Gambio GmbH
 http://www.gambio.de
 Copyright (c) 2016 Gambio GmbH
 Released under the GNU General Public License (Version 2)
 [http://www.gnu.org/licenses/gpl-2.0.html]
 --------------------------------------------------------------
 */

jse.libs.fallback = jse.libs.fallback || {};

/**
 * ## Fallback Library
 *
 * This library contains a set of deprecated functions that are still present for fallback support. Do not
 * use these methods in new modules.
 * 
 * @module JSE/Libs/fallback
 * @exports jse.libs.fallback
 */
(function(exports) {
	
	'use strict';
	
	/**
	 * Add ":attr" pseudo selector.
	 *
	 * This pseudo selector is normally enabled by including the JSEngine "jquery_extensions" library. Honeygrid
	 * through needs this pseudo selector in this library which might be loaded prior to jquery_extensions and
	 * this is why we define it once again in this file.
	 */
	if ($.expr.pseudos.attr === undefined) {
		$.expr.pseudos.attr = $.expr.createPseudo(function(selector) {
			let regexp = new RegExp(selector);
			return function(elem) {
				for(let i = 0; i < elem.attributes.length; i++) {
					let attr = elem.attributes[i];
					if(regexp.test(attr.name)) {
						return true;
					}
				}
				return false;
			};
		});
	}
	
	/**
	 * Add a fallback usage warning in the console.
	 *
	 * As the JS engine evolves many old features will need to be changed in order to let a finer and clearer
	 * API for the JS Engine core mechanisms. Use this method to create a fallback usage warning for the functions
	 * placed within this library.
	 *
	 * @param {String} functionName The deprecated function name.
	 *
	 * @private
	 */
	function _warn(functionName) {
		jse.core.debug.warn(`jse.libs.fallback.${functionName} was called! `
			+ `Avoid the use of fallback methods in new modules.`);
	}
	
	/**
	 * Get the module related data of the provided element. 
	 * 
	 * @param {jQuery} $element
	 * @param {String} moduleName
	 * 
	 * @return {Object}
	 */
	exports._data = function($element, moduleName) {
		_warn('_data');
		
		let initialData = $element.data(),
			filteredData = {};
		
		// Searches for module relevant data inside the main-data-object.
		// Data for other widgets will not get passed to this widget
		$.each(initialData, (key, value) => {
			if (key.indexOf(moduleName) === 0 || key.indexOf(moduleName.toLowerCase()) === 0) {
				let newKey = key.substr(moduleName.length);
				newKey = newKey.substr(0, 1).toLowerCase() + newKey.substr(1);
				filteredData[newKey] = value;
			}
		});
		
		return filteredData;
	};
	
	/**
	 * Setup Widget Attribute
	 *
	 * @param {Object} $element Change the widget attribute of an element.
	 */
	exports.setupWidgetAttr = function($element) {
		_warn('setupWidgetAttr');
		
		$element
			.filter(':attr(^data-gx-_), :attr(^data-gambio-_), :attr(^data-jse-_)')
			.add($element.find(':attr(^data-gx-_), :attr(^data-gambio-_), :attr(^data-jse-_)'))
			.each(function() {
				let $self = $(this),
					attributes = $self[0].attributes,
					matchedAttribute,
					namespaceName;
				
				$.each(attributes, function(index, attribute) {
					if (attribute === undefined) {
						return true; // wrong attribute, continue loop
					}
					
					matchedAttribute = attribute.name.match(/data-(gambio|gx|jse)-_.*/g);
					
					if (matchedAttribute !== null && matchedAttribute.length > 0) {
						namespaceName = matchedAttribute[0].match(/(gambio|gx|jse)/g)[0];
						
						$self
							.attr(attribute.name.replace('data-' + namespaceName + '-_',
								'data-' + namespaceName + '-'), attribute.value);
					}
				});
			});
	};
	
	/**
	 * Get URL parameters.
	 *
	 * @param {String} url
	 * @param {Boolean} deep
	 *
	 * @return {Object}
	 */
	exports.getUrlParams = function(url, deep) {
		_warn('getUrlParams');
		
		url = decodeURIComponent(url || location.href);
		
		let splitUrl = url.split('?'),
			splitParam = (splitUrl.length > 1) ? splitUrl[1].split('&') : [],
			regex = new RegExp(/\[(.*?)\]/g),
			result = {};
		
		$.each(splitParam, function(i, v) {
			let keyValue = v.split('='),
				regexResult = regex.exec(keyValue[0]),
				base = null,
				basename = keyValue[0].substring(0, keyValue[0].search('\\[')),
				keys = [],
				lastKey = null;
			
			if (!deep || regexResult === null) {
				result[keyValue[0]] = keyValue[1].split('#')[0];
			} else {
				
				result[basename] = result[basename] || [];
				base = result[basename];
				
				do {
					keys.push(regexResult[1]);
					regexResult = regex.exec(keyValue[0]);
				} while (regexResult !== null);
				
				$.each(keys, function(i, v) {
					let next = keys[i + 1];
					v = v || '0';
					
					if (typeof (next) === 'string') {
						base[v] = base[v] || [];
						base = base[v];
					} else {
						base[v] = base[v] || undefined;
						lastKey = v;
					}
				});
				
				if (lastKey !== null) {
					base[lastKey] = keyValue[1];
				} else {
					base = keyValue[1];
				}
			}
			
		});
		
		return result;
	};
	
	/**
	 * Fallback getData method.
	 *
	 * This method was included in v1.0 of JS Engine and is replaced by the
	 * "jse.libs.form.getData" method.
	 *
	 * @param {Object} $form Selector of the form to be parsed.
	 * @param {String} ignore (optional) jQuery selector string of form elements to be ignored.
	 *
	 * @return {Object} Returns the data of the form as an object.
	 */
	exports.getData = function ($form, ignore) {
		_warn('getData');
		
		let $elements = $form.find('input, textarea, select'),
			result = {};
		
		if (ignore) {
			$elements = $elements.filter(':not(' + ignore + ')');
		}
		
		$elements.each(function () {
			let $self = $(this),
				type = $self.prop('tagName').toLowerCase(),
				name = $self.attr('name'),
				$selected = null;
			
			type = (type !== 'input') ? type : $self.attr('type').toLowerCase();
			
			switch (type) {
				case 'radio':
					$form
						.find('input[name="' + name + '"]:checked')
						.val();
					break;
				case 'checkbox':
					if (name.search('\\[') !== -1) {
						if ($self.prop('checked')) {
							name = name.substring(0, name.search('\\['));
							if (result[name] === undefined) {
								result[name] = [];
							}
							result[name].push($(this).val());
						}
					} else {
						result[name] = $self.prop('checked');
					}
					break;
				case 'select':
					$selected = $self.find(':selected');
					if ($selected.length > 1) {
						result[name] = [];
						$selected.each(function () {
							result[name].push($(this).val());
						});
					} else {
						result[name] = $selected.val();
					}
					break;
				case 'button':
					break;
				default:
					if (name) {
						result[name] = $self.val();
					}
					break;
			}
		});
		return result;
	};
	
})(jse.libs.fallback);