/**
 * Attribute selection class for the attribute-settings feature.
 *
 * @author  Leonard Fischer <lfischer@i-doit.com>
 */
window.AttributeSelection = Class.create({
    initialize: function ($categoryList, $categoryLoadingIndicator, $attributeSearchContainer, $attributeLoadingIndicator, $emptyIndicator, $attributeListContainer, options) {
        this.$categoryList = $categoryList;
        this.$categoryLoadingIndicator = $categoryLoadingIndicator;
        this.$attributeSearchContainer = $attributeSearchContainer;
        this.$attributeLoadingIndicator = $attributeLoadingIndicator;
        this.$emptyIndicator = $emptyIndicator;
        this.$attributeListContainer = $attributeListContainer;

        this.options = Object.extend({ loadAttributesUrl: '' }, options || {});

        this.$attributeSearchContainer.down('input').focus();

        this.checkedItems = [];
        this.searchTerm = null;
        this.selectedCategory = null;

        this.setObserver();
    },

    getCheckedItems: function () {
        return this.checkedItems;
    },

    setObserver: function () {
        this.$categoryList.on('click', 'li', (ev) => {
            this.$categoryList.select('.selected').invoke('removeClassName', 'selected');

            const category = ev.findElement('li').addClassName('selected').readAttribute('data-category');

            this.selectedCategory = category.blank() ? null : category;

            this.processFilter()
        });

        this.$attributeListContainer.on('change', 'input', (ev) => {
            const $checkbox = ev.findElement('input');
            const value = $checkbox.readAttribute('value');

            if ($checkbox.checked) {
                this.checkedItems.push(value);
            } else {
                this.checkedItems = this.checkedItems.without(value);
            }
        });

        this.$attributeSearchContainer.on('keydown', (ev) => {
            if (ev.keyCode === Event.KEY_RETURN) {
                ev.preventDefault();
            }

            delay(this.search.bind(this), 200);
        });

        this.$attributeSearchContainer.on('click', 'img', function (ev) {
            if (!ev.findElement('img').hasClassName('mouse-pointer')) {
                return;
            }

            this.$attributeSearchContainer.down('input').setValue('');
            this.search();
        }.bind(this));
    },

    search: function () {
        const searchTerm = this.$attributeSearchContainer.down('input').getValue().toLowerCase().trim();

        if (searchTerm.blank() || searchTerm.length < 3) {
            this.searchTerm = null;
            this.$attributeSearchContainer.down('img')
                .removeClassName('mouse-pointer')
                .writeAttribute('src', window.dir_images + 'axialis/basic/zoom.svg');

            this.processFilter();
            return;
        }

        this.searchTerm = searchTerm;
        this.$attributeSearchContainer.down('img')
            .addClassName('mouse-pointer')
            .writeAttribute('src', window.dir_images + 'axialis/basic/symbol-cancel-outline.svg');

        this.processFilter();
    },

    loadData: function () {
        this.$attributeLoadingIndicator.removeClassName('hide');

        new Ajax.Request(this.options.loadAttributesUrl, {
            method:     'get',
            onComplete: function (xhr) {
                if (!is_json_response(xhr, true)) {
                    return;
                }

                const json = xhr.responseJSON;

                if (!json.success) {
                    idoit.Notify.error(json.message, {sticky: true});
                    return;
                }

                this.data = json.data;
                this.$attributeLoadingIndicator.addClassName('hide');
                this.$attributeListContainer.update();

                this.renderCategories();
                this.renderAttributes();
                this.processFilter();
            }.bind(this)
        });
    },

    renderCategories: function () {
        this.$categoryLoadingIndicator.removeClassName('hide');

        this.$categoryList.update();

        this.$categoryList.insert(new Element('li', {
            className:       'selected',
            'data-category': ''
        })
            .update(new Element('div')
                .update(new Element('span').update(idoit.Translate.get('LC__ATTRIBUTE_SETTINGS__ALL_ATTRIBUTES')))
                .insert(new Element('div', {className: 'counter'}).update(0))
            ));

        for (const i in this.data) {
            if (!this.data.hasOwnProperty(i)) {
                continue;
            }

            this.$categoryList.insert(new Element('li', {'data-category': this.data[i].constant})
                .update(new Element('div')
                    .update(new Element('span').update(this.data[i].title))
                    .insert(new Element('div', {className: 'counter'}).update(0))
                ));
        }

        this.$categoryLoadingIndicator.addClassName('hide');
    },

    renderAttributes: function () {
        this.$attributeListContainer.update();

        for (const i in this.data) {
            if (!this.data.hasOwnProperty(i)) {
                continue;
            }

            const $list = new Element('ul', {
                className:       'list',
                'data-category': this.data[i].constant
            });

            for (const j in this.data[i].properties) {
                if (!this.data[i].properties.hasOwnProperty(j)) {
                    continue;
                }

                if (this.searchTerm !== null && !this.data[i].properties[j].title.toLowerCase().includes(this.searchTerm)) {
                    continue;
                }

                const $actionField = this.data[i].properties[j].configured
                    ? new Element('span', { className: 'text-neutral-600' }).update(idoit.Translate.get('LC__ATTRIBUTE_SETTINGS__ADDED'))
                    : new Element('input', {
                        type:     'checkbox',
                        value:    this.data[i].properties[j].propertyReference,
                        checked:  this.checkedItems.include(this.data[i].properties[j].propertyReference),
                        disabled: this.data[i].properties[j].isSystemRelevant
                    });

                const $attributeNotificationIcon = this.data[i].properties[j].isSystemRelevant
                    ? new Element('img', { src: window.dir_images + 'axialis/basic/button-info.svg', className: 'ml20' })
                    : ''

                const $attributeNotification = this.data[i].properties[j].isSystemRelevant
                    ? new Element('span', { className: 'text-blue ml5' }).update(idoit.Translate.get('LC__ATTRIBUTE_SETTINGS__SYSTEM_ATTRIBUTE'))
                    : '';

                $list.insert(new Element('li', {'data-name': this.data[i].properties[j].title.toLowerCase()})
                    .update(new Element('label')
                        .update($actionField)
                        .insert(new Element('span', {className: 'ml10'}).update(this.data[i].properties[j].title))
                        .insert($attributeNotificationIcon)
                        .insert($attributeNotification)));
            }

            this.$attributeListContainer
                .insert(new Element('h2').update(this.data[i].title))
                .insert($list);
        }
    },

    processFilter: function () {
        this.$categoryLoadingIndicator.removeClassName('hide');
        this.$attributeLoadingIndicator.removeClassName('hide');

        this.filterCategoryList();
        this.filterAttributeList();

        this.$categoryLoadingIndicator.addClassName('hide');
        this.$attributeLoadingIndicator.addClassName('hide');
    },

    filterCategoryList: function () {
        this.$categoryList.select('li').invoke('removeClassName', 'hide');

        let globalCounter = 0;

        for (const i in this.data) {
            if (!this.data.hasOwnProperty(i)) {
                continue;
            }

            const visibleAttributes = this.data[i].properties
                .filter((property) => this.searchTerm === null
                    ? true
                    : this.data[i].title.toLowerCase().includes(this.searchTerm) // Check for category name
                        ? true
                        : property.title.toLowerCase().includes(this.searchTerm)) // Check for attribute name
                .length;

            if (visibleAttributes === 0) {
                this.$categoryList.down('li[data-category="' + this.data[i].constant + '"]').addClassName('hide');
            } else {
                this.$categoryList.down('li[data-category="' + this.data[i].constant + '"] .counter').update(visibleAttributes);
                globalCounter += visibleAttributes;
            }
        }

        const $allCategoriesEntry = this.$categoryList.down('li[data-category=""]');

        if (this.$categoryList.down('.selected.hide')) {
            $allCategoriesEntry.simulate('click');
        }

        $allCategoriesEntry.down('.counter').update(globalCounter);
    },

    filterAttributeList: function () {
        this.$emptyIndicator.addClassName('hide');
        this.$attributeListContainer.select('h2,ul,li').invoke('removeClassName', 'hide');

        if (this.selectedCategory !== null) {
            this.$attributeListContainer.select('h2,ul,li').invoke('addClassName', 'hide');

            const $categoryAttributes = this.$attributeListContainer.down('ul[data-category="' + this.selectedCategory + '"]').removeClassName('hide');
            $categoryAttributes.previous('h2').removeClassName('hide');
            $categoryAttributes.select('li').invoke('removeClassName', 'hide');
        }

        if (this.searchTerm !== null) {
            this.$attributeListContainer.select('h2').forEach(($headline) => {
                const $list = $headline.next('ul');

                if ($headline.innerText.toLowerCase().includes(this.searchTerm)) {
                    return
                }

                $list.select('li:not([data-name*="' + this.searchTerm + '"])').invoke('addClassName', 'hide');

                if ($list.select('li:not(.hide)').length === 0) {
                    $list.previous('h2').addClassName('hide');
                    $list.addClassName('hide');
                }
            });
        }

        if (!this.$attributeListContainer.down('h2:not(.hide),ul:not(.hide)')) {
            this.$emptyIndicator.removeClassName('hide');
        }
    }
});
