/*globals define*/
/*jslint nomen:true*/

/**
 * @class jQuery.ui.uiDatatable
 * @author Copyright 2006-2013, epages GmbH, All Rights Reserved
 *
 * The datatable widget adds to a simple table-tag dynamically content.
 *
 * ### Example
 * HTML:
 *
 *     <table class="ep-table"></table>
 *
 * JavaScript:
 *
 *     $('.ep-datatable').uiDatatable({
 *         action: 'JSONSearchProductsToInsert'
 *     });
 *
 * @uses jQuery.ui.widget
 * @uses ep
 *
 * @chainable
 * @return {Object} ep
 */

define('ep/ui/datatable', [
    'jquery/ui/widget',
    'ep/ui/input',
    '$tmpl!ep/ui/datatable',
    '$tmpl!ep/ui/datatable-unity',
    '$dict!ep/dict'
], function ($, ep, tableTemplate, tableTemplateUnity, dict) {
    'use strict';

    $.widget('ui.uiDatatable', {

        /**
         * Options to be passed to the widgt on initialzation
         *
         * @cfg {Object} options
         * @cfg {String} options.action ViewAction which is used to get data for table
         * @cfg {String} [options.searchString=''] String to search for
         * @cfg {Number} [options.pageSize=10] Number of table entries per page
         * @cfg {Number} [options.pages=5] Number of pages which should be loaded via one request
         * @cfg {Number} [options.pagerSize=5] Number of pages which should be displayed in the pager
         */
        options: {
            action: undefined,
            searchString: undefined,
            pageSize: 10,
            pages: 5,
            pagerSize: 5
        },

        /*
         * Set classes and call method the render table content
         *
         * @since 6.17.0
         * @private
         */
        _create: function () {
            var self = this,
                o = self.options;

            // called from unity environment?
            self.unity = (ep.config.unity!==undefined && ep.config.unity===true) ? true : false;
            // use correct template
            tableTemplate = self.unity ? tableTemplateUnity : tableTemplate;

            self.element.addClass('ep-uiDatatable ContentList RowSelection');
            self.data = {};
            self._loadTableData(1);
        },

        /*
         * Loads table content with the given data and calls method to render this content.
         * Already loaded data is cached.
         *
         * @since 6.17.0
         * @private
         * @param  {Number} page The value of the page which should be displayed
         */
        _loadTableData: function (page) {
            var self = this,
                o = self.options,
                sortOrderNotChanged = self.data.orderBy === self.orderBy && self.data.orderDesc === self.orderDesc,
                loader = $('<span class="data-loading" />');

            if (self.data.currentPage !== page || !sortOrderNotChanged) {
                self.data.currentPage = page;

                // use cached data
                if (self.data.tableContent && self.data.tableContent[page] && sortOrderNotChanged) {
                    self._renderTable();
                    // get new data
                } else {
                    self.element.parent().prepend(loader);
                    ep.ajax({
                        type: 'POST',
                        dataType: 'json',
                        data: $.extend({
                            'ObjectID': ep.config.siteId,
                            'ViewAction': o.action,
                            'WildSearchString': o.searchString,
                            'pageEntries': o.pageSize,
                            'pages': o.pages,
                            'ParentObjectID': o.parentObjectId || undefined,
                            'currentPage': page,
                            'orderBy': self.orderBy || undefined,
                            'orderDesc': self.orderDesc || undefined
                        }, o.otherParameters)
                    }).done(function (data) {
                        if (self.data.tableContent && sortOrderNotChanged) {
                            $.extend(self.data.tableContent, data.tableContent);
                        } else {
                            self.data = data;

                            $.extend(self.data, {
                                currentPage: page,
                                iconRoot: ep.config.iconsRoot
                            });
                        }

                        if (self.data.isHighlighted) {
                            self.element.addClass('highlight');
                        }

                        // set default sorting options
                        self.orderBy = self.data.orderBy;
                        self.orderDesc = self.data.orderDesc;

                        self._renderTable();
                        loader.remove();
                        self.element.trigger('datatablerendered', data);
                    });
                }
            }
        },

        /*
         * Renders table with the given data and adds event listener for sorting, check all entries and the pager.
         *
         * @since 6.17.0
         * @private
         */
        _renderTable: function () {
            var self = this,
                checkboxes;

            // tell the datatable in which context it is rendered (icon for variation products, etc...)
            $.extend(self.data, {
                context: self.options.context
            });

            // render table with given data
            self.renderedTable = tableTemplate(self.data)
                .dictParse(dict, true)
                .find('td')
                    .dictParseAttr(dict, 'title')
                    .end()
                .find('img')
                    .dictParseAttr(dict, 'title')
                    .end();

            $.extend(self, $.tmplItem(self.renderedTable).elements);

            self.element
                .empty()
                .html(self.renderedTable);

            self.element.find('input').uiInput();
            self._setPager();

            // Get the currently cklicked checkbox by comparing all object ids of the page with the checkbox values
            self.element.find('tbody input').on('click', function (event) {
                /**
                 * @event itemselected Fired when a checkbox is clicked. Contains all data of the selected item
                 */
                $(this).trigger('selectionstatechanged', self._getItemData(event.target.value));
            });

            // select all checkboxes when clicking on checkbox in table head
            checkboxes = self.element.find('thead input[type="checkbox"]');
            if (checkboxes.length) {
                checkboxes.on('click', function () {
                    var inputs = self.element.find('tbody input[name="' + $(this).attr('name') + '"]');

                    if ($(this).prop('checked')) {
                        inputs.filter(':not(:checked)').trigger('click');
                    } else {
                        inputs.filter(':checked').trigger('click');
                    }
                });
            }

            // add event listeners for sorting
            self.element.find('th[data-id]').on('click', function () {
                self.orderBy = $(this).data('id');
                self.orderDesc = $(this).data('orderdesc') === undefined ? 0 : ($(this).data('orderdesc') ? 0 : 1);
                self._loadTableData(1);
            });

            // trigger event 'changecontent' when clicking on link in table body
            self.element.find('tbody a').on('click', function (event) {
                /**
                 * @event changecontent Fired when a link in the table body was clicked. ID of element will be send.
                 */
                $(this).trigger('changecontent', self._getItemData($(this).data('id'))[0].ObjectID);
            });
        },

        /*
         * Builds the pager items corresponding on the current displayed page
         *
         * @since 6.17.0
         * @private
         */
        _setPager: function () {
            var self = this,
                o = self.options,
                offset = Math.floor(o.pagerSize / 2),
                start,
                end,
                i;

            if (self.data.lastPage > 1) {
                self.pagerItems.empty();
                self.element.find('.Opacity30').removeClass('Opacity30');

                // current page is the first one
                if (self.data.currentPage - offset <= 1) {
                    start = 1;
                    end = o.pagerSize > self.data.lastPage ? self.data.lastPage : o.pagerSize;
                    // current page is the last one
                } else if (self.data.currentPage + offset >= self.data.lastPage) {
                    start = self.data.lastPage - o.pagerSize + 1 < 1 ? 1 : self.data.lastPage - o.pagerSize + 1;
                    end = self.data.lastPage;
                    // current page is between first and last page
                } else {
                    start = self.data.currentPage - offset < 1 ? 1 : self.data.currentPage - offset;
                    end = self.data.currentPage + offset > self.data.lastPage ? self.data.lastPage : self.data.currentPage + offset;
                }

                // render pager elements
                for (i = start; i <= end; i += 1) {
                    self.pagerItems.append('<a class="paginate_button" data-page="' + i + '">' + i + '</a>');
                }

                // disable next buttons if we are on last page
                if (self.data.currentPage === self.data.lastPage) {
                    self.element.find('.ep-datatable-navigate.next').addClass('Opacity30');
                }

                // disable back button if we are on first page
                if (self.data.currentPage === 1) {
                    self.element.find('.ep-datatable-navigate.back').addClass('Opacity30');
                }

                self.element.find('.paginate_button').on('click', function () {
                    var page = $(this).data('page');

                    self._loadTableData(page);
                    self.element.trigger('pagechanged', page);
                });
            }

            self._setCurrentPage();
        },

        /*
         * Sets currently displayed page in the pager as active
         *
         * @since 6.17.0
         * @private
         */
        _setCurrentPage: function () {
            var self = this;

            self.element.find('.SelectedItem')
                .removeClass('SelectedItem');

            if (self.data.lastPage > 1) {
                self.pagerItems.find('a[data-page="' + self.data.currentPage + '"]')
                    .addClass('SelectedItem');
            }

            if (self.data.lastPage > 0) {
                self.currentPageNode.html(self.data.currentPage);
            }
        },

        /**
         * Get the data of a table item
         *
         * @since  6.17.0
         * @return {Object} Object containing all attributes of the item
         */
        _getItemData: function (objectid) {
            var self = this,
                pageElements = self.data.tableContent[self.data.currentPage],
                hasObjectId = function (item) {
                    return parseInt(item.ObjectID, 10) === parseInt(objectid, 10);
                },
                itemData = $.grep(pageElements, hasObjectId);

            // to get item data from a path element we need to check the parents of the actual element since they are not part (elems) of the actual page
            if (itemData.length === 0) {
                $.each(pageElements, function () {
                    itemData = $.grep(this.Parents, hasObjectId);
                });
            }

            return itemData;
        },

        /**
         * Removes all added elements and classes
         *
         * @since 6.17.0
         */
        destroy: function () {
            var self = this;

            self.element
                .removeClass('ep-uiDatatable ContentList RowSelection')
                .empty();
        }
    });

    return ep;
});