(function (paw, utils) {
    /**
     * Note on furhter dev:
     * If custom content would need to be supported:
     * - datagrid features should be moved to own component
     * - proper datagrid initialization logic should be impl.
     * 
     * @param {jQuery} $elt 
     */
    function FinderComponent($elt) {        
        var self = this;

        this.FinderDef;
        this.finderSettings;
        this.localization;

        this.$elt = $elt;
        this.$filtersHolder = null;
        this.$datagridHolder = null;
        this.$finderFiltersAction = null;

        this.finderDef = null;

        this.filterDefs = [];
        this.pinnedFilters = {};

        this.filtersPopup = null;
        this.datatable = null;

        this.filtersConfig = {};

        this.findOnChange = true;
        this.findDebouncer = utils.async.debouncer(function(){
            self.findDebounced();
        }, 400);
    }

    FinderComponent.prototype.markupDef = function(){
        var markup = [];
        markup.push('<div class="paw-area-v paw-holder paw-nooverflow paw-holder-rel">');
        markup.push('   <div class="paw-col paw-area-h paw-items-middle paw-finder-filters paw-nooverflow">');
        markup.push('      <div class="paw-col-d paw-area-h paw-finder-pinned-filters paw-nooverflow"></div>');
        markup.push('      <div class="paw-col paw-finder-filters-holder">');
        markup.push('         <button id="finder-filters" class="btn btn-primary btn-outline btn-nav">');
        markup.push('            <span class="fa fa-filter"></span>');
        markup.push('            <span class="paw-finder-filters-label">' + this.localization.filters + '</span>');
        markup.push('         </button>');
        markup.push('      </div>');
        markup.push('   </div>');
        markup.push('   <div class="paw-col-d paw-nooverflow paw-finder-datagrid-holder">');
        markup.push('      <div class="paw-finder-datagrid"></div>');
        markup.push('   </div>');
        markup.push('   <div class="paw-preloader-backdrop paw-preloader-cover">');
        markup.push('      <span class="fa fa-spinner fa-2x paw-preloader paw-preloader-spin"></span>');
        markup.push('   </div>');
        markup.push('</div>');
        return markup;
    };

    FinderComponent.prototype.filterMarkupDef = function(filter){
        var markup = [];
        markup.push('<div class="paw-col-d paw-finder-filter-slot">');
        if(utils.value.isSet(filter.label)){
            markup.push('   <div class="paw-text-ellipsis">');
            markup.push('      <span>' + filter.label + '</span>');
            markup.push('   </div>');
        }
        markup.push('   <div>');
        markup.push(filter.markup);
        markup.push('   </div>');
        markup.push('</div>');
        return markup;
    };

    FinderComponent.prototype.datagridMarkupDef = function () {
        var markup = [];
        
        markup.push('<table id="' + this.finderDef.getId() + '-datatable" data-grid-id="' + this.finderDef.getId() + '-datagrid" data-url="' + this.finderSettings.datagridUrl + '" class="list-table">');
        markup.push('   <thead>');
        markup.push('      <tr>');
        utils.iterable.iterate(this.gridColumns, function(col){
            var headerAttrs = '';
            if(utils.value.isSet(col.url)){
                headerAttrs += ' data-url="' + col.url + '"';
            }
            if(utils.value.isSet(col.width)){
                headerAttrs += ' width="' + col.width + '"'
            }
            markup.push('<th ' + headerAttrs + '>');
            markup.push(col.label);
            markup.push('</th>');
        });
        markup.push('      </tr>');
        markup.push('   </thead>');
        markup.push('</div>');
        return markup;
    };

    FinderComponent.prototype.init = function(){
        var self = this;
        this.$filtersHolder = this.$elt.find('.paw-finder-pinned-filters');
        this.$datagridHolder = this.$elt.find('.paw-finder-datagrid');
        this.$finderFiltersAction = this.$elt.find('#finder-filters');

        this.finderDef = new this.FinderDef(this, this.$filtersHolder, this.$datagridHolder, this.finderSettings, this.localization);
        this.gridColumns = this.finderDef.gridColumnsDef();
        
        self.$datagridHolder.html(self.datagridMarkupDef().join('\n'));
        self.$datagridHolder.css('opacity', 0);
        
        this.$finderFiltersAction.on('click', function(){
            self.findOnChange = false;
            self.openFiltersPopup();
        });

        utils.async.when(utils.async.all([
            this.finderDef.init()
        ])).then(function(){
            self.finderDef.data = self.finderDef.resetValues();
            self.filterDefs = self.finderDef.filtersDef();

            self.loadFiltersConfig();
            self.createPinnedFilters();

            self.$datagridHolder.css('opacity', '');
            self.$elt.find('.paw-preloader-backdrop').fadeOut(); 

            return self.initDatagrid();
        }).then(function(){
            self.onResize();
        });
    };

    FinderComponent.prototype.destroy = function(){
        this.destroyPinnedFilters();

        if(utils.value.isSet(this.datatable)){
            this.datatable.destroy();
            this.datatable = null;
        }

        if(utils.value.isFunction(this.finderDef.destroy)){
            this.finderDef.destroy();
        }

        if(utils.value.isSet(this.filtersPopup)){
            this.filtersPopup.hide();
        }

        this.$finderFiltersAction.off('click');

        this.$finderFiltersAction.off();
    };

    
    FinderComponent.prototype.onResize = function(){
        this.datatable.columns.adjust();
        if (this.datatable.fixedHeader) {
            this.datatable.fixedHeader.adjust();
        }
        if (this.datatable.responsive) {
            this.datatable.responsive.recalc();
        }
    };

    FinderComponent.prototype.createFilterFromDef = function(filterDef, data, $elt, pinned, $filtersHolder){
        filterDef.pinned = pinned;
        return {
            id: filterDef.id,
            $elt: $elt,
            inputField: filterDef.inputField($elt.find('#' + filterDef.id), data, $filtersHolder),
            def: filterDef
        };
    };

    FinderComponent.prototype.createPinnedFilters = function(){
        var self = this;
        var pinnedFiltersCount = 0;
        utils.iterable.iterate(this.filterDefs, function(filterDef){
            if(!filterDef.pinned){
                return ;
            }
            var $filter = $(self.filterMarkupDef(filterDef).join('\n'));
            self.$filtersHolder.append($filter);
            self.pinnedFilters[filterDef.id] = self.createFilterFromDef(filterDef, self.finderDef.data, $filter, true, self.$filtersHolder);
            pinnedFiltersCount++;
        });

        this.adjustPinnedFiltersWidth(pinnedFiltersCount);
    };

    FinderComponent.prototype.adjustPinnedFiltersWidth = function(pinnedFiltersCount){
        if(pinnedFiltersCount <= 1){
            return;
        }
        var pinnedFilterMaxW = 100 / pinnedFiltersCount;
        utils.iterable.iterate(this.pinnedFilters, function(pinnedFilter){
            pinnedFilter.$elt.css('max-width', pinnedFilterMaxW + '%');
        });
    };

    FinderComponent.prototype.destroyPinnedFilters = function(){
        var self = this;
        utils.iterable.iterate(self.pinnedFilters, function(pinnedFilter){
            pinnedFilter.inputField.remove();
            pinnedFilter.$elt.remove();
            delete self.pinnedFilters[pinnedFilter.id];
        });
    };

    FinderComponent.prototype.openFiltersPopup = function(){
        var self = this;
        this.filtersPopup = new paw.com.Popup('finder-filters-popup', {
            Component: paw.com.finder.FinderFiltersComponent,
            bind: {
                finderDef: self.finderDef,
                filterDefs: self.filterDefs,
                pinnedFilters: self.pinnedFilters,
                filtersConfig: self.filtersConfig,
                data: $.extend(true, {}, self.finderDef.data),
                localization: self.localization,
                onSearch: function(data){
                    self.findOnChange = true;
                    $.extend(true, self.finderDef.data, data);
                    utils.iterable.iterate(self.filterDefs, function(filterDef){
                        var pinnedFilter = self.pinnedFilters[filterDef.id];
                        if(utils.value.isSet(pinnedFilter)){
                            pinnedFilter.inputField.refreshValue();
                            return;
                        }
                    });

                    self.filtersPopup.hide();
                    self.find();
                },
                onClear: function(){
                    utils.iterable.iterate(self.pinnedFilters, function(filter){
                        filter.refreshValue();
                    });
                    self.storeFiltersConfig();
                },
                onPinned: function(filter){
                    self.storeFiltersConfig();
                    self.destroyPinnedFilters();
                    self.createPinnedFilters();
                },
                createFilterFromDef: function(filterDef, data, $filter, pinned, $filtersHolder){
                    return self.createFilterFromDef(filterDef, data, $filter, pinned, $filtersHolder);
                }
            },
            styleClass: 'paw-finder-filters-popup',
            title: self.localization.filters,
            onClose: function(){
                self.findOnChange = true;
                self.filtersPopup = null;
            }
        });
        this.filtersPopup.show();
    };

    FinderComponent.prototype.initDatagrid = function(){
        var self = this;
        var $dt = this.$datagridHolder.find('table');
        var d = utils.async.defer();
        this.datatable = $dt.DataTable({
            responsive: false,
            ajax: {
                url: $dt.attr('data-url'),
                data: function (d) {
                    if(utils.value.isFunction(self.finderDef.datagridFilters)){
                        self.finderDef.datagridFilters(d);
                    }
                }
            },
            order: [[1, 'desc']],
            columns: utils.iterable.map(this.gridColumns, function(colDef){
                return colDef.def;
            }),
            stateSave: false,
            stateSaveCallback: undefined,
            stateLoadCallback: undefined,
            fixedHeader: true,
            scrollX: true,
            scrollY: this.$datagridHolder.parent().height() + 'px',
            scroller: {
                rowHeight: 'auto',
                displayBuffer: 0.5,
                loadingIndicator: true
            },
            initComplete: function(){
                $.fn.dataTable.defaults.initComplete.apply(this, arguments);
                d.resolve();
            },
            fixedColumns: {
                leftColumns: 1
            }
        });
        return d.promise;
    };

    FinderComponent.prototype.fetchDatatableData = function(){
        var d = utils.async.defer();
        try{
            this.datatable.ajax.reload(function(){
                d.resolve();
            });
        }
        catch(err){
            console.error("Finder error", err);
            d.reject();
        }
        return d.promise;
    };

    FinderComponent.prototype.find = function(){
        if(this.findOnChange){
            return this.findDebouncer();
        }
    };

    FinderComponent.prototype.findDebounced = function(){
        var self = this;
        return this.fetchDatatableData().then(function(){
            self.storeFiltersConfig();
        });
    };

    FinderComponent.prototype.getFiltersStorageKey = function(){
        return 'paw-finder_' + this.finderDef.getId() + '_' + this.finderSettings.user.userId + '_' + this.finderSettings.user.domain;
    };

    FinderComponent.prototype.loadFiltersConfig = function(){
        var self = this;
        var filtersConfig = this.getFiltersConfig();
        if(utils.value.isSet(filtersConfig)){
            this.filtersConfig = filtersConfig;

            utils.iterable.iterate(this.filterDefs, function(filterDef){
                var filterConfig = self.filtersConfig[filterDef.id];
                if(!utils.value.isSet(filterConfig)){
                    return;
                }
                if(!filterConfig.ignoreStoreValue){
                    self.finderDef.data[filterConfig.id] = filterConfig.value;
                }
                filterDef.pinned = filterConfig.isPinned;
            });
        }
        return this.filtersConfig;
    };

    FinderComponent.prototype.getFiltersConfig = function(){
        var filtersConfig = localStorage.getItem(this.getFiltersStorageKey());
        if(utils.value.isSet(filtersConfig)){
            return JSON.parse(filtersConfig);
        }
        return null;
    };

    FinderComponent.prototype.storeFiltersConfig = function(){
        var self = this;
        var filtersConfig = {};
        var removeIds = [];
        utils.iterable.iterate(this.filterDefs, function(filterDef){
            filtersConfig[filterDef.id] = {
                id: filterDef.id,
                isPinned: filterDef.pinned,
                value: self.finderDef.data[filterDef.id]
            };
        });
        utils.iterable.iterate(removeIds, function(id){
            delete filtersConfig[id];
        });
        localStorage.setItem(this.getFiltersStorageKey(), JSON.stringify(filtersConfig));
    };

    paw.com.finder.FinderComponent = FinderComponent;
})(paw, paw.utils);