/**
 * @author Nadim Basalamah <dimbslmh@gmail.com>
 * @version: v1.0.0
 * https://github.com/dimbslmh/bootstrap-table/tree/master/src/extensions/multiple-sort/bootstrap-table-multiple-sort.js
 */

(function($) {
    'use strict';

    var isSingleSort = false;

    var sort_order = {
            asc: 'Ascending',
            desc: 'Descending'
        },
        arrowAsc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ' +
        '0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBd' +
        'qEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVo' +
        'AADeemwtPcZI2wAAAABJRU5ErkJggg==',
        arrowDesc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWj' +
        'YBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJ' +
        'zcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ';

    var showSortModal = function(that) {
        if (!$("#sortModal").hasClass("modal")) {
            var sModal = '  <div class="modal fade" id="sortModal" tabindex="-1" role="dialog" aria-labelledby="sortModalLabel" aria-hidden="true">';
            sModal += '         <div class="modal-dialog">';
            sModal += '             <div class="modal-content">';
            sModal += '                 <div class="modal-header">';
            sModal += '                     <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
            sModal += '                     <h4 class="modal-title" id="sortModalLabel">' + that.options.formatMultipleSort() + '</h4>';
            sModal += '                 </div>';
            sModal += '                 <div class="modal-body">';
            sModal += '                     <div class="bootstrap-table">';
            sModal += '                         <div class="fixed-table-toolbar">';
            sModal += '                             <div class="bars">';
            sModal += '                                 <div id="toolbar">';
            sModal += '                                     <button id="add" type="button" class="btn btn-default"><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.plus + '"></i> ' + that.options.formatAddLevel() + '</button>';
            sModal += '                                     <button id="delete" type="button" class="btn btn-default" disabled><i class="' + that.options.iconsPrefix + ' ' + that.options.icons.minus + '"></i> ' + that.options.formatDeleteLevel() + '</button>';
            sModal += '                                 </div>';
            sModal += '                             </div>';
            sModal += '                         </div>';
            sModal += '                         <div class="fixed-table-container">';
            sModal += '                             <table id="multi-sort" class="table">';
            sModal += '                                 <thead>';
            sModal += '                                     <tr>';
            sModal += '                                         <th></th>';
            sModal += '                                         <th><div class="th-inner">' + that.options.formatColumn() + '</div></th>';
            sModal += '                                         <th><div class="th-inner">' + that.options.formatOrder() + '</div></th>';
            sModal += '                                     </tr>';
            sModal += '                                 </thead>';
            sModal += '                                 <tbody></tbody>';
            sModal += '                             </table>';
            sModal += '                         </div>';
            sModal += '                     </div>';
            sModal += '                 </div>';
            sModal += '                 <div class="modal-footer">';
            sModal += '                     <button type="button" class="btn btn-default" data-dismiss="modal">' + that.options.formatCancel() + '</button>';
            sModal += '                     <button type="button" class="btn btn-primary">' + that.options.formatSort() + '</button>';
            sModal += '                 </div>';
            sModal += '             </div>';
            sModal += '         </div>';
            sModal += '     </div>';

            $("body").append($(sModal));

            var $sortModal = $('#sortModal'),
                $rows = $sortModal.find("tbody > tr");

            $sortModal.off('click', '#add').on('click', '#add', function() {
                var total = $sortModal.find('.multi-sort-name:first option').length,
                    current = $sortModal.find('tbody tr').length;

                if (current < total) {
                    current++;
                    that.addLevel();
                    that.setButtonStates();
                }
            });

            $sortModal.off('click', '#delete').on('click', '#delete', function() {
                var total = $sortModal.find('.multi-sort-name:first option').length,
                    current = $sortModal.find('tbody tr').length;

                if (current > 1 && current <= total) {
                    current--;
                    $sortModal.find('tbody tr:last').remove();
                    that.setButtonStates();
                }
            });

            $sortModal.off('click', '.btn-primary').on('click', '.btn-primary', function() {
                var $rows = $sortModal.find("tbody > tr"),
                    $alert = $sortModal.find('div.alert'),
                    fields = [],
                    results = [];


                that.options.sortPriority = $.map($rows, function(row) {
                    var $row = $(row),
                        name = $row.find('.multi-sort-name').val(),
                        order = $row.find('.multi-sort-order').val();

                    fields.push(name);

                    return {
                        sortName: name,
                        sortOrder: order
                    };
                });

                var sorted_fields = fields.sort();

                for (var i = 0; i < fields.length - 1; i++) {
                    if (sorted_fields[i + 1] == sorted_fields[i]) {
                        results.push(sorted_fields[i]);
                    }
                }

                if (results.length > 0) {
                    if ($alert.length === 0) {
                        $alert = '<div class="alert alert-danger" role="alert"><strong>' + that.options.formatDuplicateAlertTitle() + '</strong> ' + that.options.formatDuplicateAlertDescription() + '</div>';
                        $($alert).insertBefore($sortModal.find('.bars'));
                    }
                } else {
                    if ($alert.length === 1) {
                        $($alert).remove();
                    }

                    that.options.sortName = "";
                    that.onMultipleSort();
                    $sortModal.modal('hide');
                }
            });

            if (that.options.sortPriority === null) {
                if (that.options.sortName) {
                    that.options.sortPriority = [{
                        sortName: that.options.sortName,
                        sortOrder: that.options.sortOrder
                    }];
                }
            }
            
            if (that.options.sortPriority !== null) {
                if ($rows.length < that.options.sortPriority.length && typeof that.options.sortPriority === 'object') {
                    for (var i = 0; i < that.options.sortPriority.length; i++) {
                        that.addLevel(i, that.options.sortPriority[i]);
                    }
                }
            } else {
                that.addLevel(0);
            }

            that.setButtonStates();
        }
    };

    $.extend($.fn.bootstrapTable.defaults, {
        showMultiSort: false,
        sortPriority: null,
        onMultipleSort: function() {
            return false;
        }
    });

    $.extend($.fn.bootstrapTable.defaults.icons, {
        sort: 'glyphicon-sort',
        plus: 'glyphicon-plus',
        minus: 'glyphicon-minus'
    });

    $.extend($.fn.bootstrapTable.Constructor.EVENTS, {
        'multiple-sort.bs.table': 'onMultipleSort'
    });

    $.extend($.fn.bootstrapTable.locales, {
        formatMultipleSort: function() {
            return 'Multiple Sort';
        },
        formatAddLevel: function() {
            return "Add Level";
        },
        formatDeleteLevel: function() {
            return "Delete Level";
        },
        formatColumn: function() {
            return "Column";
        },
        formatOrder: function() {
            return "Order";
        },
        formatSortBy: function() {
            return "Sort by";
        },
        formatThenBy: function() {
            return "Then by";
        },
        formatSort: function() {
            return "Sort";
        },
        formatCancel: function() {
            return "Cancel";
        },
        formatDuplicateAlertTitle: function() {
            return "Duplicate(s) detected!";
        },
        formatDuplicateAlertDescription: function() {
            return "Please remove or change any duplicate column.";
        }
    });

    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales);

    var BootstrapTable = $.fn.bootstrapTable.Constructor,
        _initToolbar = BootstrapTable.prototype.initToolbar;

    BootstrapTable.prototype.initToolbar = function() {
        this.showToolbar = true;
        var that = this;

        _initToolbar.apply(this, Array.prototype.slice.apply(arguments));

        if (this.options.showMultiSort) {
            var $btnGroup = this.$toolbar.find('>.btn-group'),
                $multiSortBtn = $btnGroup.find('div.multi-sort');

            if (!$multiSortBtn.length) {
                $multiSortBtn = '  <button class="multi-sort btn btn-default' + (this.options.iconSize === undefined ? '' : ' btn-' + this.options.iconSize) + '" type="button" data-toggle="modal" data-target="#sortModal" title="' + this.options.formatMultipleSort() + '">';
                $multiSortBtn += '     <i class="' + this.options.iconsPrefix + ' ' + this.options.icons.sort + '"></i>';
                $multiSortBtn += '</button>';

                $btnGroup.append($multiSortBtn);

                showSortModal(that);
            }

            this.$el.one('sort.bs.table', function() {
                isSingleSort = true;
            });

            this.$el.on('multiple-sort.bs.table', function() {
                isSingleSort = false;
            });

            this.$el.on('load-success.bs.table', function() {
                if (!isSingleSort && that.options.sortPriority !== null && typeof that.options.sortPriority === 'object') {
                    that.onMultipleSort();
                }
            });

            this.$el.on('column-switch.bs.table', function() {
                that.options.sortPriority = null;
                $('#sortModal').remove();
                showSortModal(that);
            });
        }
    };

    BootstrapTable.prototype.onMultipleSort = function() {
        var that = this;
        
        var cmp = function(x, y) {
            return x > y ? 1 : x < y ? -1 : 0;
        };

        var arrayCmp = function(a, b) {
            var arr1 = [],
                arr2 = [];

            for (var i = 0; i < that.options.sortPriority.length; i++) {
                var order = that.options.sortPriority[i].sortOrder === 'desc' ? -1 : 1,
                    aa = a[that.options.sortPriority[i].sortName],
                    bb = b[that.options.sortPriority[i].sortName];

                if (aa === undefined || aa === null) {
                    aa = '';
                }
                if (bb === undefined || bb === null) {
                    bb = '';
                }
                if ($.isNumeric(aa) && $.isNumeric(bb)) {
                    aa = parseFloat(aa);
                    bb = parseFloat(bb);
                }
                if (typeof aa !== 'string') {
                    aa = aa.toString();
                }

                arr1.push(
                    order * cmp(aa, bb));
                arr2.push(
                    order * cmp(bb, aa));
            }

            return cmp(arr1, arr2);
        };

        this.data.sort(function(a, b) {
            return arrayCmp(a, b);
        });

        this.initBody();
        this.assignSortableArrows();
        this.trigger('multiple-sort');
    };

    BootstrapTable.prototype.addLevel = function(index, sortPriority) {
        var $sortModal = $("#sortModal"),
            text = index === 0 ? this.options.formatSortBy() : this.options.formatThenBy();

        $sortModal.find('tbody')
            .append($('<tr>')
                .append($('<td>').text(text))
                .append($('<td>').append($('<select class="form-control multi-sort-name">')))
                .append($('<td>').append($('<select class="form-control multi-sort-order">')))
            );

        var $multiSortName = $sortModal.find('.multi-sort-name').last(),
            $multiSortOrder = $sortModal.find('.multi-sort-order').last();

        this.options.columns.forEach(function(column) {
            if (column.sortable === false || column.visible === false) {
                return true;
            }
            $multiSortName.append('<option value="' + column.field + '">' + column.title + '</option>');
        });

        $.each(sort_order, function(value, order) {
            $multiSortOrder.append('<option value="' + value + '">' + order + '</option>');
        });

        if (sortPriority !== undefined) {
            $multiSortName.find('option[value="' + sortPriority.sortName + '"]').attr("selected", true);
            $multiSortOrder.find('option[value="' + sortPriority.sortOrder + '"]').attr("selected", true);
        }
    };

    BootstrapTable.prototype.assignSortableArrows = function() {
        var that = this,
            headers = that.$header.find('th');

        for (var i = 0; i < headers.length; i++) {
            for (var c = 0; c < that.options.sortPriority.length; c++) {
                if ($(headers[i]).data('field') === that.options.sortPriority[c].sortName) {
                    $(headers[i]).find('.sortable').css('background-image', 'url(' + (that.options.sortPriority[c].sortOrder === 'desc' ? arrowDesc : arrowAsc) + ')');
                }
            }
        }
    };

    BootstrapTable.prototype.setButtonStates = function() {
        var $sortModal = $('#sortModal'),
            total = $sortModal.find('.multi-sort-name:first option').length,
            current = $sortModal.find('tbody tr').length;

        if (current == total) {
            $sortModal.find('#add').attr('disabled', 'disabled');
        }
        if (current > 1) {
            $sortModal.find('#delete').removeAttr('disabled');
        }
        if (current < total) {
            $sortModal.find('#add').removeAttr('disabled');
        }
        if (current == 1) {
            $sortModal.find('#delete').attr('disabled', 'disabled');
        }
    };
})(jQuery);
