/* --------------------------------------------------------------
 panel.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]
 --------------------------------------------------------------
 */

/**
 * ## Panel widget
 *
 * This widget creates a panel container and wraps the inner html inside the panel.
 * The user configuration service is used by this widget, so the state (whether collapsed or expanded) is stored
 * by user and will be used on future usages. To make this functionality possible, the options "user" and "section"
 * are required.
 *
 * ### Options (Required)
 *
 * **Title | `data-panel-title` | String | Required**
 *
 * Panels title value.
 *
 * ### Options (Additional)
 *
 * **Collapsed icon class | `data-panel-collapsed_icon_class` | String | Optional**
 *
 * Font awesome class for collapsed icon. If no value is provided, it defaults to **'fa fa-plus-square-o'**.
 *
 * **Expanded icon class | `data-panel-expanded_icon_class` | String | Optional**
 *
 * Font awesome class for expanded icon. If no value is provided, it defaults to **'fa fa-minus-square-o'**.
 *
 * **Container class | `data-panel-container_class` | String | Optional**
 *
 * Additional class attributes. The values will be append to the .panel element.
 *
 * **Toggle time | `data-panel-toggle_time` | String | Optional**
 *
 * Toggle time for collapsing/expanding the panel. If no value is provided, it defaults to **'200'**.
 *
 * **Collapsed | `data-panel-collapsed` | Boolean | Optional **
 *
 * Determines the panels default state. Collapsed if set to true and expanded otherwise. If no value is provided,
 * the user configuration will be used. If no user configuration was found, the default state is expanded.
 *
 * **User | `data-panel-user` | Integer | Optional**
 *
 * Customer id of user, used by user configuration service to store the collapsed state. This option should be set
 * with the "section" option and will be ignored, if the "collapsed" option is set.
 *
 * **Section | `data-panel-section` | String | Optional**
 *
 * Panel section, used by user configuration service 'configuration_key'. This option should be set with the "user"
 * option and will be ignored, if the "collapsed" option is set.
 *
 * ### Example
 *
 * ```html
 * <!-- usage of user configuration -->
 * <div data-gx-widget="panel"
 *      data-panel-title="Panel Title"
 *      data-panel-user="{$smarty.session.customer_id}"
 *      data-panel-section="panel-sample-section"
 *      data-panel-container_class="additional-sample-class">
 *     <div class="sample-class">
 *         <p>Sample Content</p>!
 *     </div>
 * </div>
 *
 * <!-- usage of collapsed option -->
 * <div data-gx-widget="panel"
 *      data-panel-title="Panel Title"
 *      data-panel-container_class="additional-sample-class"
 *      data-panel-collapsed="false|true">
 *     <div class="sample-class">
 *         <p>Sample Content</p>!
 *     </div>
 * </div>
 * ```
 *
 * @module Admin/Widgets/panel
 */
gx.widgets.module(
    'panel',

    // external libraries, used by widget
    ['user_configuration_service'],

    function (data) {
        'use strict';

        /**
         * Widget reference.
         *
         * @type {jQuery}
         */
        const $this = $(this);

        /**
         * Default options for widget,
         *
         * @type {object}
         */
        const defaults = {
            collapsed_icon_class: 'fa fa-plus-square-o',
            expanded_icon_class: 'fa fa-minus-square-o',
            container_class: '',
            toggle_time: 200
        };

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

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

        /**
         * Required widget options, should passed from markup.
         *
         * @type {String[]}
         */
        const requiredOptions = ['title', 'user', 'section'];

        /**
         * User configuration service to store collapsed/expanded configuration.
         *
         * @type {jse.libs.user_configuration_service}
         */
        const userConfig = jse.libs.user_configuration_service;

        /**
         * Property like values.
         */
        let $iconContainer;
        let $collapseIcon;
        let $panelBody;

        // private methods

        /**
         * Widget initialization.
         *
         * @private
         */
        const _init = () => {
            let collapsed;

            if (undefined !== options.collapsed) {
                _renderPanel(options.collapsed)
            } else {
                if (undefined === options.user || undefined === options.section) {
                    throw new Error('Required widget options are not set. Set whether the "collapsed" option, or use '
                        + 'the user configuration service with the options "user" and "section".');
                }

                userConfig.get({
                    data: {
                        userId: options.user,
                        configurationKey: options.section + '_collapsed'
                    },
                    onSuccess: result => {
                        collapsed = result.length === 0 ? false : result.configurationValue === 'true';
                        _renderPanel(collapsed);
                    }
                });
            }
        };

        /**
         * 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!');
                }
            }
        };

        /**
         * Renders the panel.
         *
         * @param {boolean} collapsed If true, the panel will be collapsed.
         * @private
         */
        const _renderPanel = collapsed => {
            const $panelHeading = $('<div/>', {'class': 'panel-heading'});
            const $panelTitle = $('<span/>', {
                'class': 'title',
                'text': options.title
            });

            $iconContainer = $('<span/>', {'class': 'collapser pull-right cursor-pointer'})
            $collapseIcon = $('<i/>', {
                'class': collapsed ? options.collapsed_icon_class : options.expanded_icon_class
            });
            $panelBody = $('<div/>', {'class': 'panel-body'});
            $this.children().detach().appendTo($panelBody);

            $this.addClass('panel panel-default ' + options.container_class);
            $panelHeading.append($panelTitle);
            $iconContainer.append($collapseIcon).appendTo($panelHeading);
            $this.append($panelHeading);

            if (collapsed) {
                $panelBody.css({'display': 'none'});
            }
            $this.append($panelBody);

            // set event handler
            $iconContainer.on('click', _toggle)
        };

        /**
         * Toggle event listener for clicks on panel heading.
         *
         * @private
         */
        const _toggle = () => {
            const isCollapsed = $collapseIcon.hasClass(options.expanded_icon_class);

            $collapseIcon.toggleClass(options.collapsed_icon_class);
            $collapseIcon.toggleClass(options.expanded_icon_class);
            $panelBody.toggle(options.toggle_time);

            userConfig.set({
                data: {
                    userId: options.user,
                    configurationKey: options.section + '_collapsed',
                    configurationValue: isCollapsed
                }
            });
        };

        /**
         * Widget initialization function.
         *
         * @param done
         */
        module.init = done => {
            _checkRequiredOptions();
            _init();
            done();
        }

        return module;
    }
);