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

/**
 * ## Filemanager Widget
 *
 * Creates an input field and a button in order to make it possible to upload files or to select already
 * uploaded files. This widget checks if the responsive filemanager is present, if it is, the responsive
 * filemanager will be used, else a fallback will be used, which is an input field of type 'file'.
 *
 * ### Options
 *
 * **Type | `data-filemanager-type` | String | Optional**
 *
 * Provide the allowed file upload type. Currently there are 3 options which are:
 *    * 'all' - All file types are allowed
 *    * 'videos' - Only video files are allowed
 *    * 'images' - Only images are allowed
 * If you don't provide any type, the filemanager will default to 'all'.
 *
 * **Content Directory | `data-filemanager-content-directory` | String | Required**
 *
 * Provide the directory which should be opened when the filemanager gets opened, e.g. 'media'.
 * You can also provide a path from the root of your shop e.g 'images/slider_images'.
 *
 * **Name | `data-filemanager-name` | String | Required**
 *
 * The name of the input field. It will be set as the HTML name attribute.
 *
 * **Previous File | `data-filemanager-previous-file` | String | Optional**
 *
 * Name of the previous file. The name will be used in order to auto fill the input field.
 *
 * **Page | `data-filemanager-page` | String | Optional**
 *
 * The name of the current page in snake case, for example: new_category or responsive_filemanager.
 * This option will be used in order to load custom configuration files for the responsive file manager like
 * responsive_filemanager.config.php. These custom configuration files will be available or should be created
 * in the 'page' directory of the responsive file manager.
 *
 * **Page Active | `data-filemanager-page-active` | Boolean | Required**
 *
 * This option is required in order to check whether the file manager module is active, and if the configuration
 * option from the file manager is set to active, for the current page. If the module is not active, or active
 * in general but not active for the current page, the fallback will be used, which is a standard input field.
 *
 * ### Example
 *
 * ```html
 * <div data-gx-widget="filemanager"
 *     data-filemanager-name="categories_icon" // Required
 *     data-filemanager-type="images" // Optional
 *     data-filemanager-content-directory="images/categories/icons" // Required
 *     data-filemanager-previous-file="filename.extension" // Optional
 *     data-filemanager-page="responsive_filemanager" // Optional
 *     data-filemanager-page-active="true"> // Required
 * </div>
 * ```
 *
 * @module Admin/Widgets/filemanager
 */
gx.widgets.module(
    'filemanager',

    ['xhr', 'modal'],

    /** @lends module:Widgets/filemanager */

    function (data) {

        'use strict';

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

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

        /**
         * Default Widget Options
         *
         * @type {object}
         */
        const defaults = {};

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

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

        /**
         * Id of the file manager input field.
         *
         * @type {string}
         */
        let fieldId;

        /**
         * Ajax request url fetch the file managers configuration settings.
         *
         * @type {string}
         */
        const fileManagerConfigurationUrl = jse.core.config.get('appUrl')
            + '/admin/admin.php?do=ResponsiveFileManagerModuleCenterModule/GetConfiguration';

        /**
         *  Cache key.
         *
         * @type {string}
         */
        const cacheKey = 'responsiveFileManager';


        // ------------------------------------------------------------------------
        // FUNCTIONS
        // ------------------------------------------------------------------------

        // ------------------------------------------------------------------------
        // FILE MANAGER CONFIGURATIONS
        // ------------------------------------------------------------------------
        /**
         * Returns the allowed file type as an integer, which is mapped
         * for the external Responsive Filemanager plugin. It will be used
         * as a GET parameter in the URL for the file manager.
         *
         * @returns {number} Flag integer value between 0 and 3.
         */
        const _getFMType = () => {
            switch (options.type) {
                case 'images':
                    return 1;
                case 'all':
                    return 2;
                case 'videos':
                    return 3;
                default:
                    return 0;
            }
        };

        /**
         * File managers request url.
         *
         * @returns {string} Request url of file manager.
         */
        const _getFMUrl = () => {
            // Language parameter used for the file manager
            const lang = jse.core.registry.get('languageId') === 2 ? 'de' : 'en_EN';

            // Don't use the popup mode if the file manager will be opened in a modal.
            const popUp = _isCompatibilityModeEnabled() ? 1 : '';

            return jse.core.config.get('appUrl') + '/'
                + 'ResponsiveFilemanager/filemanager/filemanager.php?type=' + _getFMType()
                + _getSubDirectoryQueryString() + '&field_id=' + fieldId
                + '&popup=' + popUp + '&relative_url=1&lang=' + lang
                + _getPageQueryString();
        };

        /**
         * Returns the 'sub_folder' query argument for the file manager request.
         *
         * @returns {string} Query parameter for file manager request to set the root directory.
         */
        const _getSubDirectoryQueryString = () => {
            if (options.contentDirectory !== undefined) {
                return '&sub_folder=' + options.contentDirectory;
            }

            return '';
        };

        /**
         * Returns the 'page' query string for the file manager request.
         *
         * @returns {string} Query parameter for the file manager request to load a custom configuration file.
         */
        const _getPageQueryString = () => {
            if (options.page !== undefined) {
                return '&page=' + options.page;
            }

            return '';
        };

        /**
         * Generates a global unique identifier for each input that is generated by this widget.
         * This ID will be used in order to identify an input fields. With the help of this ID,
         * the widget knows, in which input field the file name of the chose file should be entered.
         *
         * @returns {string} Global unique identifier as string.
         */
        const guidGenerator = () => {
            const s4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);

            return (s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4());
        };

        // ------------------------------------------------------------------------
        // CREATING THE FILE MANAGER
        // ------------------------------------------------------------------------
        /**
         * Factory, which creates either the responsive file manager or the fallback,
         * which is a standard input field of the type 'file'.
         *
         * @type {{responsive: (function()), fallback: (function())}}
         */
        const factory = {
            responsive: () => {
                const $uploadIcon = $('<i/>', {
                    'class': 'fa fa-upload',
                    'aria-hidden': true
                });

                const $removeIcon = $('<i/>', {
                    'class': 'fa fa-remove',
                    'aria-hidden': true
                });

                const $input = $('<input/>', {
                    'type': 'text',
                    'name': options.name,
                    'id': fieldId,
                    'class': 'form-control',
                    'readonly': 'readonly'
                });

                // Auto fill the input field with the previous file name
                if (options.previousFile) {
                    $input.val(options.previousFile);
                }

                const $uploadButton = $('<a/>', {
                    'class': 'btn responsive-file-manager',
                    'type': 'button',
                    'html': $uploadIcon,
                    'on': {
                        'click': () => _openFileManager()
                    }
                });

                const $removeButton = $('<a/>', {
                    'class': 'btn responsive-file-manager',
                    'type': 'button',
                    'html': $removeIcon,
                    'on': {
                        'click': () => $input.val('')
                    }
                });

                const $span = $('<span/>', {
                    'class': 'input-group-btn'
                });

                const $container = $('<div/>', {
                    'class': 'input-group responsive-file-manager'
                });

                $span.append($uploadButton);
                $span.append($removeButton);

                $container.append($input).append($span);
                $this.append($container);
            },

            fallback: () => {
                const $input = $('<input/>', {
                    'name': options.name,
                    'type': 'file'
                });

                $this.append($input);
            }
        };

        /**
         /**
         * Creates the widget after the request the responsive file manager
         * request is being made. After the request, either the 'responsive'
         * widget is created or the fallback, depending on if the file manager
         * is available.
         *
         * @param done Done callback function for module.init.
         */
        const _createWidget = done => {
            jse.libs.xhr.get({url: fileManagerConfigurationUrl})
                .done(response => jse.core.registry.set(cacheKey, response.isInstalled ? 'responsive' : 'fallback'))
                .fail(() => jse.core.registry.set(cacheKey, 'fallback'))
                .always(() => {
                    // Create the file manager or fallback.
                    factory[jse.core.registry.get(cacheKey)]();
                    done();
                });
        };

        /**
         * Creates the widget when the cache key changes from pending.
         * After the cache key changed to either the 'responsive' or 'fallback',
         * the according widget will be created, depending on if the file manager
         * is available.
         *
         * @param done Done callback function for module.init.
         */
        const _createWidgetWhenCacheKeyAvailable = done => {
            const interval = setInterval(() => {
                if (jse.core.registry.get(cacheKey) !== 'pending') {
                    clearInterval(interval);

                    // Create the file manager or fallback.
                    factory[jse.core.registry.get(cacheKey)]();
                    done();
                }
            }, 100);
        };

        // ------------------------------------------------------------------------
        // OPENING THE FILE MANAGER
        // ------------------------------------------------------------------------
        /**
         * Opens the file manager in a new window popup.
         */
        const _openFMPopup = () => {
            const w = 990;
            const h = 600;
            const l = Math.floor((screen.width - w) / 2);
            const t = Math.floor((screen.height - h) / 2);

            window.open(_getFMUrl(), 'ResponsiveFilemanager', "scrollbars=1,width=" + w + ",height=" + h
                + ",top="
                + t + ",left=" + l);
        };

        /**
         * Opens the file manager in a bootstrap modal.
         */
        const _openFMModal = () => {

            // Use the fallback if bootstraps modal function is not available.
            if ($.fn.modal === undefined) {
                return _openFMPopup();
            }

            const iFrame = `<iframe src="${_getFMUrl()}" width="100%" height="550" frameborder="0"
															class="responsive-filemanager"></iframe>`;

            jse.libs.modal.showMessage('Filemanager', iFrame);
            _makeModalLarge();
        };

        /**
         * Makes the modal large by adding the modal-lg css class.
         */
        const _makeModalLarge = () => {
            $('.modal-dialog:last').addClass('modal-lg');
        };

        /**
         * Checks if compatibility mode is active.
         *
         * @returns {boolean} True on compatibility mode, false otherwise.
         */
        const _isCompatibilityModeEnabled = () => {
            return $('body.gx-compatibility').length !== 0;
        };

        /**
         * Opens the file manager in a modal, dialog or window with the priority in
         * the same order. If bootstrap is not available, the file
         * manager will be opened in a new window.
         */
        const _openFileManager = () => {
            if (_isCompatibilityModeEnabled()) {
                return _openFMPopup();
            }

            _openFMModal();
        };


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

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

            // Required option not provided
            if (options.contentDirectory === undefined || options.contentDirectory === '') {
                jse.core.debug.error('content-directory attribute was not provided for the "filemanager" widget.');
                return;
            }

            // Required option not provided
            if (options.name === undefined || options.name === '') {
                jse.core.debug.error('name attribute was not provided for the "filemanager" widget.');
                return;
            }

            // Required option not provided
            if (options.pageActive === undefined) {
                jse.core.debug.error('page-active attribute was not provided for the "filemanager" widget.');
                return;
            }

            // Module is not active at all or not active for the used page.
            if (!options.pageActive) {
                factory.fallback();
                done();
                return;
            }

            // No cache key available yet. Create the widget and set the cache key to 'fallback' or 'responsive'
            // after the responsive has arrived (done by the _createWidget function).
            if (jse.core.registry.get(cacheKey) === undefined) {
                jse.core.registry.set(cacheKey, 'pending');
                _createWidget(done);
                return;
            }

            // Cache key is on 'pending' which means we have to wait until the key changes (done by the _createWidget function).
            // Afterwards we can create the correct widget.
            if (jse.core.registry.get(cacheKey) === 'pending') {
                _createWidgetWhenCacheKeyAvailable(done);
                return;
            }

            // Build the fallback or responsive file manager.
            factory[jse.core.registry.get(cacheKey)]();
        };

        // Return data to module engine.
        return module;
    });