/**
 * Edit window for a single info popup entry.
 *
 * Uses the standard QUIQQER settings-form look (data-table / field-container),
 * a QUISwitch for the active state, a ColorPicker for the media colour and an
 * inline multilingual content editor. The design (display mode) is chosen
 * through small preview cards instead of a plain select. The entry is created
 * on save, so closing a fresh window without saving creates nothing.
 *
 * @module package/quiqqer/info-popup/bin/controls/EntryWindow
 * @author www.pcsg.de
 */
define('package/quiqqer/info-popup/bin/controls/EntryWindow', [

    'qui/QUI',
    'qui/controls/windows/Confirm',
    'qui/controls/buttons/Switch',
    'qui/controls/elements/ColorPicker',
    'controls/lang/InputMultiLang',
    'controls/lang/ContentMultiLang',
    'controls/groups/Select',
    'controls/projects/project/media/Input',
    'package/quiqqer/info-popup/bin/controls/DesignSelect',
    'Ajax',
    'Locale',

    'css!package/quiqqer/info-popup/bin/controls/EntryWindow.css'

], function (QUI, QUIConfirm, QUISwitch, ColorPicker, InputMultiLang, ContentMultiLang,
             GroupSelect, MediaInput, DesignSelect, QUIAjax, QUILocale) {
    "use strict";

    const lg = 'quiqqer/info-popup';

    // display modes that render a media region (image / colour surface)
    const MEDIA_DESIGNS = ['sidebar', 'sidebarRight', 'top'];

    return new Class({

        Extends: QUIConfirm,
        Type: 'package/quiqqer/info-popup/bin/controls/EntryWindow',

        Binds: [
            '$onOpen',
            '$onSubmit',
            '$buildForm',
            '$openContentEditor',
            '$updateContentPreview',
            '$onContentKeyDown',
            '$refreshVisibilityRow',
            '$refreshDesignRows'
        ],

        options: {
            entryId: false,
            projectName: false,
            projectLanguage: false,
            maxWidth: 820,
            maxHeight: 800,
            autoclose: false,
            backgroundClosable: false,
            icon: 'fa fa-bullhorn'
        },

        initialize: function (options) {
            this.parent(options);

            this.$Form = null;
            this.$ActiveSwitch = null;
            this.$TitleInput = null;
            this.$contentValue = '';
            this.$GroupSelect = null;
            this.$MediaInput = null;
            this.$ColorPicker = null;
            this.$MediaAutoHeightSwitch = null;
            this.$CenterContentSwitch = null;
            this.$DesignSelect = null;
            this.$designValue = '';

            this.setAttribute('title', QUILocale.get(
                lg,
                this.getAttribute('entryId') ? 'window.edit.title' : 'window.create.title'
            ));

            this.setAttribute('ok_button', {
                text: QUILocale.get(lg, 'window.save'),
                textimage: 'fa fa-save'
            });

            this.setAttribute('cancel_button', {
                text: QUILocale.get(lg, 'window.cancel'),
                textimage: 'fa fa-remove'
            });

            this.addEvents({
                onOpen: this.$onOpen,
                onSubmit: this.$onSubmit
            });
        },

        /**
         * event : on open - load data (edit) and build the form
         */
        $onOpen: function (Win) {
            const self = this;

            this.Loader.show();

            const Content = Win.getContent();
            Content.set('html', '');

            let load = Promise.resolve({});

            if (this.getAttribute('entryId')) {
                load = new Promise(function (resolve) {
                    QUIAjax.get('package_quiqqer_info-popup_ajax_get', resolve, {
                        'package': 'quiqqer/info-popup',
                        id: self.getAttribute('entryId')
                    });
                });
            }

            load.then(function (entry) {
                self.$buildForm(Content, entry || {});
                self.Loader.hide();
            });
        },

        /**
         * Build the form and initialize the sub controls.
         *
         * @param {HTMLElement} Content
         * @param {Object} entry
         */
        $buildForm: function (Content, entry) {
            const isCreate = !this.getAttribute('entryId');

            const row = (label, fieldHtml) => {
                return '<tr><td><label class="field-container">' +
                    '<span class="field-container-item">' + label + '</span>' +
                    fieldHtml +
                    '</label></td></tr>';
            };

            const desc = (text) => {
                return '<tr><td><span class="quiqqer-info-popup-entry-desc">' + text + '</span></td></tr>';
            };

            this.$Form = new Element('form', {
                'class': 'quiqqer-info-popup-entry',
                events: {
                    submit: function (event) {
                        event.stop();
                    }
                }
            }).inject(Content);

            this.$Form.set('html',
                '<table class="data-table data-table-flexbox"><tbody>' +

                row(QUILocale.get(lg, 'entry.active'),
                    '<span class="field-container-field" data-name="active-wrapper"></span>') +

                row(QUILocale.get(lg, 'entry.priority'),
                    '<input type="number" class="field-container-field" data-name="priority" value="0" />') +
                desc(QUILocale.get(lg, 'entry.priority.description')) +

                row(QUILocale.get(lg, 'entry.title'),
                    '<span class="field-container-field" data-name="title-wrapper"></span>') +

                '<tr><td><div class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.content') + '</span>' +
                '    <div class="field-container-field quiqqer-info-popup-entry-content-preview" ' +
                '         data-name="content-preview" role="button" tabindex="0"></div>' +
                '</div></td></tr>' +

                row(QUILocale.get(lg, 'entry.validFrom'),
                    '<input type="datetime-local" class="field-container-field" data-name="validFrom" />') +

                row(QUILocale.get(lg, 'entry.validTo'),
                    '<input type="datetime-local" class="field-container-field" data-name="validTo" />') +
                desc(QUILocale.get(lg, 'entry.validTo.description')) +

                row(QUILocale.get(lg, 'entry.visibility'),
                    '<select class="field-container-field" data-name="visibility">' +
                    '<option value="always">' + QUILocale.get(lg, 'visibility.always') + '</option>' +
                    '<option value="guest">' + QUILocale.get(lg, 'visibility.guest') + '</option>' +
                    '<option value="authenticated">' + QUILocale.get(lg, 'visibility.authenticated') + '</option>' +
                    '<option value="groups">' + QUILocale.get(lg, 'visibility.groups') + '</option>' +
                    '</select>') +

                '<tr data-name="groups-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.visibilityGroups') + '</span>' +
                '    <span class="field-container-field" data-name="groups-wrapper"></span>' +
                '</label></td></tr>' +

                '<tr><td><div class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.displayMode') + '</span>' +
                '    <div class="field-container-field" data-name="design-wrapper"></div>' +
                '</div></td></tr>' +
                desc(QUILocale.get(lg, 'entry.displayMode.description')) +

                row(QUILocale.get(lg, 'entry.verticalAlign'),
                    '<select class="field-container-field" data-name="verticalAlign">' +
                    '<option value="top">' + QUILocale.get(lg, 'valign.top') + '</option>' +
                    '<option value="center">' + QUILocale.get(lg, 'valign.center') + '</option>' +
                    '<option value="bottom">' + QUILocale.get(lg, 'valign.bottom') + '</option>' +
                    '</select>') +

                row(QUILocale.get(lg, 'entry.centerContent'),
                    '<span class="field-container-field" data-name="centerContent-wrapper"></span>') +
                desc(QUILocale.get(lg, 'entry.centerContent.description')) +

                '<tr data-name="mediaImage-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.mediaImage') + '</span>' +
                '    <span class="field-container-field" data-name="mediaImage-wrapper"></span>' +
                '</label></td></tr>' +

                '<tr data-name="mediaAutoHeight-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.mediaAutoHeight') + '</span>' +
                '    <span class="field-container-field" data-name="mediaAutoHeight-wrapper"></span>' +
                '</label></td></tr>' +
                '<tr data-name="mediaAutoHeight-desc"><td><span class="quiqqer-info-popup-entry-desc">' +
                QUILocale.get(lg, 'entry.mediaAutoHeight.description') + '</span></td></tr>' +

                '<tr data-name="mediaColor-row"><td><label class="field-container">' +
                '    <span class="field-container-item">' + QUILocale.get(lg, 'entry.mediaColor') + '</span>' +
                '    <span class="field-container-field" data-name="mediaColor-wrapper"></span>' +
                '</label></td></tr>' +
                '<tr data-name="mediaColor-desc"><td><span class="quiqqer-info-popup-entry-desc">' +
                QUILocale.get(lg, 'entry.mediaColor.description') + '</span></td></tr>' +

                row(QUILocale.get(lg, 'entry.maxWidth'),
                    '<input type="number" min="0" class="field-container-field" data-name="maxWidth" />') +

                row(QUILocale.get(lg, 'entry.maxHeight'),
                    '<input type="number" min="0" class="field-container-field" data-name="maxHeight" />') +
                desc(QUILocale.get(lg, 'entry.size.description')) +

                '</tbody></table>'
            );

            // active switch
            this.$ActiveSwitch = new QUISwitch({
                status: isCreate ? true : parseInt(entry.active) === 1
            }).inject(this.$Form.querySelector('[data-name="active-wrapper"]'));

            // plain fields
            this.$Form.querySelector('[data-name="priority"]').value = parseInt(entry.priority) || 0;
            this.$Form.querySelector('[data-name="validFrom"]').value = this.$toInputDate(entry.validFrom);
            this.$Form.querySelector('[data-name="validTo"]').value = this.$toInputDate(entry.validTo);
            this.$Form.querySelector('[data-name="visibility"]').value = entry.visibility || 'always';
            this.$Form.querySelector('[data-name="verticalAlign"]').value = entry.verticalAlign || 'top';

            this.$CenterContentSwitch = new QUISwitch({
                status: parseInt(entry.centerContent) === 1
            }).inject(this.$Form.querySelector('[data-name="centerContent-wrapper"]'));

            if (entry.maxWidth) {
                this.$Form.querySelector('[data-name="maxWidth"]').value = parseInt(entry.maxWidth);
            }

            if (entry.maxHeight) {
                this.$Form.querySelector('[data-name="maxHeight"]').value = parseInt(entry.maxHeight);
            }

            // multilang title (lightweight, inline)
            this.$TitleInput = new InputMultiLang({
                name: 'title',
                value: entry.title || ''
            }).inject(this.$Form.querySelector('[data-name="title-wrapper"]'));

            // content: rich preview box that opens the multilingual editor in
            // its own window on click (lazy: the editor loads only on demand).
            this.$contentValue = entry.content || '';

            const ContentPreview = this.$Form.querySelector('[data-name="content-preview"]');
            ContentPreview.addEventListener('click', this.$openContentEditor);
            ContentPreview.addEventListener('keydown', this.$onContentKeyDown);
            this.$updateContentPreview();

            // design preview cards (own control, reused in the project settings).
            // An empty value means "use the project default".
            this.$designValue = entry.displayMode || '';
            this.$DesignSelect = new DesignSelect({
                value: this.$designValue,
                allowEmpty: true,
                events: {
                    onChange: (value) => {
                        this.$designValue = value;
                        this.$refreshDesignRows();
                    }
                }
            }).inject(this.$Form.querySelector('[data-name="design-wrapper"]'));

            // groups select
            this.$GroupSelect = new GroupSelect().inject(
                this.$Form.querySelector('[data-name="groups-wrapper"]')
            );

            if (entry.visibilityGroups) {
                String(entry.visibilityGroups).split(',').forEach((groupId) => {
                    groupId = groupId.trim();

                    if (groupId !== '') {
                        this.$GroupSelect.addItem(groupId);
                    }
                });
            }

            // media image
            this.$MediaInput = new MediaInput({
                name: 'mediaImage',
                project: this.getAttribute('projectName')
            }).inject(this.$Form.querySelector('[data-name="mediaImage-wrapper"]'));

            if (entry.mediaImage) {
                this.$MediaInput.setValue(entry.mediaImage);
            }

            this.$MediaAutoHeightSwitch = new QUISwitch({
                status: parseInt(entry.mediaAutoHeight) === 1
            }).inject(this.$Form.querySelector('[data-name="mediaAutoHeight-wrapper"]'));

            // media colour (parsed picker with clear button)
            this.$ColorPicker = new ColorPicker().inject(
                this.$Form.querySelector('[data-name="mediaColor-wrapper"]')
            );

            if (entry.mediaColor) {
                this.$ColorPicker.setValue(entry.mediaColor);
            }

            // toggles
            this.$Form.querySelector('[data-name="visibility"]')
                .addEventListener('change', this.$refreshVisibilityRow);

            this.$refreshVisibilityRow();
            this.$refreshDesignRows();
        },

        /**
         * Open the multilingual content editor in its own window (lazy, so the
         * editor is only loaded when the user actually edits the content).
         */
        $openContentEditor: function () {
            const self = this;
            let ContentInput = null;

            new QUIConfirm({
                title: QUILocale.get(lg, 'window.content.title'),
                icon: 'fa fa-edit',
                maxWidth: 900,
                maxHeight: 700,
                autoclose: false,
                backgroundClosable: false,
                ok_button: {
                    text: QUILocale.get(lg, 'window.save'),
                    textimage: 'fa fa-check'
                },
                cancel_button: {
                    text: QUILocale.get(lg, 'window.cancel'),
                    textimage: 'fa fa-remove'
                },
                events: {
                    onOpen: function (Win) {
                        Win.getContent().set('html', '');

                        ContentInput = new ContentMultiLang({
                            name: 'content',
                            value: self.$contentValue || ''
                        }).inject(Win.getContent());
                    },
                    onSubmit: function (Win) {
                        // flush the currently edited language into the input
                        // before reading (periodical save only runs every 1s)
                        if (ContentInput.$Editor) {
                            ContentInput.$saveContent();
                        }

                        self.$contentValue = ContentInput.getValue();
                        self.$updateContentPreview();
                        Win.close();
                    }
                }
            }).open();
        },

        /**
         * Keyboard support for the content preview (Enter / Space).
         *
         * @param {KeyboardEvent} event
         */
        $onContentKeyDown: function (event) {
            if (event.key === 'Enter' || event.key === ' ') {
                event.preventDefault();
                this.$openContentEditor();
            }
        },

        /**
         * Render the content preview from the stored multilingual value. Shows
         * the formatted content of the current language (fallback: first
         * non-empty language) or a placeholder when empty.
         */
        $updateContentPreview: function () {
            const Preview = this.$Form.querySelector('[data-name="content-preview"]');
            const html = this.$contentPreviewHtml(this.$contentValue);

            if (html) {
                Preview.set('html', html);
                Preview.classList.remove('quiqqer-info-popup-entry-content-preview--empty');
                return;
            }

            Preview.set('text', QUILocale.get(lg, 'entry.content.empty'));
            Preview.classList.add('quiqqer-info-popup-entry-content-preview--empty');
        },

        /**
         * Extract the formatted content HTML for the current language from the
         * multilingual JSON value.
         *
         * @param {String} json
         * @return {String}
         */
        $contentPreviewHtml: function (json) {
            if (!json) {
                return '';
            }

            let data = null;

            try {
                data = JSON.parse(json);
            } catch (e) {
                return String(json);
            }

            if (!data || typeof data !== 'object') {
                return String(json);
            }

            if (data[QUILocale.getCurrent()]) {
                return data[QUILocale.getCurrent()];
            }

            for (const key in data) {
                if (data[key]) {
                    return data[key];
                }
            }

            return '';
        },

        /**
         * Show the groups row only for the "groups" visibility mode.
         */
        $refreshVisibilityRow: function () {
            const isGroups = this.$Form.querySelector('[data-name="visibility"]').value === 'groups';
            this.$Form.querySelector('[data-name="groups-row"]').style.display = isGroups ? '' : 'none';
        },

        /**
         * Show the media rows (image + colour) only for designs with a media
         * region, so image and colour appear only when they actually apply.
         */
        $refreshDesignRows: function () {
            const hasMedia = MEDIA_DESIGNS.includes(this.$designValue);
            const display = hasMedia ? '' : 'none';

            this.$Form.querySelector('[data-name="mediaImage-row"]').style.display = display;
            this.$Form.querySelector('[data-name="mediaColor-row"]').style.display = display;
            this.$Form.querySelector('[data-name="mediaColor-desc"]').style.display = display;

            const autoHeightDisplay = this.$designValue === 'top' ? '' : 'none';
            this.$Form.querySelector('[data-name="mediaAutoHeight-row"]').style.display = autoHeightDisplay;
            this.$Form.querySelector('[data-name="mediaAutoHeight-desc"]').style.display = autoHeightDisplay;
        },

        /**
         * event : on submit - collect the values, create (if new) and save
         */
        $onSubmit: function () {
            const self = this;

            const data = {
                active: this.$ActiveSwitch.getStatus() ? 1 : 0,
                priority: parseInt(this.$Form.querySelector('[data-name="priority"]').value) || 0,
                title: this.$TitleInput.getValue(),
                content: this.$contentValue,
                validFrom: this.$Form.querySelector('[data-name="validFrom"]').value,
                validTo: this.$Form.querySelector('[data-name="validTo"]').value,
                visibility: this.$Form.querySelector('[data-name="visibility"]').value,
                visibilityGroups: this.$GroupSelect.getValue(),
                displayMode: this.$designValue,
                verticalAlign: this.$Form.querySelector('[data-name="verticalAlign"]').value,
                centerContent: this.$CenterContentSwitch.getStatus() ? 1 : 0,
                mediaImage: this.$MediaInput.getValue(),
                mediaColor: this.$ColorPicker.getValue(),
                mediaAutoHeight: this.$MediaAutoHeightSwitch.getStatus() ? 1 : 0,
                maxWidth: this.$Form.querySelector('[data-name="maxWidth"]').value,
                maxHeight: this.$Form.querySelector('[data-name="maxHeight"]').value
            };

            this.Loader.show();

            const save = function (entryId) {
                QUIAjax.post('package_quiqqer_info-popup_ajax_save', function () {
                    self.fireEvent('saved', [self]);
                    self.close();
                }, {
                    'package': 'quiqqer/info-popup',
                    id: entryId,
                    data: JSON.encode(data),
                    onError: function () {
                        self.Loader.hide();
                    }
                });
            };

            if (this.getAttribute('entryId')) {
                save(this.getAttribute('entryId'));
                return;
            }

            // create mode: persist the entry only now, then save the data
            QUIAjax.post('package_quiqqer_info-popup_ajax_create', function (newId) {
                self.setAttribute('entryId', newId);
                save(newId);
            }, {
                'package': 'quiqqer/info-popup',
                project: JSON.encode({
                    name: self.getAttribute('projectName'),
                    lang: self.getAttribute('projectLanguage')
                }),
                onError: function () {
                    self.Loader.hide();
                }
            });
        },

        /**
         * Convert a database datetime ("Y-m-d H:i:s") to the value expected
         * by an <input type="datetime-local">.
         *
         * @param {String} value
         * @return {String}
         */
        $toInputDate: function (value) {
            if (!value) {
                return '';
            }

            return String(value).replace(' ', 'T').substr(0, 16);
        }
    });
});
