/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file This is the common View file for displaying Table/Grid to be used overall in the application.
 */
define(['require',
    'backbone',
    'hbs!tmpl/common/TableLayout_tmpl',
    'utils/Messages',
    'utils/Utils',
    'utils/Globals',
    'utils/CommonViewFunction',
    'backgrid-filter',
    'backgrid-paginator',
    'backgrid-sizeable',
    'backgrid-orderable',
    'backgrid-select-all',
    'backgrid-columnmanager'
], function(require, Backbone, FSTablelayoutTmpl, Messages, Utils, Globals, CommonViewFunction) {
    'use strict';

    var FSTableLayout = Backbone.Marionette.LayoutView.extend(
        /** @lends FSTableLayout */
        {
            _viewName: 'FSTableLayout',

            template: FSTablelayoutTmpl,
            templateHelpers: function() {
                return this.options;
            },

            /** Layout sub regions */
            regions: {
                'rTableList': 'div[data-id="r_tableList"]',
                'rTableSpinner': 'div[data-id="r_tableSpinner"]',
                'rPagination': 'div[data-id="r_pagination"]',
                'rFooterRecords': 'div[data-id="r_footerRecords"]'
            },

            // /** ui selector cache */
            ui: {
                selectPageSize: 'select[data-id="pageSize"]',
                paginationDiv: '[data-id="paginationDiv"]',
                previousData: "[data-id='previousData']",
                nextData: "[data-id='nextData']",
                pageRecordText: "[data-id='pageRecordText']",
                showPage: "[data-id='showPage']",
                gotoPage: "[data-id='gotoPage']",
                gotoPagebtn: "[data-id='gotoPagebtn']",
                activePage: "[data-id='activePage']"
            },

            gridOpts: {
                className: 'table table-bordered table-hover table-condensed backgrid',
                emptyText: 'No Records found!'
            },

            /**
             * Backgrid.Filter default options
             */
            filterOpts: {
                placeholder: 'plcHldr.searchByResourcePath',
                wait: 150
            },

            /**
             * Paginator default options
             */
            paginatorOpts: {
                // If you anticipate a large number of pages, you can adjust
                // the number of page handles to show. The sliding window
                // will automatically show the next set of page handles when
                // you click next at the end of a window.
                windowSize: 5, // Default is 10

                // Used to multiple windowSize to yield a number of pages to slide,
                // in the case the number is 5
                slideScale: 0.5, // Default is 0.5

                // Whether sorting should go back to the first page
                goBackFirstOnSort: false // Default is true
            },

            /**
               page handlers for pagination
            */
            controlOpts: {
                rewind: null,
                back: {
                    label: "<i class='fa fa-angle-left'></i>",
                    title: "Previous"
                },
                forward: {
                    label: "<i class='fa fa-angle-right'></i>",
                    title: "Next"
                },
                fastForward: null
            },
            columnOpts: {
                opts: {
                    initialColumnsVisible: 4,
                    // State settings
                    saveState: false,
                    loadStateOnInit: true
                },
                visibilityControlOpts: {},
                el: null
            },

            includePagination: true,

            includeAtlasPagination: false,

            includeAtlasPageSize: false,

            includeFilter: false,

            includeHeaderSearch: false,

            includePageSize: false,

            includeGotoPage: false,

            includeFooterRecords: true,

            includeColumnManager: false,

            includeSizeAbleColumns: false,

            includeOrderAbleColumns: false,

            includeTableLoader: true,

            includeAtlasTableSorting: false,

            showDefaultTableSorted: false,

            /**
             * [updateFullCollectionManually  If collection was updated using silent true
             * then need to update FullCollection Manually for correct sorting experience]
             * @type {Boolean}
             */
            updateFullCollectionManually: false,

            sortOpts: {
                sortColumn: "name",
                sortDirection: "ascending"
            },


            /** ui events hash */
            events: function() {
                var events = {},
                    that = this;
                events['change ' + this.ui.selectPageSize] = 'onPageSizeChange';
                events['change ' + this.ui.showPage] = 'changePageLimit';
                events["click " + this.ui.nextData] = "onClicknextData";
                events["click " + this.ui.previousData] = "onClickpreviousData";
                events["click " + this.ui.gotoPagebtn] = 'gotoPagebtn';
                events["keyup " + this.ui.gotoPage] = function(e) {
                    var code = e.which,
                        goToPage = parseInt(e.currentTarget.value);
                    if (e.currentTarget.value) {
                        that.ui.gotoPagebtn.attr('disabled', false);
                    } else {
                        that.ui.gotoPagebtn.attr('disabled', true);
                    }
                    if (code == 13) {
                        if (e.currentTarget.value) {
                            that.gotoPagebtn();
                        }
                    }
                };
                return events;
            },

            /**
             * intialize a new HDFSTableLayout Layout
             * @constructs
             */
            initialize: function(options) {
                this.limit = 25;
                this.offset = 0;
                _.extend(this, _.omit(options, 'gridOpts', 'sortOpts', 'atlasPaginationOpts'));
                _.extend(this, options.atlasPaginationOpts);
                _.extend(this.gridOpts, options.gridOpts, { collection: this.collection, columns: this.columns });
                _.extend(this.sortOpts, options.sortOpts);
                /* Atlas schema / client pagination: block double-clicks while fetch runs. */
                this._atlasPaginationBusy = false;
                this._lastRenderAtlasPaginationOptions = {};
                if (this.isApiSorting) {
                    //after audit sorting pagination values
                    if (this.offset === 0) {
                        this.limit = this.count || this.limit;
                    }
                }
                if (this.includeAtlasTableSorting) {
                    var oldSortingRef = this.collection.setSorting;
                    this.collection.setSorting = function() {
                        this.state.pageSize = this.length
                        var val = oldSortingRef.apply(this, arguments);
                        val.fullCollection.sort();
                        this.comparator = function(next, previous, data) {
                            var getValue = function(options) {
                                    var next = options.next,
                                        previous = options.previous,
                                        order = options.order;
                                    if (next === previous) {
                                        return null;
                                    } else {
                                        if (order === -1) {
                                            return next < previous ? -1 : 1;
                                        } else {
                                            return next < previous ? 1 : -1;
                                        }
                                    }
                                },
                                getKeyVal = function(model, key) {
                                    //for nested obj
                                    var value = null;
                                    if (model && key) {
                                        value = model[key];
                                        if (!value) {
                                            _.each(model, function(modalValue) {
                                                if (typeof(modalValue) == "object") {
                                                    if (!value) {
                                                        value = getKeyVal(modalValue, key);
                                                    }
                                                }
                                            });
                                        }
                                    }
                                    return Number(value) || value;
                                };
                            if (val.state && (!_.isNull(val.state.sortKey))) {
                                var nextValue,
                                    previousValue;
                                if ((next && next.get("attributes") && next.get("attributes")[val.state.sortKey]) || (previous && previous.get("attributes") && previous.get("attributes")[val.state.sortKey])) {
                                    nextValue = next.get("attributes")[val.state.sortKey];
                                    previousValue = previous.get("attributes")[val.state.sortKey];
                                } else {
                                    nextValue = getKeyVal(next.attributes, val.state.sortKey);
                                    previousValue = getKeyVal(previous.attributes, val.state.sortKey);
                                }
                                nextValue = (typeof nextValue === 'string') ? nextValue.toLowerCase() : nextValue;
                                previousValue = (typeof previousValue === 'string') ? previousValue.toLowerCase() : previousValue;
                                return getValue({
                                    "next": nextValue || '',
                                    "previous": previousValue || '',
                                    "order": val.state.order
                                });
                            }
                        }
                        return val;
                    };
                }
                this.bindEvents();
            },
            /** all events binding here */
            bindEvents: function() {
                this.listenTo(this.collection, 'request', function() {
                    this.$('div[data-id="r_tableSpinner"]').addClass('show');
                }, this);
                this.listenTo(this.collection, 'sync error', function() {
                    this.$('div[data-id="r_tableSpinner"]').removeClass('show');
                }, this);

                this.listenTo(this.collection, 'reset', function(collection, options) {
                    this.$('div[data-id="r_tableSpinner"]').removeClass('show');
                    this.ui.gotoPage.val('');
                    this.ui.gotoPage.parent().removeClass('has-error');
                    this.ui.gotoPagebtn.prop("disabled", true);
                    if (this.includePagination) {
                        this.renderPagination();
                    }
                    if (this.includeFooterRecords) {
                        this.renderFooterRecords(this.collection.state);
                    }
                    if (this.includeAtlasPagination) {
                        this.renderAtlasPagination(options);
                    }
                }, this);

                /*This "sort" trigger event is fired when clicked on
                'sortable' header cell (backgrid).
                Collection.trigger event was fired because backgrid has
                removeCellDirection function (backgrid.js - line no: 2088)
                which is invoked when "sort" event is triggered
                on collection (backgrid.js - line no: 2081).
                removeCellDirection function - removes "ascending" and "descending"
                which in turn removes chevrons from every 'sortable' header-cells*/
                this.listenTo(this.collection, "backgrid:sorted", function(column, direction, collection) {
                    // backgrid:sorted fullCollection trigger required for icon chage
                    if (this.isApiSorting) {
                        column.set("direction", direction);
                    } else {
                        this.collection.fullCollection.trigger("backgrid:sorted", column, direction, collection)
                        if (this.includeAtlasTableSorting && this.updateFullCollectionManually) {
                            this.collection.fullCollection.reset(collection.toJSON(), { silent: true });
                        }
                    }
                }, this);
                this.listenTo(this, "grid:refresh", function() {
                    if (this.grid) {
                        this.grid.trigger("backgrid:refresh");
                    }
                });
                this.listenTo(this, "grid:refresh:update", function() {
                    if (this.grid) {
                        this.grid.trigger("backgrid:refresh");
                        if (this.grid.collection) { this.grid.collection.trigger("backgrid:colgroup:updated"); }
                    }
                });

                // It will show tool tip when td has ellipsis  Property
                this.listenTo(this.collection, "backgrid:refresh", function() {
                    /*this.$('.table td').bind('mouseenter', function() {
                        var $this = $(this);
                        if (this.offsetWidth < this.scrollWidth && !$this.attr('title')) {
                            $this.attr('title', $this.text());
                        }
                    });*/
                }, this);

            },

            /** on render callback */
            onRender: function() {
                this.renderTable();
                if (this.includePagination) {
                    this.renderPagination();
                }
                if (this.includeAtlasPagination) {
                    this.renderAtlasPagination();
                }
                if (this.includeFilter) {
                    this.renderFilter();
                }
                if (this.includeFooterRecords) {
                    this.renderFooterRecords(this.collection.state);
                }
                if (this.includeColumnManager) {
                    this.renderColumnManager();
                }
                var pageSizeEl = null;
                if (this.includePageSize) {
                    pageSizeEl = this.ui.selectPageSize;
                } else if (this.includeAtlasPageSize) {
                    pageSizeEl = this.ui.showPage;
                }
                if (pageSizeEl) {
                    pageSizeEl.select2({
                        data: _.sortBy(_.union([25, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500], [this.collection.state.pageSize])),
                        tags: true,
                        dropdownCssClass: "number-input",
                        multiple: false
                    });
                    var val = this.collection.state.pageSize;
                    if (this.value && this.value.pageLimit) {
                        val = this.limit;
                    }
                    pageSizeEl.val(val).trigger('change', { "skipViewChange": true });
                }

            },
            /**
             * show table
             */
            renderTable: function() {
                var that = this;
                this.grid = new Backgrid.Grid(this.gridOpts).on('backgrid:rendered', function() {
                    that.trigger('backgrid:manual:rendered', this)
                });
                if (this.showDefaultTableSorted) {
                    this.grid.render();
                    if (this.collection.fullCollection.length > 1 || this.isApiSorting) {
                        this.grid.sort(this.sortOpts.sortColumn, this.sortOpts.sortDirection);
                    }
                    this.rTableList.show(this.grid);
                } else {
                    this.rTableList.show(this.grid);
                }
            },
            onShow: function() {
                if (this.includeSizeAbleColumns) {
                    this.renderSizeAbleColumns();
                }
                if (this.includeOrderAbleColumns) {
                    this.renderOrderAbleColumns();
                }
            },
            /**
             * show pagination buttons(first, last, next, prev and numbers)
             */
            renderPagination: function() {
                var options = _.extend({
                    collection: this.collection,
                    controls: this.controlOpts
                }, this.paginatorOpts);

                // TODO - Debug this part
                if (this.rPagination) {
                    this.rPagination.show(new Backgrid.Extension.Paginator(options));
                } else if (this.regions.rPagination) {
                    this.$('div[data-id="r_pagination"]').show(new Backgrid.Extension.Paginator(options));
                    this.showHideGoToPage();
                }
            },

            /**
             * Optional merged approximate total (e.g. schema tab across relations).
             * When set (number or function), footer and next/prev bounds use it like React
             * TablePagination client mode.
             */
            resolveAtlasApproximateTotal: function() {
                var v = this.atlasApproximateDatasetTotal;
                if (_.isFunction(v)) {
                    var n = v.call(this);
                    return (_.isFinite(n) && n >= 0) ? n : null;
                }
                if (typeof v === 'number' && _.isFinite(v) && v >= 0) {
                    return v;
                }
                return null;
            },

            getAtlasPaginationCeiling: function() {
                var approx = this.resolveAtlasApproximateTotal();
                if (approx !== null) {
                    return approx;
                }
                return this.collection.fullCollection
                    ? this.collection.fullCollection.length
                    : this.collection.length;
            },

            /**
             * While relationship/chunk fetch or grid rebuild is in progress, disable
             * Next/Prev and Page Limit (schema tab double-click / stale nav).
             * @param {boolean} busy
             * @param {'next'|'prev'|'both'} [navHint] Which control triggered load — drives spinner
             *   placement (Classic schema: user sees feedback like basic search).
             */
            setAtlasPaginationBusy: function(busy, navHint) {
                this._atlasPaginationBusy = !!busy;
                if (busy) {
                    this._atlasPaginationBusyHint = navHint === 'next' || navHint === 'prev'
                        ? navHint
                        : 'both';
                } else {
                    this._atlasPaginationBusyHint = null;
                }
                if (!this.includeAtlasPagination || !this.ui || !this.ui.nextData || !this.ui.nextData.length) {
                    return;
                }
                this.renderAtlasPagination(this._lastRenderAtlasPaginationOptions || {});
            },

            /**
             * After renderAtlasPagination sets disabled props, show spinner + busy chrome so
             * the user sees work in progress (disabled buttons do not get :hover cursor).
             */
            _syncAtlasPaginationBusyVisuals: function() {
                if (!this.includeAtlasPagination || !this.ui || !this.ui.nextData || !this.ui.nextData.length) {
                    return;
                }
                var nextBtn = this.ui.nextData;
                var prevBtn = this.ui.previousData;
                var ul = nextBtn.closest('ul');
                var spinHtml = '<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>';
                var prevHtml = '<i class="fa fa-angle-left" aria-hidden="true"></i>';
                var nextHtml = '<i class="fa fa-angle-right" aria-hidden="true"></i>';
                var loadingTitle = 'Loading...';
                if (this._atlasPaginationBusy) {
                    ul.addClass('atlas-pagination-busy');
                    ul.attr('aria-busy', 'true');
                    var hint = this._atlasPaginationBusyHint || 'both';
                    if (hint === 'next') {
                        nextBtn.html(spinHtml);
                        nextBtn.attr('title', loadingTitle);
                        if (prevBtn && prevBtn.length) {
                            prevBtn.html(prevHtml);
                            prevBtn.attr('title', 'Previous');
                        }
                    } else if (hint === 'prev') {
                        if (prevBtn && prevBtn.length) {
                            prevBtn.html(spinHtml);
                            prevBtn.attr('title', loadingTitle);
                        }
                        nextBtn.html(nextHtml);
                        nextBtn.attr('title', 'Next');
                    } else {
                        nextBtn.html(spinHtml);
                        nextBtn.attr('title', loadingTitle);
                        if (prevBtn && prevBtn.length) {
                            prevBtn.html(spinHtml);
                            prevBtn.attr('title', loadingTitle);
                        }
                    }
                } else {
                    ul.removeClass('atlas-pagination-busy');
                    ul.attr('aria-busy', 'false');
                    nextBtn.html(nextHtml);
                    nextBtn.attr('title', 'Next');
                    if (prevBtn && prevBtn.length) {
                        prevBtn.html(prevHtml);
                        prevBtn.attr('title', 'Previous');
                    }
                }
            },

            renderAtlasPagination: function(options) {
                this._lastRenderAtlasPaginationOptions = options || {};
                /*
                 * Schema tab: Next updates collection.queryParams.offset before fetchCollection;
                 * Pageable state can briefly leave this.offset stale so footer shows 1–100.
                 */
                if (this.clientAtlasPagination && this.collection && this.collection.queryParams) {
                    var qo = parseInt(this.collection.queryParams.offset, 10);
                    if (_.isFinite(qo) && qo >= 0) {
                        this.offset = qo;
                    }
                    var ql = parseInt(this.collection.queryParams.limit, 10);
                    if (_.isFinite(ql) && ql > 0) {
                        this.limit = ql;
                    }
                    /*
                     * Page Limit dropdown is authoritative. Stale queryParams.limit (e.g. after
                     * relationship chunk size vs UI limit) made prev subtract the wrong step and
                     * renderAtlasPagination's old "previous" branch used pageTo - limit with a
                     * mismatched limit — wrong page number (e.g. 10 -> 7) and range (31-35).
                     */
                    if (this.ui && this.ui.showPage && this.ui.showPage.length) {
                        var lp = parseInt(this.ui.showPage.val(), 10);
                        if (_.isFinite(lp) && lp > 0) {
                            this.limit = lp;
                            this.collection.queryParams.limit = lp;
                        }
                    }
                }
                var isFirstPage = this.offset === 0,
                    dataLength = this.collection.length,
                    goToPage = (this.ui.gotoPage && this.ui.gotoPage.length) ? this.ui.gotoPage.val() : '',
                    ceiling = this.getAtlasPaginationCeiling(),
                    approxTotal = this.resolveAtlasApproximateTotal();

                /*Next button check.
                It's outside of Previous button else condition
                because when user comes from 2 page to 1 page than we need to check next button.*/
                if (this.clientAtlasPagination && approxTotal !== null) {
                    this.ui.nextData.attr('disabled', (this.offset + this.limit) >= ceiling);
                } else if (dataLength < this.limit) {
                    this.ui.nextData.attr('disabled', true);
                } else {
                    this.ui.nextData.attr('disabled', false);
                }

                if (isFirstPage && (!dataLength || dataLength < this.limit)) {
                    this.ui.paginationDiv.hide();
                } else {
                    this.ui.paginationDiv.show();
                }

                // Previous button check.s
                if (isFirstPage) {
                    this.ui.previousData.attr('disabled', true);
                    this.pageFrom = ceiling === 0 ? 0 : 1;
                    this.pageTo = Math.min(this.limit, ceiling);
                } else {
                    this.ui.previousData.attr('disabled', false);
                }

                if (!isFirstPage) {
                    /* Next/Prev both: offset + limit are authoritative (set before fetchCollection). */
                    this.pageFrom = this.offset + 1;
                    this.pageTo = Math.min(this.offset + this.limit, ceiling);
                }
                if (this.isApiSorting && !this.pageTo && !this.pageFrom) {
                    this.limit = this.count;
                    this.pageTo = (this.offset + this.limit);
                    this.pageFrom = this.offset + 1;
                }
                var totalRecords = ceiling;
                var displayTo = Math.min(this.pageTo, totalRecords);
                var displayFrom = totalRecords === 0 ? 0 : Math.min(this.pageFrom, displayTo);
                var totalLabel = (typeof totalRecords === 'number' && totalRecords.toLocaleString)
                    ? totalRecords.toLocaleString('en-US')
                    : totalRecords;
                this.ui.pageRecordText.html("Showing  <u>" + totalLabel + " records</u> From " + displayFrom + " - " + displayTo);
                this.activePage = (this.limit > 0)
                    ? (Math.floor(this.offset / this.limit) + 1)
                    : 1;
                this.ui.activePage.attr('title', "Page " + this.activePage);
                this.ui.activePage.text(this.activePage);
                this.ui.showPage.val(this.limit).trigger('change', { "skipViewChange": true });

                if (!dataLength && this.offset >= this.limit && ((options && options.next) || goToPage) && (options && !options.fromUrl)) {
                    /* User clicks on next button and server returns
                    empty response then disabled the next button without rendering table*/

                    var pageNumber = this.activePage;
                    if (goToPage) {
                        pageNumber = goToPage;
                        this.offset = (this.activePage - 1) * this.limit;
                    } else {
                        this.ui.nextData.attr('disabled', true);
                    }
                    if (this.value) {
                        this.value.pageOffset = this.offset;
                        if (this.triggerUrl) {
                            this.triggerUrl();
                        }
                    }
                    Utils.notifyInfo({
                        html: true,
                        content: Messages.search.noRecordForPage + '<b>' + Utils.getNumberSuffix({ number: pageNumber, sup: true }) + '</b> page'
                    });
                    if (this._atlasPaginationBusy) {
                        this.ui.nextData.prop('disabled', true);
                        this.ui.previousData.prop('disabled', true);
                        if (this.ui.showPage && this.ui.showPage.length) {
                            this.ui.showPage.prop('disabled', true);
                        }
                    }
                    this._syncAtlasPaginationBusyVisuals();
                    return;
                }
                if (this._atlasPaginationBusy) {
                    this.ui.nextData.prop('disabled', true);
                    this.ui.previousData.prop('disabled', true);
                    if (this.ui.showPage && this.ui.showPage.length) {
                        this.ui.showPage.prop('disabled', true);
                    }
                } else if (this.ui.showPage && this.ui.showPage.length) {
                    this.ui.showPage.prop('disabled', false);
                }
                this._syncAtlasPaginationBusyVisuals();
            },

            /**
             * show/hide pagination buttons of the grid
             */
            showHidePager: function() {

                if (!this.includePagination) {
                    return;
                }

                if (this.collection.state && this.collection.state.totalRecords > this.collection.state.pageSize) {
                    this.$('div[data-id="r_pagination"]').show();
                } else {
                    this.$('div[data-id="r_pagination"]').hide();
                }
            },

            showHideGoToPage: function() {
                if (this.collection.state.pageSize > this.collection.fullCollection.length) {
                    this.ui.paginationDiv.hide();
                } else {
                    this.ui.paginationDiv.show();
                }
            },

            /**
             * show/hide filter of the grid
             */
            renderFilter: function() {
                this.rFilter.show(new Backgrid.Extension.ServerSideFilter({
                    collection: this.collection,
                    name: ['name'],
                    placeholder: 'plcHldr.searchByResourcePath',
                    wait: 150
                }));

                setTimeout(function() {
                    that.$('table').colResizable({ liveDrag: true });
                }, 0);
            },

            /**
             * show/hide footer details of the list/collection shown in the grid
             */
            renderFooterRecords: function(collectionState) {
                var collState = collectionState;
                var totalRecords = collState.totalRecords || 0;
                var pageStartIndex = totalRecords ? (collState.currentPage * collState.pageSize) : 0;
                var pageEndIndex = pageStartIndex + this.collection.length;
                this.$('[data-id="r_footerRecords"]').html('<h5>Showing ' + (totalRecords ? pageStartIndex + 1 : (this.collection.length === 0) ? 0 : 1) + ' - ' + pageEndIndex + '</h5>');
                return this;
            },
            /**
             * ColumnManager for the table
             */
            renderColumnManager: function() {
                if (!this.columns) {
                    return;
                }
                var that = this,
                    $el = this.columnOpts.el || this.$("[data-id='control']"),
                    colManager = new Backgrid.Extension.ColumnManager(this.columns, this.columnOpts.opts),
                    // Add control
                    colVisibilityControl = new Backgrid.Extension.ColumnManagerVisibilityControl(_.extend({
                        columnManager: colManager,
                    }, this.columnOpts.visibilityControlOpts));
                if (!$el.jquery) {
                    $el = $($el)
                }
                if (this.columnOpts.el) {
                    $el.html(colVisibilityControl.render().el);
                } else {
                    $el.append(colVisibilityControl.render().el);
                }

                colManager.on("state-changed", function(state) {
                    that.collection.trigger("state-changed", state);
                });
                colManager.on("state-saved", function() {
                    that.collection.trigger("state-changed");
                });
            },
            renderSizeAbleColumns: function() {
                // Add sizeable columns
                var that = this,
                    sizeAbleCol = new Backgrid.Extension.SizeAbleColumns({
                        collection: this.collection,
                        columns: this.columns,
                        grid: this.getGridObj()
                    });
                this.$('thead').before(sizeAbleCol.render().el);

                // Add resize handlers
                var sizeHandler = new Backgrid.Extension.SizeAbleColumnsHandlers({
                    sizeAbleColumns: sizeAbleCol,
                    // grid: this.getGridObj(),
                    saveModelWidth: true
                });
                this.$('thead').before(sizeHandler.render().el);

                // Listen to resize events
                this.columns.on('resize', function(columnModel, newWidth, oldWidth) {
                });
            },

            renderOrderAbleColumns: function() {
                // Add orderable columns
                var sizeAbleCol = new Backgrid.Extension.SizeAbleColumns({
                    collection: this.collection,
                    grid: this.getGridObj(),
                    columns: this.columns
                });
                this.$('thead').before(sizeAbleCol.render().el);
                var orderHandler = new Backgrid.Extension.OrderableColumns({
                    grid: this.getGridObj(),
                    sizeAbleColumns: sizeAbleCol
                });
                this.$('thead').before(orderHandler.render().el);
            },

            /** on close */
            onClose: function() {},

            /**
             * get the Backgrid object
             * @return {null}
             */
            getGridObj: function() {
                if (this.rTableList.currentView) {
                    return this.rTableList.currentView;
                }
                return null;
            },

            /**
             * handle change event on page size select box
             * @param  {Object} e event
             */
            onPageSizeChange: function(e, options) {
                if (!options || !options.skipViewChange) {
                    var pagesize = $(e.currentTarget).val();
                    if (pagesize == 0) {
                        this.ui.selectPageSize.data('select2').$container.addClass('has-error');
                        return;
                    } else {
                        this.ui.selectPageSize.data('select2').$container.removeClass('has-error');
                    }
                    this.collection.state.pageSize = parseInt(pagesize, 10);
                    this.collection.state.currentPage = this.collection.state.firstPage;
                    this.showHideGoToPage();
                    if (this.collection.mode == "client") {
                        this.collection.fullCollection.reset(this.collection.fullCollection.toJSON());
                    } else {
                        this.collection.fetch({
                            sort: false,
                            reset: true,
                            cache: false
                        });
                    }
                }
            },
            /**
                atlasNextBtn
            **/
            onClicknextData: function() {
                if (this._atlasPaginationBusy) {
                    return;
                }
                if (this.clientAtlasPagination && typeof this.atlasShowLoaderBeforeFetch === 'function') {
                    this.atlasShowLoaderBeforeFetch();
                }
                if (this.clientAtlasPagination && this.ui && this.ui.showPage && this.ui.showPage.length) {
                    var ln = parseInt(this.ui.showPage.val(), 10);
                    if (_.isFinite(ln) && ln > 0) {
                        this.limit = ln;
                    }
                }
                this.offset = this.offset + this.limit;
                _.extend(this.collection.queryParams, {
                    offset: this.offset,
                    limit: this.limit
                });
                if (this.value) {
                    this.value.pageOffset = this.offset;
                    if (this.triggerUrl) {
                        this.triggerUrl();
                    }
                }
                if (this.fetchCollection) {
                    this.fetchCollection({
                        next: true
                    });
                }
            },
            /**
                atlasPrevBtn
            **/
            onClickpreviousData: function() {
                if (this._atlasPaginationBusy) {
                    return;
                }
                if (this.clientAtlasPagination && typeof this.atlasShowLoaderBeforeFetch === 'function') {
                    this.atlasShowLoaderBeforeFetch();
                }
                if (this.clientAtlasPagination && this.ui && this.ui.showPage && this.ui.showPage.length) {
                    var lp = parseInt(this.ui.showPage.val(), 10);
                    if (_.isFinite(lp) && lp > 0) {
                        this.limit = lp;
                    }
                }
                this.offset = this.offset - this.limit;
                if (this.offset <= -1) {
                    this.offset = 0;
                }
                _.extend(this.collection.queryParams, {
                    offset: this.offset,
                    limit: this.limit
                });
                if (this.value) {
                    this.value.pageOffset = this.offset;
                    if (this.triggerUrl) {
                        this.triggerUrl();
                    }
                }
                if (this.fetchCollection) {
                    this.fetchCollection({
                        previous: true
                    });
                }
            },
            /**
                atlasPageLimit
            **/
            changePageLimit: function(e, obj) {
                if (!obj || (obj && !obj.skipViewChange)) {
                    if (this._atlasPaginationBusy) {
                        return;
                    }
                    var limit = parseInt(this.ui.showPage.val());
                    if (limit == 0) {
                        this.ui.showPage.data('select2').$container.addClass('has-error');
                        return;
                    } else {
                        this.ui.showPage.data('select2').$container.removeClass('has-error');
                    }
                    this.limit = limit;
                    this.offset = 0;
                    if (this.value) {
                        this.value.pageLimit = this.limit;
                        this.value.pageOffset = this.offset;
                        if (this.triggerUrl) {
                            this.triggerUrl();
                        }
                    }
                    _.extend(this.collection.queryParams, { limit: this.limit, offset: this.offset });
                    /* Schema tab: Classic UI re-sorts cached rows by position when limit changes. */
                    this.fetchCollection({ fromPageLimitChange: true });
                }
            },
            /**
                atlasGotoBtn & Local Goto Btn
            **/
            gotoPagebtn: function(e) {
                var that = this;
                var goToPage = parseInt(this.ui.gotoPage.val());
                if (!_.isNaN(goToPage) && ((goToPage == 0) || (this.collection.state.totalPages < goToPage))) {
                    Utils.notifyInfo({
                        content: Messages.search.noRecordForPage + "page " + goToPage
                    });
                    this.ui.gotoPage.val('')
                    that.ui.gotoPagebtn.attr('disabled', true);
                    return;
                }
                if (!(_.isNaN(goToPage) || goToPage <= -1)) {
                    if (this.collection.mode == "client") {
                        return this.collection.getPage((goToPage - 1), {
                            reset: true
                        });
                    } else {
                        this.offset = (goToPage - 1) * this.limit;
                        if (this.offset <= -1) {
                            this.offset = 0;
                        }
                        _.extend(this.collection.queryParams, { limit: this.limit, offset: this.offset });
                        if (this.offset == (this.pageFrom - 1)) {
                            Utils.notifyInfo({
                                content: Messages.search.onSamePage
                            });
                        } else {
                            if (this.value) {
                                this.value.pageOffset = this.offset;
                                if (this.triggerUrl) {
                                    this.triggerUrl();
                                }
                            }
                            // this.offset is updated in gotoPagebtn function so use next button calculation.
                            if (this.fetchCollection) {
                                this.fetchCollection({ 'next': true });
                            }
                        }
                    }
                }
            }
        });

    return FSTableLayout;
});