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

/**
 * ## Switcher Widget
 *
 * This widget originates from the "switcher" mode of the existing checkbox widget. Because of the increased
 * complexity of the old widget code, the switcher mode is now server by this file. Apply the widget in a parent
 * container and it will search and convert all the checkbox/radio instances into switchers.
 *
 * ### Options
 *
 * **On State | `data-switcher-on-state` | String | Optional**
 *
 * Define the content of the "on" state.
 *
 * **Off State | `data-switcher-off-state` | String | Optional**
 *
 * Define the content of the "off" state.
 *
 * **Selector | `data-switcher-selector` | String | Optional**
 *
 * Set the selector of the checkboxes to be converted to switcher instances. It defaults to **input:checkbox**.
 *
 * ### Methods
 *
 * **Checked**
 *
 * ```js
 * // Set the checked value of the single checkbox selection (no change event will be triggered!).
 * $('table input:checkbox').switcher('checked', true);
 * ```
 *
 * ### Examples
 *
 * In the following example the checkbox element will be converted into a single-checkbox instance.
 *
 * ```html
 * <div class="wrapper" data-gx-widget="switcher">
 *   <input type="checkbox" />
 * </div>
 * ```
 *
 * @todo Add method for disabling the switcher widget (e.g. $('#my-switcher').switcher('disabled', true));
 *
 * @module Admin/Widgets/switcher
 */
gx.widgets.module('switcher', [], function (data) {
	
	'use strict';
	
	// ------------------------------------------------------------------------
	// VARIABLES
	// ------------------------------------------------------------------------
	
	/**
	 * Module Selector
	 *
	 * @type {jQuery}
	 */
	const $this = $(this);
	
	/**
	 * Default Options
	 *
	 * @type {Object}
	 */
	const defaults = {
		onState: '<span class="fa fa-check"></span>',
		offState: '<span class="fa fa-times"></span>',
		selector: 'input:checkbox'
	};
	
	/**
	 * Final Options
	 *
	 * @type {Object}
	 */
	const options = $.extend(true, {}, defaults, data);
	
	/**
	 * Module Instance
	 *
	 * @type {Object}
	 */
	const module = {};
	
	// ------------------------------------------------------------------------
	// FUNCTIONS
	// ------------------------------------------------------------------------
	
	/**
	 * Set the "checked" property of the single checkbox instances.
	 *
	 * This method will update the value and display of the widgets without triggering a "change" event.
	 *
	 * @param {Boolean} isChecked The checkbox values will be updated along with their representation.
	 *
	 * @return {jQuery} Returns the jQuery selector for chained calls.
	 */
	function _checked(isChecked) {
		$(this).prop('checked', isChecked);
		_onCheckboxChange.call(this);
		return $(this);
	}
	
	/**
	 * Add Public Module Methods
	 *
	 * Example: $('input:checkbox').switcher('checked', false);
	 */
	function _addPublicMethod() {
		if ($.fn.switcher) {
			return; // Method is already registered.
		}
		
		$.fn.extend({
			switcher: function (action, ...args) {
	            switch (action) {
		            case 'checked':
			            return _checked.apply(this, args);
	            }
            }
        });
	}
	
	/**
	 * On Switcher Click Event
	 *
	 * Delegate the click event to the checkbox elements which will update the DOM accordingly.
	 *
	 * @param {object} event
	 */
	function _onSwitcherClick(event) {
		event.stopPropagation();
		
		if ($(this).hasClass('disabled')) {
			return false; // The switcher is disabled.
		}
		
		const $checkbox = $(this).find('input:checkbox');
		
		$checkbox
			.prop('checked', !$checkbox.prop('checked'))
			.trigger('change');
	}
	
	/**
	 * On Checkbox Change
	 *
	 * This callback will update the display of the widget. It will perform the required animations and set the
	 * respective state classes.
	 */
	function _onCheckboxChange() {
		const $checkbox = $(this);
		const $switcher = $checkbox.parent();
		
		if (!$switcher.hasClass('checked') && $checkbox.prop('checked')) {
			$switcher.addClass('checked');
		} else if ($switcher.hasClass('checked') && !$checkbox.prop('checked')) {
			$switcher.removeClass('checked');
		}
	}
	
	// ------------------------------------------------------------------------
	// INITIALIZATION
	// ------------------------------------------------------------------------
	
	module.init = function (done) {
		_addPublicMethod();
		$this.find(options.selector).each(function () {
			const $checkbox = $(this);
			const title = $checkbox.prop('title') ? `title="${$checkbox.prop('title')}"` : '';
			
			$checkbox
				.wrap(`<div class="switcher" ${title}></div>`)
				.parent()
				.append(`
					<div class="switcher-toggler"></div>
					<div class="switcher-inner">
						<div class="switcher-state-on">${options.onState}</div>
						<div class="switcher-state-off">${options.offState}</div>
					</div>
				`);
			
			// Bind the switcher event handlers.  
			$checkbox
				.parent()
				.on('click', _onSwitcherClick)
				.on('change', 'input:checkbox', _onCheckboxChange);
			
			// Trigger the change event to update the checkbox display.
			_onCheckboxChange.call($checkbox[0]);
		});
		
		done();
	};
	
	return module;
	
});