/**
 * Copyright © 2018 Wyomind. All rights reserved.
 * See LICENSE.txt for license details.
 */

requireDep = ['jquery','underscore','mage/template','jquery-ui-modules/widget','jquery-ui-modules/core','jquery-ui-modules/slider','jquery-ui-modules/widget'];
if (!compareVersions(MAGE_VERSION,"2.3.4")) {
    requireDep = ['jquery','underscore','mage/template','jquery/ui'];
}

define(requireDep, function ($, _, mageTemplate) {
    'use strict';
    return {

        /**
         * Elasticsearch requesters cache (contains the results of the requests)
         */
        cache: [],
        /**
         * Did we reach the end of the infinite scroll?
         */
        infiniteScrollNoMoreProduct: false,
        /**
         * Is a request being processed?
         */
        isRequestProcessing: false,
        /**
         * Are template hints enabled?
         */
        templateHintsEnabled: false,
        /**
         * Last request result
         */
        lastRequestData: "",
        /**
         * Global parameters
         */
        config: {
            elasticsearchUrl: "",
            storeCode: "",
            filterableAttributes: {},
            infiniteScroll: {
                enabled: false,
                automatic: true,
                offset: 600
            },
            theme: {},
            displayInputBoxesForPriceFilter: false,
            ajaxCart: {
                enabled: false
            },
            addToCompare: {
                enabled: false
            },
            highlightEnabled: true,
            layerHideOneValue: true,
            layerUpdateMethod: 1, // 1: disabled, 0: hidden, -1: no update
            layerUpdateSorting: 1, // 1: native, 2: alpha, 3: count
            labels: {},
            customerGroupId: 0,
            pageTitle: "",
            autoRefresh: true,
            eaConfig: {},
            updateSearchTerm: 0,
            updateSearchTermUrl: ''
        },
        /**
         * Search options
         */
        search: {
            categoryId: -1,
            categoryUrl: "/",
            searchTerm: ""
        },
        /**
         * Paging options
         */
        paging: {
            from: "0",
            size: "0"
        },
        /**
         * Sorting options
         */
        sorter: {
            order: 'position',
            direction: 'asc'
        },
        /**
         * Price sliders limit
         */
        prices: {
            min: 0,
            max: 0
        },

        /**
         * Current filters applied
         */
        filters: {},
        filtersLabels: {},
        allowUrls: {},
        /**
         * Configurable products data cached
         */
        configurableIndex: {},
        configurableImages: {},


        /**
         * Underscore.js templates selectors
         */
        templateSelectors: {
            productItems: "#eln-product-items-template",
            productItem: "#eln-product-item-template",
            productAmount: "#eln-product-amount-template",
            productCount: "#eln-product-count-template",
            productPaging: "#eln-product-paging-template",
            pricesFilter: "#eln-product-prices-filter-template",
            textSwatchFilter: "#eln-product-text-swatch-filter-template",
            visualSwatchFilter: "#eln-product-visual-swatch-filter-template",
            breadcrumb: "#eln-product-breadcrumb-filter-template",
            attributeFilter: "#eln-product-attribute-filter-template",
            ratingsFilter: "#eln-product-ratings-filter-template",
            categoryFilter: "#eln-product-category-filter-template",
            categoryItemFilter: "#eln-product-category-filter-item-template"
        },
        /**
         * Underscore.js containers target
         */
        contentSelectors: {
            productItems: "#eln-product-products ol.product-items",
            productItem: "#eln-product-products ol.product-items li.product-item",
            productAmount: "#product-amount",
            productCount: ".product-count",
            productPaging: "#product-paging-bottom",
            product: "#eln-product-products",
            filters: "[data-role=eln-filters-content]",
            breadcrumb: "[data-role=eln-breadcrumb-content]",
            attributeFilter: "[data-role=eln-product-attribute-filter-content]",
            ratingsFilter: "[data-role=eln-product-ratings-filter-content]",
            categoryFilter: "[data-role=eln-product-category-filter-content]",
            categoryItemFilter: "[data-role=eln-product-category-filter-item-filter-content]",
            textSwatchFilter: "[data-role=eln-product-text-swatch-filter-content]",
            visualSwatchFilter: "[data-role=eln-product-visual-swatch-filter-content]",
            pricesFilter: "[data-role=eln-product-prices-filter-content]",
        },
        /**
         * Containers phtml references (only for template hints)
         */
        contentTemplateFiles: {
            product: "view/frontend/templates/listing/products.phtml",
            productItems: "view/frontend/templates/listing/products/grid.phtml",
            productItem: "view/frontend/templates/listing/products/grid.phtml",
            productAmount: "view/frontend/templates/listing/products/amount.phtml",
            productPaging: "view/frontend/templates/listing/products/paging.phtml",
            pricesFilter: "view/frontend/templates/layer/renderer/price.phtml",
            textSwatchFilter: "view/frontend/templates/layer/renderer/textSwatch.phtml",
            visualSwatchFilter: "view/frontend/templates/layer/renderer/visualSwatch.phtml",
            breadcrumb: "view/frontend/templates/layer/breadcrumb.phtml",
            attributeFilter: "view/frontend/templates/layer/renderer/attribute.phtml",
            ratingsFilter: "view/frontend/templates/layer/renderer/rating.phtml",
            categoryFilter: "view/frontend/templates/layer/renderer/categories.phtml",
            categoryItemFilter: "view/frontend/templates/layer/renderer/categories.phtml",
            filters: "view/frontend/templates/layer/filters.phtml",
        },


        /**
         * Init observers for the debug popup
         */
        initDebugObservers: function () {

            // enable template hints
            $(document).on('click', '#eln-debug-enable-template-hints', function () {
                this.toggleTemplateHints(true);
            }.bind(this));

            // disable template hints
            $(document).on('click', '#eln-debug-disable-template-hints', function () {
                this.toggleTemplateHints(false);
            }.bind(this));

            // display the last request result
            $(document).on('click', '#eln-debug-show-last-request-data', function () {

                requireDep = ['jquery', 'jquery-ui-modules/dialog', "elasticsearchcore_jsonview"];
                if (!compareVersions(MAGE_VERSION,"2.3.4")) {
                    requireDep = ['jquery', 'jquery/ui', "elasticsearchcore_jsonview"];
                }
                require(requireDep, function ($) {
                    $("#eln-debug-show-last-request-data-modal").modal({
                        "type": "slide",
                        "title": "Last Request Data",
                        "modalClass": "mage-new-category-dialog form-inline",
                        buttons: []
                    });
                    $("#eln-debug-show-last-request-data-modal").html("");
                    $("#eln-debug-show-last-request-data-modal").JSONView(JSON.stringify(this.lastRequestData));
                    $("#eln-debug-show-last-request-data-modal").modal("openModal");
                }.bind(this));
            }.bind(this));

        },


        /**
         * Init observers for the mode switcher (grid/list)
         */
        initModeSwitcherObservers: function () {

            $(document).on('click', '.eln-modes a.el.modes-mode', function (evt) {
                this.setCookie('eln_mode', evt.target.id.replace('mode-', ''));
                if ($(evt.target).parents(".ultimo").length > 0) {
                    document.location.reload();
                    return false;
                }
                if (evt.target.id === "mode-grid") {
                    $('.eln-modes a#mode-list.mode-list.el.active').removeClass('active');
                    $('.eln-modes a#mode-grid.mode-grid.el').addClass('active');
                    $('span#eln-product-products').find("div.list").removeClass('list').removeClass('products-list').addClass('grid').addClass('products-grid');
                } else if (evt.target.id === "mode-list") {
                    $('.eln-modes a#mode-grid.mode-grid.el.active').removeClass('active');
                    $('.eln-modes a#mode-list.mode-list.el').addClass('active');
                    $('span#eln-product-products').find("div.grid").removeClass('grid').removeClass('products-grid').addClass('list').addClass('products-list');
                }
                return false;
            }.bind(this));

        },

        /**
         * Init configurable product observers (options selection)
         */
        initConfigurableProductObservers: function () {
            $(document).on('click', '.eln-product-item-details .swatch-option', function (evt) {
                var elt = $(evt.target);
                // unselect other option values
                elt.parent().find('.swatch-option').removeClass('selected');
                // select this value
                elt.addClass('selected');
                // product id
                var productId = elt.attr('product-id');
                // attribute id
                var attributeId = elt.attr('attribute-id');
                // option id
                var optionId = elt.attr('option-id');
                $('#cart-super-attribute-' + productId + '-' + attributeId).val(optionId);
                // all option selected
                var selected = $(elt.parents(".eln-product-item-details")[0]).find(".swatch-option.selected");
                var selection = {};
                selected.each(function () {
                    selection[$(this).attr('attribute-id')] = $(this).attr('option-id');
                });
                // search the simple product id
                var simpleProductId = -1;
                _.each(this.configurableIndex[productId], function (data, key) {
                    if (_.isEqual(data, selection)) {
                        simpleProductId = key;
                    }
                }.bind(this));
                // simple product id found
                if (simpleProductId !== -1
                    && typeof this.configurableImages[productId] !== "undefined"
                    && typeof this.configurableImages[productId][simpleProductId] !== "undefined"
                    && typeof this.configurableImages[productId][simpleProductId]['img'] !== "undefined") {
                    $('#product-image-' + productId).attr('src', this.configurableImages[productId][simpleProductId]['img']);
                    // display the image matching the simple product (if it exists)

                }

            }.bind(this));
        },

        /**
         * Init paging observers (page change, limitation change)
         */
        initPagingObservers: function () {

            // pages
            $(document).on('click', 'div.eln-product-paging a.page', function (evt) {
                var fromSize = 0;
                if (evt.target.tagName != "SPAN") {
                    fromSize = $(evt.target).find('span').attr('id').replace("page_", "").split("_");
                } else {
                    fromSize = $(evt.target).attr('id').replace("page_", "").split("_");
                }
                this.paging.from = fromSize[0];
                this.paging.size = fromSize[1];
                this.loadProducts();
                return false;
            }.bind(this));

            // - limit
            $(document).on('change', 'div.eln-limiter select#limiter', function (evt) {
                this.paging.from = "0";
                this.paging.size = evt.target.value;
                this.loadProducts();
                this.setCookie('eln_limit', evt.target.value);
                document.body.scrollTop = 0;
                document.documentElement.scrollTop = 0;
            }.bind(this));

        },

        /**
         * Init sorting observers (sorting field, sort order)
         */
        initSortingObservers: function () {

            // - direction
            $(document).on('click', '.eln-toolbar a.action.sorter-action', function (evt) {
                if ($(evt.target).hasClass('sort-desc')) {
                    this.sorter.direction = "asc";
                    this.paging.from = "0";
                    this.loadProducts();
                    this.setCookie('eln_dir', "asc");
                    $(evt.target).removeClass('active');
                    $('.eln-toolbar a.action.sorter-action.sort-asc').addClass('active');
                } else if ($(evt.target).hasClass('sort-asc')) {
                    this.sorter.direction = "desc";
                    this.paging.from = "0";
                    this.loadProducts();
                    this.setCookie('eln_dir', "desc");
                    $(evt.target).removeClass('active');
                    $('.eln-toolbar a.action.sorter-action.sort-desc').addClass('active');
                }
                return false;
            }.bind(this));

            // - order
            $(document).on('change', '.eln-toolbar select#sorter', function (evt) {
                this.paging.from = "0";
                this.sorter.order = evt.target.value;
                this.loadProducts();
                this.setCookie('eln_order', evt.target.value);
                return false;
            }.bind(this));

        },

        /**
         * Init observers on filters
         */
        initFilterObservers: function () {

            // - clear all
            $(document).on('click', '.eln-layer-clear-all', function (evt) {
                //this.filters = {};
                this.filtersLabels = {};
                this.loadProducts();
                return false;
            }.bind(this));

            // - prices range changed
            $(document).on('price-range-changed', function (evt, valMin, valMax) {
                if (parseFloat(valMin) == this.prices.min && parseFloat(valMax) == this.prices.max) {
                    //delete(this.filters.final_price);
                    delete(this.filtersLabels.final_price);
                } else {
                    //this.filters.final_price = {min: valMin, max: valMax};
                    this.filtersLabels.final_price = {min: valMin, max: valMax};
                }
                this.paging.from = "0";
                this.loadProducts();
                return false;
            }.bind(this));

            // prices text input
            $(document).on('change', '.eln-filter-content.price .eln-price.input-text', function (evt) {
                var elt = $(evt.target).parent();
                var selectedMin = elt.find(".input-text.min").val();
                var selectedMax = elt.find(".input-text.max").val();
                if (isNaN(selectedMin) || selectedMin === "" || parseFloat(selectedMin) < this.prices.min) {
                    selectedMin = this.prices.min;
                }
                selectedMin = parseFloat(selectedMin);
                if (selectedMin > this.prices.max) {
                    selectedMin = this.prices.max;
                }
                if (isNaN(selectedMax) || selectedMax === "" || parseFloat(selectedMax) > this.prices.max) {
                    selectedMax = this.prices.max;
                }
                selectedMax = parseFloat(selectedMax);
                if (selectedMax < this.prices.min) {
                    selectedMax = this.prices.min
                }
                if (selectedMax < selectedMin) {
                    selectedMax = selectedMin;
                }
                $(document).trigger("price-range-changed", [selectedMin, selectedMax]);
            }.bind(this));

            // - categories treeview
            $(document).on('click', 'div.eln-filter-item[attribute-code=categories] li.children span.tree', function (evt) {
                $($(this).parents('li')[0]).toggleClass('active');
            });

            // - attributes
            $(document).on('click', '.eln-filter-option', function (evt) {
                // retrieve attribute code + option id
                var target = evt.target;
                if (target.tagName !== "A" && target.tagName !== "SPAN" || !$(target).hasClass(".eln-filter-option")) {
                    target = $(evt.target).parents(".eln-filter-option");
                } else {
                    target = $(target);
                }

                if (target.hasClass('disabled')) {
                    return false;
                }

                var attributeCode = target.attr("attribute-code");
                var optionId = target.attr("option-id");
                var optionLabel = target.attr("option-label");

                // swatch
                if (target.hasClass("swatch-option-link-layered")) {
                    if (target.find(".swatch-option").hasClass("selected")) {
                        this.removeFilter(attributeCode, optionId, optionLabel);
                        target.find(".swatch-option").removeClass("selected");
                    } else {
                        this.addFilter(attributeCode, optionId, optionLabel);
                        target.find(".swatch-option").addClass("selected");
                    }

                }

                // ratings
                else if (target.hasClass("rating")) {
                    if (target.find(".title").hasClass("selected")) {
                        this.removeFilter(attributeCode, optionId, optionLabel);
                        target.find(".title").removeClass("selected");
                    } else {
                        this.addFilter(attributeCode, optionId, optionLabel);
                        target.find(".title").addClass("selected");
                    }
                }

                // click on the checkbox
                else if (evt.target.tagName === "INPUT") {
                    var checked = $(evt.target).attr('checked');

                    if (typeof checked === "undefined") { // unchecked => remove filter
                        // categories
                        if (attributeCode === "categories_ids") {
                            target.parent().find(".eln-filter-option:not(.disabled) span.title").removeClass('selected');
                            var uid = jQuery(target.parents("div.block.filter")[0]).attr('uid');
                            this.updateCategoriesFilter(uid);
                            // others
                        } else {
                            this.removeFilter(attributeCode, optionId, optionLabel);
                        }
                    } else {
                        // categories
                        if (attributeCode === "categories_ids") {
                            target.parent().find(".eln-filter-option:not(.disabled) span.title").addClass('selected');
                            var uid = jQuery(target.parents("div.block.filter")[0]).attr('uid');
                            this.updateCategoriesFilter(uid);
                            // others
                        } else {
                            this.addFilter(attributeCode, optionId, optionLabel);
                        }
                    }
                } else { // click on the label + count
                    var cbx = target.find('input[type="checkbox"]');
                    var checked = cbx.attr('checked');
                    if (typeof checked === "undefined") { // unchecked => add filter
                        // categories
                        if (attributeCode === "categories_ids") {
                            target.parent().find(".eln-filter-option:not(.disabled) input[type=checkbox]").attr('checked', true);
                            target.parent().find(".eln-filter-option:not(.disabled) span.title").addClass('selected');
                            var uid = jQuery(target.parents("div.block.filter")[0]).attr('uid');
                            this.updateCategoriesFilter(uid);
                            // others
                        } else {
                            target.find("input[type=checkbox]").attr('checked', true);
                            target.find("span.title").addClass('selected');
                            this.addFilter(attributeCode, optionId, optionLabel);
                        }
                    } else {
                        // categories
                        if (attributeCode === "categories_ids") {
                            target.parent().find(".eln-filter-option:not(.disabled) input[type=checkbox]").attr('checked', false);
                            target.parent().find(".eln-filter-option:not(.disabled) span.title").removeClass('selected');
                            var uid = jQuery(target.parents("div.block.filter")[0]).attr('uid');
                            this.updateCategoriesFilter(uid);
                            // others
                        } else {
                            target.find("input[type=checkbox]").attr('checked', false);
                            target.find("span.title").removeClass('selected');
                            this.removeFilter(attributeCode, optionId, optionLabel);
                        }
                    }

                }
                return false;
            }.bind(this));

            // - open/close filter div
            $(document).on('click', 'div.eln-filter-item div.filter-options-title', function () {

                var parent = $(this).parent();
                if (!parent.hasClass('active')) {
                    if ($(this).parents("div.horizontal").length === 1) {
                        $($(this).parents("div.horizontal")[0]).find(".active").each(function () {
                            $(this).removeClass('active');
                        });
                    }
                }
                // if (parent.hasClass('active')) {
                //     parent.find(".eln-filter-content").slideUp();
                // } else {
                //     parent.find(".eln-filter-content").slideDown();
                // }
                parent.toggleClass('active');
            });

            // - show more links
            $(document).on('click', '.eln-filter-content .show-more', function () {
                $(this).parent().removeClass('hide-more');
                return false;
            });
            $(document).on('click', '.eln-filter-content .show-less', function () {
                $(this).parent().addClass('hide-more');
                return false;
            });
        },


        /**
         * Init observers for the breadcrumb
         */
        initBreadcrumbObservers: function () {


            // - remove filters after
            $(document).on('click', 'div.eln-breadcrumb a.remove-after', function (evt) {
                var target = evt.target;
                if (target.tagName !== "A") {
                    target = $(evt.target).parents("a.remove-after");
                } else {
                    target = $(target);
                }

                var attributeCode = target.attr("attribute-code").replace('_ids', '');
                var after = false;
                _.each(this.filtersLabels, function (values, key) {
                    if (after) {
                        //delete(this.filters[key]);
                        delete(this.filtersLabels[key]);
                    }
                    if (key === attributeCode) {
                        after = true;
                    }
                }.bind(this));
                this.paging.from = 0;
                this.loadProducts();
                return false;
            }.bind(this));


            // - remove filters after and others values
            $(document).on('click', 'div.eln-breadcrumb a.remove-after-and-others', function (evt) {

                var target = evt.target;
                if (target.tagName !== "A") {
                    target = $(evt.target).parents("a.remove-after-and-others");
                } else {
                    target = $(target);
                }

                var attributeCode = target.attr("attribute-code").replace('_ids', '');
                var optionId = target.attr("option-id");
                var optionLabel = target.attr("option-label").replace(new RegExp(/-/g), '_').toLowerCase();
                var after = false;
                _.each(this.filtersLabels, function (values, key) {
                    if (after) {
                        //delete(this.filters[key]);
                        delete(this.filtersLabels[key]);
                    }
                    if (key === attributeCode) {
                        after = true;
                    }
                }.bind(this));

                //this.filters[attributeCode] = [optionId];
                this.filtersLabels[attributeCode] = [optionLabel];
                this.paging.from = 0;
                this.loadProducts();
                return false;
            }.bind(this));

            // - remove filter
            $(document).on('click', 'div.eln-breadcrumb a.action.remove', function (evt) {
                var a = $(evt.target);
                var attributeCode = a.attr("attribute-code");
                // if "remove" for all attribute values
                //var optionId = a.attr("option-id");
                //this.removeFilter(attributeCode, optionId);
                // global remove of the filter
                this.removeFilter(attributeCode);
                return false;
            }.bind(this));
        },

        /**
         * Init observers for the infinite scroll
         */
        initInfiniteScrollObservers: function () {
            if (this.config.infiniteScroll.enabled) {
                if ($('#eln-manual-infinite-scroll').length) { // manual
                    $('#eln-manual-infinite-scroll').on('click', function () {
                        if (this.infiniteScrollNoMoreProduct) {
                            $("#eln-infinite-scroll-end").addClass('active');
                        } else {
                            if (!this.isRequestProcessing) {
                                this.loadInfiniteScrollProducts();
                            }
                        }
                    }.bind(this));
                } else { // auto
                    let deviceAgent = navigator.userAgent.toLowerCase();
                    let agentID = deviceAgent.match(/(iphone|ipod|ipad)/);
                    $(window).scroll(function () {
                        if (this.infiniteScrollNoMoreProduct) {
                            $("#eln-infinite-scroll-end").addClass('active');
                        } else {
                            if (!this.isRequestProcessing) {
                                let grid = $(".products.wrapper");//.grid.products-grid
                                if (($(window).scrollTop() + $(window).height()) >= parseInt(grid.offset().top + grid.height()) - parseInt(this.config.infiniteScroll.offset)
                                    || agentID && ($(window).scrollTop() + $(window).height()) + 150 > $(window).height()) {
                                    this.loadInfiniteScrollProducts();
                                }
                            }
                        }
                    }.bind(this));
                }
            }
        },

        initAddToWishlistObservers: function () {
            $(document).on('click', 'a.eln-ajax-add-to-wishlist', function (evt) {
                let elt = $(evt.target);
                elt.parent().submit();
            });
        },

        ajaxCartInProgress: false,
        currentAjaxCartRequestProduct: null,
        /**
         * Initialize the ajax add to cart observers
         */
        initAjaxAddToCartObservers: function () {


            $(document).on('ajaxComplete', function (event, xhr, settings) {
                if (settings.url.includes("customer/section/load")) {
                    if (typeof xhr.responseJSON.messages != "undefined" && this.ajaxCartInProgress != false) {
                        let message = xhr.responseJSON.messages.messages[0];
                        this.currentAjaxCartRequestProduct.find('.loader').removeClass('active');
                        let cartMessage = this.currentAjaxCartRequestProduct.find('.ajax-cart-message');
                        if (typeof message != "undefined") {
                            if (message.type == "success") {
                                cartMessage.html(message.text)
                                    .addClass('message-success')
                                    .addClass('success')
                                    .fadeIn('fast');
                                setTimeout(function () {
                                    cartMessage.fadeOut('slow');
                                }.bind(this), 2000);
                            } else {
                                cartMessage.html(message.text)
                                    .addClass('message-error')
                                    .addClass('error')
                                    .fadeIn('fast');
                                setTimeout(function () {
                                    cartMessage.fadeOut('slow');
                                }, 2000);
                            }
                        } else {
                            cartMessage.html("An error occurs")
                                .addClass('message-error')
                                .addClass('error')
                                .fadeIn('fast');
                            setTimeout(function () {
                                cartMessage.fadeOut('slow');
                            }, 2000);
                        }
                        this.ajaxCartInProgress = false;
                    }
                }
            }.bind(this));

            // Add To Cart button
            $(document).on('click', 'button.eln-ajax-add-to-cart', function (evt) {

                let elt = $(evt.target);
                let form = $($(elt).parents("div[data-role=tocart-form]")[0]);
                let data = {};
                let error = false;

                // check if the product is a configurable product and that all options are selected
                form.find("input").each(function () {
                    if (!error && $(this).hasClass("swatch-input") && $(this).val() === "") {
                        error = true;
                    }
                    data[$(this).attr('name')] = $(this).val();
                });

                // an option is missing => display an error message
                if (error) {
                    let errorMsg = form.parents('li').find('.eln-message-options-error');
                    $(errorMsg).slideDown();
                    setTimeout(function () {
                        $(errorMsg).slideUp();
                    }, 3000);
                    return;
                }

                let action = form.attr('action'); // ajax call url

                // enable the loader div in front of the product block
                form.parents('li').find('.loader').addClass('active');


                let interval = setInterval(function () {
                    if (!this.ajaxCartInProgress) {
                        clearInterval(interval);
                        // execute the cart request when no other cart request is in progress
                        this.ajaxCartInProgress = true;
                        this.currentAjaxCartRequestProduct = form.parents('li');
                        $.ajax({
                            url: action,
                            method: "post",
                            global: true, // reload the mini cart after the call
                            data: data,
                            dataType: 'json',
                            success: function (data) {
                                if (typeof data.backUrl !== "undefined") {
                                    document.location.href = data.backUrl;
                                } else if (!_.isArray(data)) {
                                    document.location.href = document.location.href;
                                } else {
                                }
                            }
                        });
                    }
                }.bind(this), 500);


            }.bind(this));
        },

        sidebarTop: 0,
        lastScrollTop: 0,

        /**
         * Initializes the scroll observer on the page
         * Moves the sidebar-main/additional according to the scroll
         */
        initWindowScroll: function () {
            $(window).scroll(function (elt) {
                this.calculateNewPosSidebars();
            }.bind(this));

        },

        calculateNewPosSidebars: function (down) {


            if ($(window).width() < 768) {
                return;
            }

            if (typeof down == "undefined") {
                down = false;
            }

            var layout = $("body").hasClass('page-layout-3columns') ? 3 : 2;

            let sidebarHeightMain = 0;
            if ($('.sidebar.sidebar-main').length == 1) {
                sidebarHeightMain = $('.sidebar.sidebar-main').height();
            }
            let sidebarHeightAdd = 0;
            if ($('.sidebar.sidebar-additional').length == 1) {
                sidebarHeightAdd = $('.sidebar.sidebar-additional').height();
            }

            let sidebarTopAdd = 0;
            if ($('.sidebar.sidebar-additional').length == 1) {
                sidebarTopAdd = $('.sidebar.sidebar-additional').offset().top;
            }

            let sidebarTopMain = sidebarTopAdd;
            if ($('.sidebar.sidebar-main').length == 1) {
                sidebarTopMain = $('.sidebar.sidebar-main').offset().top;
            }


            let sidebarTop = $('div.columns').offset().top;

            let limitBottomMain = sidebarTop + sidebarHeightMain;
            let limitBottomAdd = sidebarTop + sidebarHeightAdd;
            let scrollTop = $(window).scrollTop() + $(window).height();
            let footerTop = 0;
            if ($('.footer-container.page-footer').length == 1) {
                footerTop = $('.footer-container.page-footer').offset().top;
            } else {
                footerTop = $('footer.page-footer').offset().top;
            }

            let stickyOffset = 0;
            if ($('.nav-container.sticky-container').length == 1) { // ultimo sticky menu
                stickyOffset = $('.nav-container.sticky-container').height();
            }


            if (layout == 2) {
                sidebarHeightMain += sidebarHeightAdd;
                limitBottomMain += sidebarHeightAdd;
            }


            let main = $('.sidebar.sidebar-main');
            if ($('.sidebar.sidebar-main').length == 0) {
                main = $('.sidebar.sidebar-additional');
            }

            if (down || this.lastScrollTop - $(window).scrollTop() < 0) { // down


                if (down) {
                    $('.sidebar.sidebar-main').addClass('moving');
                    $('.sidebar.sidebar-additional').addClass('moving');
                    //$(window).scrollTop($(window).scrollTop()+1);
                }

                // sidebar main
                let translateY = '';
                if ((sidebarTopMain + sidebarHeightMain) < scrollTop && footerTop > (sidebarTopMain + sidebarHeightMain)) {
                    if (sidebarHeightMain < $(window).height()) {
                        if (sidebarTopMain < sidebarTop) {
                            main.css('transform', 'none');
                        } else if (sidebarTopMain < $(window).scrollTop()) {
                            main.css('transform', 'translateY(' + ($(window).scrollTop() - sidebarTop + stickyOffset) + 'px)');
                            translateY = 'translateY(' + ($(window).scrollTop() - sidebarTop + stickyOffset) + 'px)';
                        }
                    } else {
                        main.css('transform', 'translateY(' + (scrollTop - limitBottomMain) + 'px)');
                        translateY = 'translateY(' + (scrollTop - limitBottomMain) + 'px)';
                    }
                } else if ((sidebarTopMain + sidebarHeightMain) < scrollTop && footerTop <= (sidebarTopMain + sidebarHeightMain)) {
                    main.css('transform', 'translateY(' + (footerTop - limitBottomMain + 1) + 'px)');
                    translateY = 'translateY(' + (footerTop - limitBottomMain + 1) + 'px)';
                }

                // sidebar additional
                if (main.length != 0) {
                    if (layout == 3) {
                        if ((sidebarTopAdd + sidebarHeightAdd) < scrollTop && footerTop > (sidebarTopAdd + sidebarHeightAdd)) {
                            if (sidebarHeightAdd < $(window).height()) {
                                if (sidebarTopAdd < sidebarTop) {
                                    $('.sidebar.sidebar-additional').css('transform', 'none');
                                } else if (sidebarTopAdd < $(window).scrollTop()) {
                                    $('.sidebar.sidebar-additional').css('transform', 'translateY(' + ($(window).scrollTop() - sidebarTop + stickyOffset) + 'px)');
                                }
                            } else {
                                $('.sidebar.sidebar-additional').css('transform', 'translateY(' + (scrollTop - limitBottomAdd) + 'px)');
                            }
                        } else if ((sidebarTopAdd + sidebarHeightAdd) < scrollTop && footerTop <= (sidebarTopAdd + sidebarHeightAdd)) {
                            $('.sidebar.sidebar-additional').css('transform', 'translateY(' + (footerTop - limitBottomAdd + 1) + 'px)');
                        }
                    } else if (layout == 2) {
                        $('.sidebar.sidebar-additional').css('transform', translateY);
                    }
                }
                if (down) {
                    setTimeout(function () {
                        $('.sidebar.sidebar-main').removeClass('moving');
                        $('.sidebar.sidebar-additional').removeClass('moving');
                    }, 600);
                }

            } else {// up

                if ($(window).scrollTop() < sidebarTop) {
                    main.css('transform', 'none');
                    $('.sidebar.sidebar-additional').css('transform', 'none');
                } else {
                    // sidebar main
                    if (sidebarTopMain > $(window).scrollTop() && sidebarTopMain > sidebarTop && parseInt($(window).scrollTop() - sidebarTop) > 0) {
                        main.css('transform', 'translateY(' + ($(window).scrollTop() - sidebarTop + stickyOffset) + 'px)');
                    } else if (sidebarTopMain <= sidebarTop) {
                        main.css('transform', 'none');
                    }
                    // sidebar additional
                    if (main.length != 0) {
                        if (layout == 3) {
                            if (sidebarTopAdd > $(window).scrollTop() && sidebarTopAdd > sidebarTop && parseInt($(window).scrollTop() - sidebarTop) > 0) {
                                $('.sidebar.sidebar-additional').css('transform', 'translateY(' + ($(window).scrollTop() - sidebarTop + stickyOffset) + 'px)');
                            } else if (sidebarTopAdd <= sidebarTop) {
                                $('.sidebar.sidebar-additional').css('transform', 'none');
                            }
                        } else if (layout == 2) {
                            $('.sidebar.sidebar-additional').css('transform', main.css('transform'));
                        }
                    }
                }


            }
            this.lastScrollTop = $(window).scrollTop();
        },

        initLayerFilterObservers: function () {
            $(document).on('keyup', '.eln-layer-filter', function () {
                if ($(this).val() == "") {
                    $(this).parent().find('a div').parent().removeClass('hidden');
                    $(this).parent().find('span div').parent().removeClass('hidden');
                    $(this).parent().parent().addClass('hide-more');
                    $(this).parent().parent().find('.show-more, .show-less').css({'display': ''});
                } else {
                    $(this).parent().parent().removeClass('hide-more');
                    $(this).parent().parent().find('.show-more, .show-less').css({'display': 'none'});
                    $(this).parent().find('a div:not([data-filter*=' + $(this).val().toLowerCase() + '])').parent().addClass('hidden');
                    $(this).parent().find('span div:not([data-filter*=' + $(this).val().toLowerCase() + '])').parent().addClass('hidden');
                    $(this).parent().find('a div[data-filter*=' + $(this).val().toLowerCase() + ']').parent().removeClass('hidden');
                    $(this).parent().find('span div[data-filter*=' + $(this).val().toLowerCase() + ']').parent().removeClass('hidden');
                }
            });
        },

        /**
         * Init all observers
         */
        initObservers: function () {
            this.initDebugObservers();
            this.initModeSwitcherObservers();
            this.initConfigurableProductObservers();
            this.initPagingObservers();
            this.initSortingObservers();
            this.initFilterObservers();
            this.initBreadcrumbObservers();
            this.initInfiniteScrollObservers();
            if (this.config.ajaxCart.enabled) {
                this.initAjaxAddToCartObservers();
            }
            this.initAddToWishlistObservers();
            if (this.config.stickyLayer == 1) {
                this.initWindowScroll();
            }
            this.initLayerFilterObservers();
            this.initMobileObservers();


            $(document).on('wyo-search-term-updated', function (evt, searchTerm) {
                if ($('body').hasClass('catalogsearch-result-index') && this.config.autoRefresh) {

                    document.location.hash = "";
                    this.search.term = searchTerm;
                    this.paging.from = 0;
                    this.search.categoryId = -1;
                    this.filtersLabels = {};
                    this.loadProducts(true, true, true);
                    if (searchTerm === "") {
                        $('span[data-ui-id=page-title-wrapper]').html("");
                    } else {
                        $('span[data-ui-id=page-title-wrapper]').html(this.config.pageTitle.replace('%1', searchTerm));
                    }
                }
            }.bind(this));

            $(document).on('input propertychange', "#search", function () {
                $(document).trigger('wyo-search-term-updated', $("#search").val());
            });

        },

        initMobileObservers: function () {
            $(document).on('click', '.uid-mobile-toolbar button.close', function (evt) {
                $('body').removeClass('mobile-filter');
            });
            $(document).on('click', '.mobile-filter-open', function (evt) {
                $('body').addClass('mobile-filter');
            });
        },

        initPriceSlider: function (valMin, valMax) {
            $(".eln-filter-content .eln-price-slider").slider({
                range: true,
                min: this.prices.min,
                max: this.prices.max,
                values: [valMin, valMax],
                stop: function (event, ui) {
                    var selectedMin = parseInt(ui.values[0]);
                    if (isNaN(selectedMin)) {
                        selectedMin = 0;
                    }
                    var selectedMax = parseInt(ui.values[1]);
                    $(document).trigger("price-range-changed", [selectedMin, selectedMax, this.min, this.max]);
                }.bind(this),
                slide: function (event, ui) {
                    $(".eln-filter-content .price-range .from").html(_.getFormattedPrice(ui.values[0]));
                    $(".eln-filter-content .price-range .to").html(_.getFormattedPrice(ui.values[1]));
                    $(".eln-filter-content .eln-price-slider").slider("option", "values", [ui.values[0], ui.values[1]]);
                }
            });
            $(".eln-filter-content .eln-price-slider .ui-slider-handle").addClass("wyomind-primary-bgcolor");
        },

        initPriceSliders: function () {
            _.each($(".eln-filter-content .eln-price-slider"), function (elt) {
                elt = $(elt);
                elt.slider({
                    range: true,
                    min: parseInt(elt.attr('min')),
                    max: parseInt(elt.attr('max')),
                    values: [parseInt(elt.attr('valmin')), parseInt(elt.attr('valmax'))],
                    stop: function (event, ui) {
                        var selectedMin = parseInt(ui.values[0]);
                        if (isNaN(selectedMin)) {
                            selectedMin = 0;
                        }
                        var selectedMax = parseInt(ui.values[1]);
                        $(document).trigger("price-range-changed", [selectedMin, selectedMax, parseInt(elt.attr('min')), parseInt(elt.attr('max'))]);
                    }.bind(this),
                    slide: function (event, ui) {
                        $(".eln-filter-content .eln-price-slider").parent().find(".from").html(_.getFormattedPrice(ui.values[0]));
                        $(".eln-filter-content .eln-price-slider").parent().find(".to").html(_.getFormattedPrice(ui.values[1]));
                        $(".eln-filter-content .eln-price-slider").slider("option", "values", [ui.values[0], ui.values[1]]);
                    }
                });
                elt.find(".ui-slider-handle").addClass("wyomind-primary-bgcolor");
            });
        },

        /**
         * Update the categories selected in the filters then reload the products
         */
        updateCategoriesFilter: function (uid) {
            //this.filters["categories_ids"] = [];
            this.filtersLabels["categories"] = [];
            var elts = $('div.block.filter[uid=' + uid + '] .eln-filter-item[attribute-code=categories] span.selected');
            _.each(elts, function (elt) {
                //this.filters["categories_ids"].push($(elt).attr('category-id'));
                this.filtersLabels["categories"].push($(elt).attr('category-id'));
            }.bind(this));
            if (this.filtersLabels["categories"].length == 0) {
                //delete(this.filters["categories_ids"]);
                delete(this.filtersLabels["categories"]);
            }
            this.paging.from = "0";
            this.loadProducts();
        },

        /**
         * Add a filter to the current filters list, then reload the products list
         * @param attributeCode
         * @param optionId
         */
        addFilter: function (attributeCode, optionId, optionLabel) {
            attributeCode = attributeCode.replace('_ids', '');
            optionLabel = optionLabel.toLowerCase().replace('-', '_');
            if (typeof this.filtersLabels[attributeCode] === "undefined") {
                //this.filters[attributeCode] = [optionId];
                this.filtersLabels[attributeCode] = [optionLabel];
            } else {
                //this.filters[attributeCode].push(optionId);
                this.filtersLabels[attributeCode].push(optionLabel);
            }
            this.paging.from = "0";
            this.loadProducts();
        },

        /**
         * Remove a filter from the current filters list, then reload the products list
         * @param attributeCode
         * @param optionId
         */
        removeFilter: function (attributeCode, optionId, optionLabel) {
            attributeCode = attributeCode.replace('_ids', '');
            if (typeof optionLabel != "undefined" && attributeCode != "rating") {
                optionLabel = optionLabel.toLowerCase().replace('-', '_');
            }
            if (attributeCode === "rating") {
                $("#rating-filter-" + optionId).removeClass("selected");
            }
            this.paging.from = "0";
            if (attributeCode === "final_price" || typeof optionId == "undefined") {
                //delete(this.filters[attributeCode]);
                delete(this.filtersLabels[attributeCode]);
                this.loadProducts();
            } else {
                this.filtersLabels[attributeCode] = _.without(this.filtersLabels[attributeCode], optionLabel);
                if (this.filtersLabels[attributeCode].length === 0) {
                    delete(this.filtersLabels[attributeCode]);
                }
                this.loadProducts();
            }
        },


        /**
         * Make a request to get products list when the infinite scroll is triggered, according to the current filters, page, order, sorting field, etc...
         */
        loadInfiniteScrollProducts: function () {

            $('#eln-manual-infinite-scroll').addClass('hidden');

            this.isRequestProcessing = true;
            var fullStartTime = Date.now();
            // display loader
            $('#eln-infinite-scroll-loader').toggleClass('active');
            $("#eln-infinite-scroll-end").removeClass('active');
            this.paging.from = parseInt(this.paging.from) + parseInt(this.paging.size);
            var data = {
                "store": this.config.storeCode,
                "categoryId": this.search.categoryId,
                "searchTerm": this.search.term,
                "from": this.paging.from,
                "size": this.paging.size,
                "order": this.sorter.order,
                "direction": this.sorter.direction,
                "filters": this.filtersLabels,
                "onlyProducts": true,
                "highlightEnabled": this.config.highlightEnabled,
                "loadAggregations": false,
                "customerGroupId": this.config.customerGroupId
            };
            var hash = this.hash(JSON.stringify(data));
            var requestStartTime = Date.now();
            if (this.storageGet(hash)) {
                data = this.storageGet(hash);
                this.updateContentInfiniteScroll(data, fullStartTime, requestStartTime, hash);
            } else {
                $.ajax({
                    url: this.config.elasticsearchUrl,
                    method: "POST",
                    global: false,
                    data: data,
                    dataType: "json"
                }).done(function (data) {
                    this.updateContentInfiniteScroll(data, fullStartTime, requestStartTime);
                    this.storageSet(hash, data);
                }.bind(this)).fail(function (jqXHR, textStatus) {
                    console.log("Request failed: " + textStatus);
                }.bind(this));
            }
        },

        /**
         * Update the products list contains in the results of the request for the infinite scroll
         * No need to refresh the filters
         * @param data
         * @param fullStartTime
         * @param requestStartTime
         * @param cacheHash
         */
        updateContentInfiniteScroll: function (data, fullStartTime, requestStartTime, cacheHash) {

            var requestTime = Date.now() - requestStartTime;
            var renderingStartTime = Date.now();
            if (data['products'].length < this.paging.size) {
                this.infiniteScrollNoMoreProduct = true;
                $("#eln-infinite-scroll-end").addClass('active');
                $('#eln-manual-infinite-scroll').addClass('hidden');
            } else {
                $('#eln-manual-infinite-scroll').removeClass('hidden');
            }

            let allProductIds = [];

            _.each(data['products'], function (product) {
                allProductIds.push(product.id);
                if (typeof product.configurable_index !== "undefined") {
                    this.configurableIndex[product.id] = $.parseJSON(product.configurable_index);
                    this.configurableImages[product.id] = $.parseJSON(product.configurable_images);
                }

                var htmlItem = mageTemplate(this.templateSelectors.productItem, {
                    "product": product,
                    "ajaxCartEnabled": this.config.ajaxCart.enabled,
                    "addToCompareEnabled": this.config.addToCompare.enabled,
                    "customerGroupId": this.config.customerGroupId
                });
                $(this.contentSelectors.productItems).append(htmlItem);
                $(this.contentSelectors.productItems).trigger('contentUpdated');

            }.bind(this));

            if ($("#eln-debug-template").length >= 1) {
                var fullEndTime = Date.now();
                var debug = mageTemplate("#eln-debug-template", {
                    "phpTime": typeof cacheHash !== "undefined" ? 0 : data.time,
                    "requestTime": requestTime,
                    "renderingTime": (fullEndTime - renderingStartTime),
                    "totalTime": (fullEndTime - fullStartTime),
                    "fromCache": typeof cacheHash !== "undefined",
                    "cacheHash": cacheHash,
                    "infiniteScroll": true,
                    "templateHintsEnabled": this.templateHintsEnabled
                });
                $('#eln-debug').html(debug);
                this.toggleTemplateHints(this.templateHintsEnabled);
                this.lastRequestData = data;
            }
            // hide loader
            $('#eln-infinite-scroll-loader').toggleClass('active');
            this.isRequestProcessing = false;

            // ultimo - resize product items block
            if (this.config.theme.model.includes("Infortis") && this.config.theme.config.equal_height === "1") {
                this.ULTIMO.setGridItemsEqualHeight();
            }


            // get estimated delivery dates
            this.updateEstimatedDeliveryDate(allProductIds);

            this.updateFormKey();
            if (this.config.stickyLayer == 1 && $('#eln-manual-infinite-scroll').length > 0) { // only for manual infinite scroll
                this.calculateNewPosSidebars(true);
            }
        },

        updateSearchRequest: function () {


            let locationHash = this.encodeFilters(this.filtersLabels);
            let page = (this.paging.from / this.paging.size) + 1;
            if (page > 1) {
                page = "/page/" + page;
            } else {
                page = "";
            }

            let params = "";
            if (this.search.term != "") {
                if (this.sorter.order != "score") {
                    params += "order=" + this.sorter.order;
                    params += "&dir=" + this.sorter.direction;
                } else {
                    if (this.sorter.direction != "desc") {
                        params += "dir=" + this.sorter.direction;
                    }
                }
            } else {
                if (this.sorter.order != "position") {
                    params += "order=" + this.sorter.order;
                    params += "&dir=" + this.sorter.direction;
                } else {
                    if (this.sorter.direction != "asc") {
                        params += "dir=" + this.sorter.direction;
                    }
                }
            }
            if (params != "") {
                params = "?" + params;
            }

            if (locationHash == "") {
                if (this.search.term != "") {
                    window.history.replaceState(null, null, "/catalogsearch/result/" + this.search.term + page + params);
                } else {
                    window.history.replaceState(null, null, this.search.categoryUrl.replace(this.config.seoCategoryUrlSuffix, '') + page + this.config.seoCategoryUrlSuffix + params);
                }
            } else if (locationHash != "") {
                if (this.search.term != "") {
                    window.history.pushState("", "", "/catalogsearch/result/" + this.search.term + "/" + locationHash + page + params);
                } else {
                    window.history.replaceState(null, null, this.search.categoryUrl.replace(this.config.seoCategoryUrlSuffix, '') + "/" + locationHash + page + this.config.seoCategoryUrlSuffix + params);
                }
            }
        },

        /**
         * Make a request to get products list according to the current filters, page, order, sorting field, etc...
         */
        loadProducts: function (loadAggregations, firstLoad, fromSearchBox) {


            if (this.xhr !== undefined) {
                this.xhr.abort();
            }

            if (typeof loadAggregations == "undefined") {
                loadAggregations = this.config.layerUpdateMethod >= 0;
            }

            if (typeof fromSearchBox == "undefined") {
                fromSearchBox = false;
            }
            if ($('.eln-main-loader').css('display') != 'block') {
                $('.eln-main-loader').fadeIn('fast');
            }
            var fullStartTime = Date.now();
            // we are not loading products for the infinite scroll
            $("#eln-infinite-scroll-end").removeClass('active');
            $('#eln-manual-infinite-scroll').removeClass('hidden');
            this.infiniteScrollNoMoreProduct = false;
            // current parameters for the request


            var data = {
                "elsln": "true",
                "store": this.config.storeCode,
                "categoryId": this.search.categoryId,
                "searchTerm": this.search.term,
                "from": this.paging.from,
                "size": this.paging.size,
                "order": this.sorter.order,
                "direction": this.sorter.direction,
                "filters": this.filtersLabels,
                "highlightEnabled": this.config.highlightEnabled,
                "loadAggregations": loadAggregations,
                "layerUpdateSorting": this.config.layerUpdateSorting,
                "customerGroupId": this.config.customerGroupId
            };

            if (fromSearchBox) {
                if (!_.isEmpty(this.config.eaConfig)) {
                    if (this.config.eaConfig.category.enable_search) {
                        data.categories = "true";
                        data.categoriesLimit = 5;
                    }
                    if (this.config.eaConfig.cms.enable_search) {
                        data.cms = "true";
                        data.cmsLimit = 5;
                    }
                    if (this.config.eaConfig.didyoumean.enable_search) {
                        data.suggest = "true";
                    }
                    if (this.config.eaConfig.general.enable_highlight) {
                        data.eaHighlightEnabled = "true";
                    }
                }
            }

            this.updateSearchRequest();
            // $([document.documentElement, document.body]).animate({
            //     scrollTop: $(".eln-main-content").offset().top
            // }, 1000);

            // backup of the opened filter divs
            var openedFilters = {};
            var openedShowMore = {};
            var layerFilters = {};
            $('div > div > div > div.eln-filter-item.active').each(function () {
                var uid = $(this).parents('div.block.filter').attr('uid');
                if (typeof openedFilters[uid] === "undefined") {
                    openedFilters[uid] = [];
                    layerFilters[uid] = {};
                }
                openedFilters[uid].push($(this).attr('attribute-code'));

                if ($(this).find('.show-more').length > 0) {
                    if ($(this).find('.hide-more').length == 0) {
                        if (typeof openedShowMore[uid] === "undefined") {
                            openedShowMore[uid] = [];
                        }
                        openedShowMore[uid].push($(this).attr('attribute-code'));
                    }
                }

                if ($(this).find('.eln-layer-filter').length == 1) {
                    let filter = $(this).find('.eln-layer-filter').val();
                    if (filter !== "") {
                        layerFilters[uid][$(this).attr('attribute-code')] = filter;
                    }
                }

            });


            // backup of the opened categories in tree
            var openedCategories = {};
            $('li.children.active').each(function () {
                var uid = $(this).parents('div.block.filter').attr('uid');
                if (typeof openedCategories[uid] === "undefined") {
                    openedCategories[uid] = [];
                }
                openedCategories[uid].push($(this).attr('category-id'));
            });
            // unique hash of the parameters
            var hash = this.hash(JSON.stringify(data));
            var requestStartTime = Date.now();
            // request already in cache?

            if (!$('body').hasClass('catalogsearch-result-index') || this.search.term.trim() !== "") {
                if (this.storageGet(hash)) {
                    this.updateContent(this.storageGet(hash), openedFilters, openedShowMore, openedCategories, layerFilters, fullStartTime, requestStartTime, hash, fromSearchBox);
                    $('.eln-main-loader').fadeOut('fast');
                } else {
                    // not in cache => perform an ES request
                    this.xhr = $.ajax({
                        url: this.config.elasticsearchUrl,
                        method: "POST",
                        global: false,
                        data: data,
                        dataType: "json"
                    }).done(function (data) {
                        _.each(data['products'], function (product) {
                            // cache configurable products data
                            if (typeof product.configurable_index !== "undefined") {
                                this.configurableIndex[product.id] = $.parseJSON(product.configurable_index);
                                this.configurableImages[product.id] = $.parseJSON(product.configurable_images);
                            }
                        }.bind(this));
                        // update the products list with the new products list from ES
                        this.updateContent(data, openedFilters, openedShowMore, openedCategories, layerFilters, fullStartTime, requestStartTime, null, fromSearchBox);
                        // cache the results
                        this.storageSet(hash, data);

                        $('.eln-main-loader').fadeOut('fast');
                    }.bind(this)).fail(function (jqXHR, textStatus) {
                        console.log("Request failed: " + textStatus); // " No alive node in your cluster" handled here
                        $('.eln-main-loader').fadeOut('fast');
                        //orig//$('.eln-main-loader').addClass('hide').css({'display': 'none'});
                        $('body.page-products :not(#eln-product-products)>.products.wrapper, body.page-products .toolbar.toolbar-products:not(.eln-toolbar)').css({opacity: 1});
                    }.bind(this));
                }
            } else {
                this.storageSet(hash, {
                    "synonyms": [""],
                    "products": [],
                    "amount": 0,
                    "aggregations": [],
                    "selectedFilters": [],
                    "time": 0
                });
                this.updateContent(this.storageGet(hash), openedFilters, openedShowMore, openedCategories, fullStartTime, requestStartTime, hash, fromSearchBox);
                $('.eln-main-loader').fadeOut('fast');
            }
        },

        /**
         * Update the content of the products list and the filters (not infinite scroll)
         * @param data
         * @param openedFilters
         * @param openedCategories
         * @param fullStartTime
         * @param requestStartTime
         * @param cacheHash
         */
        updateContent: function (data, openedFilters, openedShowMore, openedCategories, layerFilters, fullStartTime, requestStartTime, cacheHash, fromSearchBox) {

            // hide the Magento native grid
            //$('.eln-main-content').parent().find("> .toolbar.toolbar-products").remove();
            //$('.eln-main-content').parent().find("> .products.wrapper").remove();
            $(".message.info.empty").remove();


            var requestTime = Date.now() - requestStartTime;
            var renderingStartTime = Date.now();
            var amount = data['amount'];


            if (fromSearchBox && this.config.updateSearchTerm == 1) {
                $.ajax({
                    url: this.config.updateSearchTermUrl,
                    method: "POST",
                    global: false,
                    data: {"term": this.search.term, "num_results": amount.total},
                    dataType: "json"
                }).done(function (data) {
                }.bind(this));
            }

            //--------------------------------------------------------------
            // TOOLBAR
            if (amount === 0) {
                $('.eln-toolbar.toolbar.toolbar-products').addClass('hidden');
                $('.block.filter.horizontal').addClass('hidden');
            } else {
                $('.eln-toolbar.toolbar.toolbar-products').removeClass('hidden');
                $('.block.filter.horizontal').removeClass('hidden');
            }

            // - amount
            var size = this.paging.size;
            if (size == 'all') {
                size = amount['total'];
            }
            var to = parseInt(this.paging.from) + parseInt(size);
            if (to > amount['total']) {
                to = amount['total'];
            }
            var count = mageTemplate(this.templateSelectors.productAmount, {
                "count": amount['total'],
                "from": parseInt(this.paging.from) + 1,
                "to": to,
                "infiniteScroll": this.config.infiniteScroll.enabled,
                "labels": this.config.labels
            });
            $(this.contentSelectors.productAmount).html(count);

            count = mageTemplate(this.templateSelectors.productCount, {
                "count": amount['total'],
                "labels": this.config.labels,
                "nbFilters": _.size(data['selectedFilters'])
            });
            let nbFilters = _.size(data['selectedFilters']);
            if (nbFilters > 0) {
                $('.mobile-filter-open button span.nb-filters').html(' (' + nbFilters + ')');
            } else {
                $('.mobile-filter-open button span.nb-filters').html('');
            }
            $(this.contentSelectors.productCount).html(count);


            // Did we load all products: Yes => no infinite scroll, No => infinite scroll possible

            if (this.paging.size >= amount['total']) {
                this.infiniteScrollNoMoreProduct = true;
                $('#eln-manual-infinite-scroll').addClass('hidden');
            }
            if (amount == 0) {
                $('#eln-manual-infinite-scroll').addClass('hidden');
            }

            //--------------------------------------------------------------
            // BOTTOM
            // - paging
            var paging = "";
            if (!this.config.infiniteScroll.enabled) {
                paging = mageTemplate(this.templateSelectors.productPaging, {
                    "pages": amount['pages'],
                    "current": amount['current'],
                    "previous": amount['previous'],
                    "next": amount['next'],
                    "size": amount['size']
                });
            }
            $(this.contentSelectors.productPaging).html(paging);

            //--------------------------------------------------------------
            // PRODUCTS GRID
            // if the product grid doesn't exist, adding it
            if ($(this.contentSelectors.productItems).length === 0) {
                var html = mageTemplate(this.templateSelectors.productItems, {
                    "count": amount['total']
                });
                $(this.contentSelectors.product).html(html);
            }
            // fill in the grid with the product
            $(this.contentSelectors.productItems).html("");
            let allProductIds = [];
            _.each(data['products'], function (product) {
                allProductIds.push(product['id']);
                var htmlItem = mageTemplate(this.templateSelectors.productItem, {
                    "product": product,
                    "ajaxCartEnabled": this.config.ajaxCart.enabled,
                    "addToCompareEnabled": this.config.addToCompare.enabled,
                    "customerGroupId": this.config.customerGroupId
                });
                $(this.contentSelectors.productItems).append(htmlItem);
                $(this.contentSelectors.productItems).trigger('contentUpdated');
            }.bind(this));

            if (data['products'].length == 0) {

            }

            //--------------------------------------------------------------
            // FILTERS
            var selectedFilters = data['selectedFilters'];
            // - filters
            var filters = data['aggregations'];

            if (!_.isEmpty(filters)) {
                // cache for the filters (can be several times the same filter [top,left,right])
                var filtersCache = [];
                // price sliders config
                var initSlider = false;
                // price filters data
                var min = 0;
                var max = 0;
                var valMin = 0;
                var valMax = 0;
                // remove all filters
                $(this.contentSelectors.filters).html("");
                // add filters elts
                _.each(this.config.filterableAttributes, function (attributeInfos, uid) { // uid = left,top,right

                    _.each(attributeInfos, function (attributeInfo) {
                        var attributeCode = attributeInfo[0];
                        var showResultsCount = attributeInfo[1];
                        var showMoreLess = attributeInfo[2];
                        var showMoreLessNbValues = attributeInfo[3];
                        var showLayerFilter = attributeInfo[4];
                        var generateUrl = attributeInfo[6];

                        // need to add "_ids" at the end of the attribute code?
                        var code = "";
                        if (typeof filters[attributeCode] !== "undefined") {
                            code = attributeCode;
                        } else if (typeof filters[attributeCode + "_ids"] !== "undefined") {
                            code = attributeCode + "_ids";
                        }
                        if (code !== "") { // the attribute is well a filter

                            // attribute filter already processed => adding it in the dom
                            // if (typeof filtersCache[code] !== "undefined") { // use local cache of the current request
                            //     $("[uid=" + uid + "] " + this.contentSelectors.filters).append(filtersCache[code]);
                            //
                            // } else { // attribute filter not in the cache

                            var filter = filters[code];
                            var attributeFilter = "";

                            var goahead = 0;


                            // price filter
                            if (code === "final_price") {
                                if (filter['min'] != filter['max']) {
                                    attributeFilter = mageTemplate(this.templateSelectors.pricesFilter, {
                                        "min": filter['min'],
                                        "max": filter['max'],
                                        "valMin": filter['values']['min'],
                                        "valMax": filter['values']['max'],
                                        "displayInputBoxesForPriceFilter": this.config.displayInputBoxesForPriceFilter,
                                        "generateUrl": generateUrl
                                    });
                                    initSlider = true;
                                    min = filter['min'];
                                    max = filter['max'];
                                    valMin = filter['values']['min'];
                                    valMax = filter['values']['max'];
                                } else {
                                    attributeFilter = "";
                                }
                                // rating filter
                            } else if (code === "rating") {
                                _.each(filter, function (count, rating) {
                                    goahead += count;
                                });
                                if (((this.config.layerHideOneValue && _.size(filter) > 1) || !this.config.layerHideOneValue) && (goahead > 0 || this.config.layerUpdateMethod > 0)) {
                                    attributeFilter = mageTemplate(this.templateSelectors.ratingsFilter, {
                                        "ratings": filter,
                                        "selected": (typeof selectedFilters[code] !== "undefined") ? selectedFilters[code]['values'] : [],
                                        "showResultsCount": showResultsCount,
                                        "generateUrl": generateUrl
                                    });
                                } else {
                                    attributeFilter = "";
                                }
                                // categories filter
                            } else if (code === "categories") {
                                _.each(filter, function (category) {
                                    goahead += ((category.count == -1) ? 0 : category.count);
                                });
                                if (goahead > 0 || this.config.layerUpdateMethod > 0) {
                                    attributeFilter = mageTemplate(this.templateSelectors.categoryFilter, {
                                        "showResultsCount": showResultsCount,
                                        "generateUrl": generateUrl
                                    });
                                } else {
                                    attributeFilter = "";
                                }

                                // text swatch attribute filter
                            } else {
                                var goahead = 0;
                                _.each(filter.values, function (data, optionId) {
                                    goahead += data.count;
                                });
                                if (((this.config.layerHideOneValue && _.size(filter.values) > 1) || !this.config.layerHideOneValue) && (goahead > 0 || this.config.layerUpdateMethod > 0)) { // layerUpdateMethod > 0 => visible and disabled
                                    if (filter.textSwatch) {
                                        attributeFilter = mageTemplate(this.templateSelectors.textSwatchFilter, {
                                            "filter": filter,
                                            "attributeCode": code,
                                            "selected": (typeof selectedFilters[code] !== "undefined") ? selectedFilters[code]['values'] : [],
                                            "showResultsCount": showResultsCount,
                                            "showMoreLess": showMoreLess,
                                            "showMoreLessNbValues": showMoreLessNbValues,
                                            "generateUrl": generateUrl
                                        });

                                        // visual swatch attribute filter
                                    } else if (filter.visualSwatch) {
                                        attributeFilter = mageTemplate(this.templateSelectors.visualSwatchFilter, {
                                            "filter": filter,
                                            "attributeCode": code,
                                            "selected": (typeof selectedFilters[code] !== "undefined") ? selectedFilters[code]['values'] : [],
                                            "showResultsCount": showResultsCount,
                                            "showMoreLess": showMoreLess,
                                            "showMoreLessNbValues": showMoreLessNbValues,
                                            "generateUrl": generateUrl
                                        });

                                        // all other attributes
                                    } else {
                                        attributeFilter = mageTemplate(this.templateSelectors.attributeFilter, {
                                            "filter": filter,
                                            "attributeCode": code,
                                            "selected": (typeof selectedFilters[code] !== "undefined") ? selectedFilters[code]['values'] : [],
                                            "showResultsCount": showResultsCount,
                                            "showMoreLess": showMoreLess,
                                            "showMoreLessNbValues": showMoreLessNbValues,
                                            "showLayerFilter": showLayerFilter,
                                            "generateUrl": generateUrl
                                        });

                                    }
                                } else {
                                    attributeFilter = "";
                                }
                            }
                            // adding the filter to the cache
                            //filtersCache[code] = attributeFilter; // local caching for the current request
                            // adding the filter to the dom

                            $("[uid=" + uid + "] " + this.contentSelectors.filters).append(attributeFilter);

                            // populate categories filter treeview
                            if (code === "categories") {
                                if (goahead > 0 || this.config.layerUpdateMethod > 0) {
                                    var values = [];
                                    if ((typeof selectedFilters["categories_ids"] !== "undefined")) {
                                        values = _.keys(selectedFilters["categories_ids"]['values']);
                                    }
                                    _.each(filters.categories_ordered, function (category) {
                                        var categoryContent = mageTemplate(this.templateSelectors.categoryItemFilter, {
                                            "category": filter[category],
                                            "selected": _.contains(values, filter[category].id),
                                            "showResultsCount": showResultsCount,
                                            "generateUrl": generateUrl
                                        });
                                        var parent = $("[uid=" + uid + "] ul#eln-category-" + filter[category].parent);
                                        if (parent.length === 0) {
                                            $("[uid=" + uid + "] div[attribute-code=categories] div.eln-filter-content > ul").append(categoryContent);
                                        } else {
                                            parent.append(categoryContent);
                                        }
                                    }.bind(this));
                                    // filtersCache[code] = $("[uid=" + uid + "] " + this.contentSelectors.filters + " [attribute-code=categories]").outerHTML;
                                }
                            }
                            // }
                        }
                    }.bind(this));
                }.bind(this));

                // initialize price sliders
                if (initSlider) {
                    this.prices = {min: parseFloat(min), max: parseFloat(max)};
                    this.initPriceSlider(valMin, valMax);
                }


                // re-open previously opened filters
                _.each(openedFilters, function (attributeCodes, uid) {
                    _.each(attributeCodes, function (attributeCode) {
                        $("[uid=" + uid + "] [attribute-code=" + attributeCode + "]").addClass('active');
                    });
                });

                _.each(openedShowMore, function (attributeCodes, uid) {
                    _.each(attributeCodes, function (attributeCode) {
                        $("[uid=" + uid + "] [attribute-code=" + attributeCode + "]").find('.hide-more').removeClass('hide-more');
                    });
                });


                _.each(layerFilters, function (attributeCodes, uid) {
                    _.each(attributeCodes, function (term, attributeCode) {
                        let container = $("[uid=" + uid + "] [attribute-code=" + attributeCode + "]");
                        container.find('.eln-layer-filter').val(term);
                        container.find('.swatch-attribute').removeClass('hide-more');
                        container.find('.show-more, .show-less').css({'display': 'none'});
                        container.find('a div:not([data-filter*=' + term.toLowerCase() + '])').parent().addClass('hidden');
                        container.find('a div[data-filter*=' + term.toLowerCase() + ']').parent().removeClass('hidden');
                    });
                });

                // re-open previously opened categories
                _.each(openedCategories, function (categoryIds, uid) {
                    _.each(categoryIds, function (categoryId) {
                        $("[uid=" + uid + "] li.children[category-id=" + categoryId + "]").addClass('active');
                    });
                });
            } else {
                $("[data-role=eln-filters-content]").html("");
            }

            // if ($(window).width() >= 768 /* wider than a  smartphone */) {
            //     $("[uid=left] .eln-filter-item, [uid=right] .eln-filter-item").addClass('active');
            // }

            //--------------------------------------------------------------
            // BREADCRUMB
            if ($(this.contentSelectors.breadcrumb).length != 0) {
                var breadcrumb = mageTemplate(this.templateSelectors.breadcrumb, {
                    "filters": selectedFilters,
                    "clear_all": this.config.labels.clear_all
                });
                $(this.contentSelectors.breadcrumb).html(breadcrumb);
            }

            if (!_.isEmpty(selectedFilters)) {
                $('.eln-layer-clear-all').removeClass('hidden');
            } else {
                $('.eln-layer-clear-all').addClass('hidden');
            }


            // ELSAutocomplete categories results
            if (fromSearchBox) {
                if ($('#els-category-results-template').length) {
                    if (typeof data['category'] != "undefined") {
                        let html = mageTemplate("#els-category-results-template", {
                            "categories": data['category'].docs,
                            "count": data['category'].docs.length
                        });
                        $('#els-category-results').html(html);
                    } else {
                        $('#els-category-results').html("");
                    }
                }
                if ($('#els-cms-results-template').length) {
                    if (typeof data['cms'] != "undefined") {
                        let html = mageTemplate("#els-cms-results-template", {
                            "cms": data['cms'].docs,
                            "count": data['cms'].docs.length
                        });
                        $('#els-cms-results').html(html);
                    } else {
                        $('#els-cms-results').html("");
                    }
                }
                if ($('#els-suggest-results-template').length) {
                    if (typeof data['suggest'] != "undefined" && data['suggest'].count > 0) {
                        let html = mageTemplate("#els-suggest-results-template", {
                            "suggest": data['suggest'].docs
                        });
                        $('#els-suggest-results').html(html);
                    } else {
                        $('#els-suggest-results').html("");
                    }
                }
            }


            if (this.infiniteScrollNoMoreProduct && this.config.infiniteScroll.enabled) {
                $("#eln-infinite-scroll-end").addClass('active');
            } else {
                $("#eln-infinite-scroll-end").removeClass('active');
            }

            // DEBUG
            var fullEndTime = Date.now();
            if ($("#eln-debug-template").length >= 1) {
                var debug = mageTemplate("#eln-debug-template", {
                    "phpTime": typeof cacheHash !== "undefined" && cacheHash !== null ? 0 : data.time,
                    "requestTime": requestTime,
                    "renderingTime": (fullEndTime - renderingStartTime),
                    "totalTime": (fullEndTime - fullStartTime),
                    "fromCache": typeof cacheHash !== "undefined" && cacheHash !== null,
                    "cacheHash": cacheHash,
                    "infiniteScroll": false,
                    "templateHintsEnabled": this.templateHintsEnabled
                });
                $('#eln-debug').html(debug);
                this.toggleTemplateHints(this.templateHintsEnabled);
                this.lastRequestData = data;
            }

            // get estimated delivery dates
            this.updateEstimatedDeliveryDate(allProductIds);

            // no more request processing
            this.isRequestProcessing = false;

            // ultimo - resize product items block
            if (this.config.theme.model.includes("Infortis") && this.config.theme.config.equal_height === "1") {
                this.ULTIMO.setGridItemsEqualHeight();
            }

            if (this.config.stickyLayer == 1) {
                this.calculateNewPosSidebars();
            }
            this.updateFormKey();

            if (fromSearchBox) {
                $(document).trigger('wyo-search-term-updated-finish');
            }


        },


        //######################################################################
        // ULTIMO TOOLS
        //######################################################################
        ULTIMO: {
            /**
             * Resize the product blocks in the grid (see Infortis_Ultimo theme js scripts)
             */
            setGridItemsEqualHeight: function () {
                var bottomMinSpace = 20; // Minimum space below the button at the bottom of the item
                var gridItemMaxHeight = 0;
                var gridItemMaxPaddingBottom = 0;
                var $listContainer = jQuery('.category-products-grid');
                var $listItems = $listContainer.children('ol').children();
                var centered = $listContainer.hasClass('centered');
                var $row = jQuery();
                $listItems.each(function () {
                    var $item = jQuery(this);
                    var $actionsBlock = $item.find('.actions');
                    // Check if first item in a row
                    if ($item.css("clear") === "left") {
                        // If row not empty, apply the max values to all items in a row
                        if ($row.length) {
                            $row.css({
                                "height": gridItemMaxHeight + "px",
                                "padding-bottom": gridItemMaxPaddingBottom + "px"
                            });
                            // Reset the row collection and reset the max values
                            $row = jQuery();
                            gridItemMaxHeight = 0;
                            gridItemMaxPaddingBottom = 0;
                        }
                    }
                    $row = $row.add($item);
                    $item.css("height", "auto");
                    gridItemMaxHeight = Math.max(gridItemMaxHeight, $item.height());
                    // Use constant bottomMinSpace as bottom offset for the actions container
                    $actionsBlock.css("bottom", bottomMinSpace + "px");
                    // Align button to the center
                    if (centered) {
                        var objectWidth = $actionsBlock.width();
                        var availableWidth = $item.width();
                        var space = availableWidth - objectWidth;
                        var leftOffset = ~~(space / 2);
                        $actionsBlock.css("padding-left", leftOffset + "px");
                    }
                    // Set bottom padding wich equals to: actions container height + bottomMinSpace
                    var currentPaddingBottom = bottomMinSpace + $actionsBlock.innerHeight();
                    gridItemMaxPaddingBottom = Math.max(gridItemMaxPaddingBottom, currentPaddingBottom);
                    $item.css("padding-bottom", currentPaddingBottom + "px"); // TODO: possibly redundant. Padding will be applied for the entire row.
                });
                // Apply the max values to all items in the last row
                if ($row.length) {
                    $row.css({
                        "height": gridItemMaxHeight + "px",
                        "padding-bottom": gridItemMaxPaddingBottom + "px"
                    });
                }
            }
        },


        //######################################################################
        // GENERAL TOOLS
        //######################################################################

        /**
         * Get a unique hash of a string
         * @param string
         * @returns {number}
         */
        hash: function (string) {
            var hash = 0;
            if (string.length === 0) {
                return hash;
            }
            for (var i = 0; i < string.length; i++) {
                var char = string.charCodeAt(i);
                hash = ((hash << 5) - hash) + char;
                hash = hash & hash; // Convert to 32bit integer
            }
            return hash;
        },

        //######################################################################
        // DEBUG TOOLS
        //######################################################################

        /**
         * Enable the template hints
         * @param on true => enable, false => disable
         */
        toggleTemplateHints: function (on) {
            // add a hint for all Underscore.js template
            _.each(this.templateSelectors, function (elt, id) {
                // remove all hints
                $(elt + "-th").remove();
                if (on) { // enabling
                    var div = $("<div>").addClass("eln-template-hint").addClass("template-hint").attr('id', elt.replace("#", "") + "-th");
                    div.html("<a name='" + id.toUpperCase() + "'>" + id.toUpperCase() + "</a><br/>elt: " + elt + "<br/>file: " + this.contentTemplateFiles[id]);
                    // the template dom elt is a script node => adding the hint before the node
                    div.insertBefore($(elt));
                }
            }.bind(this));

            // add a hint for all blocks updated using uUnderscore.js template
            _.each(this.contentSelectors, function (elt, id) {
                // remove all hints
                $(elt + " > .eln-template-hint").remove();
                if (on) { // enabling template hints
                    this.templateHintsEnabled = true;
                    $('#eln-debug-disable-template-hints').show();
                    $('#eln-debug-enable-template-hints').hide();
                    var div = $("<div>").addClass("eln-template-hint");
                    if (typeof this.templateSelectors[id] != "undefined") {
                        // an underscore.js template exists => add an anchor link to the hint of the underscore.js template
                        div.html(id.toUpperCase() + "<br/>elt: " + elt + "<br/>_tpl: <a onClick='jQuery(\".template-hint.selected\").removeClass(\"selected\");jQuery(\"" + this.templateSelectors[id] + "-th\").addClass(\"selected\")' href='#" + id.toUpperCase() + "'>" + this.templateSelectors[id] + "</a>");
                    } else {
                        div.html(id.toUpperCase() + "<br/>elt: " + elt + "<br/>phtml: " + this.contentTemplateFiles[id]);
                    }
                    $(elt).prepend(div);
                    $(elt).addClass("eln-template-hint-container");
                } else { // disabling templateh hints
                    this.templateHintsEnabled = false;
                    // remove hint class to the container
                    $(elt).removeClass("eln-template-hint-container");
                    $('#eln-debug-disable-template-hints').hide();
                    $('#eln-debug-enable-template-hints').show();
                }
            }.bind(this));
        },
        getCookie: function (cname) {
            if (cname != 'eln_mode') {
                if (this.search.term != "") {
                    cname += "_search";
                } else {
                    cname += "_category";
                }
            }
            var name = cname + "=";
            var decodedCookie = decodeURIComponent(document.cookie);
            var ca = decodedCookie.split(';');
            for (var i = 0; i < ca.length; i++) {
                var c = ca[i];
                while (c.charAt(0) == ' ') {
                    c = c.substring(1);
                }
                if (c.indexOf(name) == 0) {
                    return c.substring(name.length, c.length);
                }
            }
            return "";
        },

        /**
         * use own function instaead of $.cookie in order to remove the leading dot before the domain name
         * @param c_name
         * @param value
         * @param exdays
         */
        setCookie: function (c_name, value, exdays) {
            if (c_name != 'eln_mode') {
                if (this.search.term != "") {
                    c_name += "_search";
                } else {
                    c_name += "_category";
                }
            }
            var exdate = new Date();
            exdate.setDate(exdate.getDate() + exdays);
            var c_value = escape(value) + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString());
            document.cookie = c_name + "=" + c_value + "; path=/;";
        },

        updateFormKey: function () {
            let formKey = this.getCookie("form_key");
            $('input[name=form_key]').val(formKey);
            var as = $('a[href*=\\/form_key\\/]');
            as.each(function (i) {
                let link = jQuery(as[i]);
                let href = link.attr('href').replace(/form_key\/[^\/]+\//, "form_key/" + formKey + "/");
                link.attr("href", href);

            });
        },

        encodeFilters: function (filters, additionalAttributeOption) {
            var parameters = "";
            var attributeCode = "";
            if (typeof additionalAttributeOption != "undefined") {
                attributeCode = additionalAttributeOption.attributeCode.toLowerCase().replace('_ids', '');
            }
            _.each(filters, function (data, key) {
                if (!_.contains(this.allowUrls, key)) {
                    return;
                }
                key = key.toLowerCase().replace('_ids', '');
                if (parameters !== "") {
                    parameters += "/";
                }
                parameters += key + "/";
                if (_.isArray(data)) {
                    let tmpData = [];
                    _.each(data, function (val, i) {
                        data[i] = val.replace(new RegExp(/-/g), "_");
                        tmpData.push(data[i]);
                    });

                    if (typeof additionalAttributeOption != "undefined" && additionalAttributeOption != "" && attributeCode == key) {
                        tmpData.push(("" + additionalAttributeOption.optionLabel).toLowerCase().replace(new RegExp(/-/g), '_'));
                        additionalAttributeOption = "";
                    }
                    tmpData.sort();
                    parameters += (tmpData + "").replace(new RegExp(/,/g), '-');
                } else if (_.isObject(data)) {
                    var tmp = [];
                    _.each(data, function (data, key) {
                        tmp.push(key + ":" + data);
                    });
                    parameters += "[" + tmp + "]";
                } else {
                    data.sort();
                    parameters += (data + "").replace(new RegExp(/,/g), '-');
                    ;
                }
            }.bind(this));
            if (typeof additionalAttributeOption != "undefined" && additionalAttributeOption != "") {
                if (parameters != "") {
                    parameters += "/";
                }
                parameters += attributeCode + "/" + additionalAttributeOption.optionLabel;
            }
            return parameters;
        },
        encodeFiltersMinus: function (filters, additionalAttributeOption) {
            additionalAttributeOption.optionLabel = ("" + additionalAttributeOption.optionLabel).toLowerCase().replace(new RegExp(/-/g), '_');
            var parameters = "";
            _.each(filters, function (data, key) {
                if (_.isArray(data)) {
                    data.sort();
                    let values = ("" + (_.without(data, additionalAttributeOption.optionLabel) + "").replace(new RegExp(/,/g), '-'));
                    if (values != "") {
                        parameters += "/" + key + "/";
                        parameters += (values + "").replace(new RegExp(/,/g), '-');
                    }
                } else if (_.isObject(data)) {
                    var tmp = [];
                    _.each(data, function (data, key) {
                        tmp.push(key + ":" + data);
                    });
                    parameters += "/" + key + "/";
                    parameters += "[" + tmp + "]";
                } else {
                    if (data != additionalAttributeOption.optionLabel) {
                        data.sort();
                        _.each(data, function (val, i) {
                            data[i] = val.replace(new RegExp(/-/g), "_");
                        });
                        parameters += "/" + key + "/";
                        parameters += (data + "").replace(new RegExp(/,/g), '-');
                    }
                }
            });
            return parameters;
        },


        decodeFilters: function (encoded) {
            try {
                var json = {};
                _.each(encoded, function (values, att) {
                    if (att == "q") {
                        return;
                    }
                    if (values.startsWith('[')) {
                        var tmpjson = {};
                        var tmpdata = values.replace('[', '').replace(']', '').split(',');
                        _.each(tmpdata, function (prop) {
                            prop = prop.split(':');
                            tmpjson[prop[0]] = prop[1];

                        });
                        values = tmpjson;
                    } else {
                        values = values.split('-');
                        _.each(values, function (val, i) {
                            values[i] = val.replace(new RegExp(/_/g), "-");
                        });
                    }
                    json[att] = values;
                });
                return json;
            } catch (e) {
                return {};
            }
        },

        storageSet: function (hash, data) {
            //sessionStorage.setItem("elsln-cache-" + hash, JSON.stringify(data));
            this.cache[hash] = JSON.stringify(data);
        },
        storageGet: function (hash) {
            //if (sessionStorage.getItem("elsln-cache-" + hash)) {
            if (typeof this.cache[hash] != "undefined") {
                //return $.parseJSON(sessionStorage.getItem("elsln-cache-" + hash));
                return $.parseJSON(this.cache[hash]);
            } else {
                return null;
            }
        },

        eddRequest: null,

        updateEstimatedDeliveryDate: function (allProductsIds) {
            if (this.config.edd) {
                // if (typeof this.eddRequest !== undefined && this.eddRequest !== null) {
                //     this.eddRequest.abort();
                // }
                this.eddRequest = $.ajax({
                    url: "/estimateddeliverydate/message/update",
                    method: "post",
                    global: false,
                    data: {"ids": allProductsIds},
                    dataType: 'json',
                    success: function (data) {
                        _.each(data.edd_data, function (msg, id) {
                            $('#estimated-delivery-date-' + id).replaceWith(msg.replace(/\\/g, ""));
                        });
                        if (this.config.theme.model.includes("Infortis") && this.config.theme.config.equal_height === "1") {
                            this.ULTIMO.setGridItemsEqualHeight();
                        }
                    }.bind(this)
                });
            }
        }


    };
});
