/* --------------------------------------------------------------
 group_check.js 2017-10-10
 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]
 --------------------------------------------------------------
 */

/**
 * ## Group check widget
 *
 * The widget creates a panel with switcher fields for all customer groups. If the options "user" and "section" are
 * provided, the user configuration service will be used to store the panels collapsed/expanded state.
 *
 * ### Options (Required)
 *
 * **User | `data-panel-user` | Integer | Optional**
 *
 * Customer id of user, used by user configuration service to store the collapsed state.
 *
 * **Section | `data-panel-section` | String | Optional**
 *
 * Panel section, used by user configuration service 'configuration_key'. The value get a "**'group_check_'**"-prefix.
 *
 * ### Options (Additional)
 *
 * **Selected | `data-group_check-selected` | String | Additional**
 *
 * Comma separated list of customer status ids. If an switcher value is equal to one of the customer ids, the
 * switcher state is active. Alternatively you can set the value "all" to set all switchers to an active state.
 *
 * **Name | `data-group_check-name` | String | Additional**
 *
 * Name attribute of switchers hidden input:checkbox field. If no value is provided, it defaults to **'group_check'**
 *
 * ### Example
 *
 * * ```html
 * <div data-gx-widget="group_check"
 *      data-group_check-user="{$smarty.session.customer_id}"
 *      data-group_check-section="group-check-sample-section"
 *      data-group_check-active="[1,2,3]|[all]"
 *      data-group_check-name="custom-switcher-name"></div>
 * ```
 *
 * @module Admin/Widgets/group_check
 */
gx.widgets.module(
    'group_check',

    ['xhr'],

    /** @lends module:Widgets/group_check */

    function (data) {

        'use strict';

        // ------------------------------------------------------------------------
        // VARIABLE DEFINITION
        // ------------------------------------------------------------------------

        /**
         * Widget Reference
         *
         * @type {object}
         */
        const $this = $(this);

        /**
         * Default Widget Options
         *
         * @type {object}
         */
        const defaults = {
            name: 'group_check'
        };

        /**
         * Final Widget Options
         *
         * @type {object}
         */
        const options = $.extend(true, {}, defaults, data);

        /**
         * Module Object
         *
         * @type {object}
         */
        const module = {};

        /**
         * Required options.
         *
         * @type {String[]}
         */
        const requiredOptions = ['user', 'section'];

        /**
         * Element for whether selecting or deselecting all other switcher.
         */
        let $allSwitcher;

        /**
         * Renders the group check box.
         *
         * @private
         */
        const _renderGroupCheck = () => {
            jse.libs.xhr.get({
                url: './admin.php?do=JSWidgetsAjax/isGroupCheckEnabled'
            }).done(r => {
                if (r.status) {
                    const $container = $('<div/>', {
                        'data-gx-widget': 'panel switcher',
                        'data-panel-title': jse.core.lang.translate('HEADING_GROUP_CHECK', 'content_manager'),
                        'data-panel-user': options.user,
                        'data-panel-section': 'group_check_' + options.section,
                        'data-panel-container_class': 'group-check'
                    });

                    $container.append(_renderBody(r.customerGroups)).appendTo($this);
                    gx.widgets.init($container).then(() => {
                        _setEventListener();
                        _setSwitcherDefaultStates();
                    });
                }
            });
        };

        /**
         * Sets default state of switcher elements.
         * The "selected" option is used to determine the default state.
         *
         * @private
         */
        const _setSwitcherDefaultStates = () => {
            // just continue if option is not set
            if (undefined === options.selected || options.selected === '') {
                return;
            }

            // use bulk switcher action if option value is set to "all"
            if (options.selected === 'all') {
                $allSwitcher.find('input:checkbox').switcher('checked', true);
                _bulkSwitcherAction(true);
                return;
            }

            // activate switcher programmatically
            let preselection;
            if (Number.isInteger(options.selected)) {
                preselection = [options.selected];
            } else {
                preselection = options.selected.split(',').map(Number);
            }

            const switcher = $this.find('input:checkbox');
            let i = 0;

            for (; i < switcher.length; i++) {
                if (switcher[i].value !== 'all') {
                    if (preselection.indexOf(parseInt(switcher[i].value, 10)) !== -1) {
                        $(switcher[i]).switcher('checked', true);
                    }
                }
            }
            _tryActiveAllSwitcher();
        };

        /**
         * Renders the panel body.
         * @param {Object} customerGroups Serialized customer group collection, provided by ajax request.
         * @returns {jQuery} Panel body html.
         * @private
         */
        const _renderBody = customerGroups => {
            const $gxContainer = $('<div/>', {
                'class': 'gx-container'
            });
            const $fieldSet = $('<fieldset/>');

            $allSwitcher = _renderFormGroup(jse.core.lang.translate('LABLE_GROUPCHECK_ALL', 'content_manager'), 'all');
            $fieldSet.append($allSwitcher);

            let i = 0;
            for (; i < customerGroups.length; i++) {
                $fieldSet.append(_renderFormGroup(customerGroups[i].names[jse.core.config.get('languageCode')
                    .toUpperCase()], customerGroups[i].id));
            }
            $gxContainer.append($fieldSet);

            return $gxContainer;
        };

        /**
         * Renders the form group elements of the group check.
         *
         * @param {string} label Label name.
         * @param {string} value Switchers value attribute.
         * @returns {jQuery} Form group html.
         * @private
         */
        const _renderFormGroup = (label, value) => {
            const $formGroup = $('<div/>', {'class': 'form-group'});
            const $label = $('<label/>', {
                'for': 'customer-groups-' + label.toLowerCase(),
                'class': 'col-md-4',
                'text': label
            });
            const $inputContainer = $('<div/>', {
                'class': 'col-md-6'
            });
            const $input = $('<input/>', {
                'type': 'checkbox',
                'id': 'customer-groups-' + label.toLowerCase(),
                'name': options.name + '[]',
                'value': value,
                'checked': options.all_checked
            });
            $inputContainer.append($input);

            return $formGroup.append($label).append($inputContainer);
        };

        /**
         * Checks if all required options are passed.
         *
         * @private
         */
        const _checkRequiredOptions = () => {
            let i = 0;
            for (; i < requiredOptions.length; i++) {
                if (undefined === options[requiredOptions[i]]) {
                    throw new Error('Required widget option "' + requiredOptions[i] + '" is no set!');
                }
            }
        };

        /**
         * Sets the event listener for the group check widget.
         *
         * @private
         */
        const _setEventListener = () => {
            const switcher = $this.find('input:checkbox');

            // check all switcher if the "all" switcher is clicked
            $allSwitcher.on('change', () => {
                if ($allSwitcher.find('input:checkbox').prop('checked')) {
                    _bulkSwitcherAction(true);
                } else {
                    _bulkSwitcherAction(false);
                }
            });

            switcher.on('change', e => {
                if (!$allSwitcher.find('input:checkbox').is(e.currentTarget)) {
                    // remove checked attribute from "all" switcher if one is deselected
                    if (!$(e.currentTarget).prop('checked')) {
                        $allSwitcher.find('input:checkbox').switcher('checked', false);
                    }

                    _tryActiveAllSwitcher();
                }
            });
        };

        /**
         * This method checks if all other switcher fields instead of "all" are active.
         * If so, the "all" switcher will be activated.
         *
         * @private
         */
        const _tryActiveAllSwitcher = () => {
            const switcher = $this.find('input:checkbox');
            let allChecked = true;
            let i = 0;

            for (; i < switcher.length; i++) {
                if (!$allSwitcher.find('input:checkbox').is($(switcher[i]))) {
                    allChecked = allChecked && $(switcher[i]).prop('checked');
                }
            }
            if (allChecked) {
                $allSwitcher.find('input:checkbox').switcher('checked', true);
            }
        }

        /**
         * Bulk action for whether selecting or deselecting all switcher elements.
         *
         * @param {boolean} checked Status of "checked" property.
         * @private
         */
        const _bulkSwitcherAction = checked => {
            const switcher = $this.find('input:checkbox');
            let i = 0;
            for (; i < switcher.length; i++) {
                if (!$allSwitcher.find('input:checkbox').is($(switcher[i]))) {
                    $(switcher[i]).switcher('checked', checked);
                }
            }
        };

        // ------------------------------------------------------------------------
        // INITIALIZATION
        // ------------------------------------------------------------------------

        /**
         * Initialize method of the widget, called by the engine.
         */
        module.init = done => {
            _checkRequiredOptions();
            _renderGroupCheck();
            done();
        };

        return module;
    });