(function ($) {
    function SlickColumnPicker(columns, grid, options, target) {
        var $menu;
        var columnCheckboxes;
        var columnsLocalStorage = ko.toJS(ko.mapping.fromJSON(localStorage.getItem(target))());

        function getColumnsLocalStorage() {
            return ko.toJS(ko.mapping.fromJSON(localStorage.getItem(target))());
        }

        var defaults = {
            fadeSpeed: 250
        };

        function init() {
            grid.onHeaderContextMenu.subscribe(handleHeaderContextMenu);
            grid.onColumnsReordered.subscribe(updateColumnOrder);
            options = $.extend({}, defaults, options);

            $menu = $("<span class='slick-columnpicker'></span>").appendTo(document.body);

            $menu.bind("mouseleave", function (e) {
                $(this).fadeOut(options.fadeSpeed)
            });
            $menu.bind("click", updateColumn);

            var col = ko.utils.arrayMap(columnsLocalStorage, function (item) { return item.item; });

            if (!columnsLocalStorage ||
                (columnsLocalStorage &&
                    (columnsLocalStorage.length != columns.length || ko.toJSON(col) != ko.toJSON(columns)))) {
                columnsLocalStorage = [];
            }

            $.each(columns, function (i, e) {
                var name = columns[i].name;

                var coluna = ko.utils.arrayFirst(columnsLocalStorage, function (col) {
                    return col.item.name === name;
                });

                if (!coluna) {
                    columnsLocalStorage.push({ visivel: true, item: columns[i] });
                }
            });

            localStorage.setItem(target, ko.toJSON(columnsLocalStorage));

            loadColumnsStorage();
        }

        function destroy() {
            grid.onHeaderContextMenu.unsubscribe(handleHeaderContextMenu);
            grid.onColumnsReordered.unsubscribe(updateColumnOrder);
            $menu.remove();
        }

        function handleHeaderContextMenu(e, args) {
            e.preventDefault();
            $menu.empty();
            updateColumnOrder();
            columnCheckboxes = [];

            var $li, $input;
            for (var i = 0; i < columns.length; i++) {
                $li = $("<li />").appendTo($menu);
                $input = $("<input type='checkbox' />").data("column-id", columns[i].id);
                columnCheckboxes.push($input);

                if (grid.getColumnIndex(columns[i].id) != null) {
                    $input.attr("checked", "checked");
                }

                $("<label />")
                    .text(columns[i].name)
                    .prepend($input)
                    .appendTo($li);
            }

            // Alinha o menu acima do cursor do mouse
            var h = $(".slick-columnpicker").outerHeight() - 20;

            $menu
                .css("top", e.pageY - h)
                .css("left", e.pageX)
                .fadeIn(options.fadeSpeed);

            //$(".slick-columnpicker li:last-child").hide();
        }

        function updateColumnOrder() {
            // Because columns can be reordered, we have to update the `columns`
            // to reflect the new order, however we can't just take `grid.getColumns()`,
            // as it does not include columns currently hidden by the picker.
            // We create a new `columns` structure by leaving currently-hidden
            // columns in their original ordinal position and interleaving the results
            // of the current column sort.
            var current = grid.getColumns().slice(0);
            var ordered = new Array(columns.length);
            for (var i = 0; i < ordered.length; i++) {
                if (grid.getColumnIndex(columns[i].id) === undefined) {
                    // If the column doesn't return a value from getColumnIndex,
                    // it is hidden. Leave it in this position.
                    ordered[i] = columns[i];
                } else {
                    // Otherwise, grab the next visible column.
                    ordered[i] = current.shift();
                }
            }
            columns = ordered;
        }

        function updateColumn(e) {
            if ($(e.target).data("option") == "autoresize") {
                if (e.target.checked) {
                    grid.setOptions({ forceFitColumns: true });
                    grid.autosizeColumns();
                } else {
                    grid.setOptions({ forceFitColumns: false });
                }
                return;
            }

            if ($(e.target).data("option") == "syncresize") {
                if (e.target.checked) {
                    grid.setOptions({ syncColumnCellResize: true });
                } else {
                    grid.setOptions({ syncColumnCellResize: false });
                }
                return;
            }

            if ($(e.target).is(":checkbox")) {
                var visibleColumns = [];
                $.each(columnCheckboxes, function (i, e) {
                    if ($(this).is(":checked")) {
                        visibleColumns.push(columns[i]);
                    }
                });

                if (!visibleColumns.length) {
                    $(e.target).attr("checked", "checked");
                    return;
                }

                setLocalStorage($(e.target));

                grid.setColumns(visibleColumns);
            }
        }

        function setLocalStorage(item) {

            var name = item.parent()[0].innerText;
            var check = item[0].checked;

            var columns = getColumnsLocalStorage();
            var coluna = ko.utils.arrayFirst(columns, function (col) {
                return col.item.name === name;
            });
            if (coluna) {
                coluna.visivel = check;
                localStorage.setItem(target, ko.toJSON(columns));
            }

        }

        function loadColumnsStorage() {
            var columnsLocalStorage = getColumnsLocalStorage();
            var colunaVisiveis = ko.utils.arrayFilter(columnsLocalStorage, function (col) {
                return col.visivel === true;
            });
            var col = ko.utils.arrayMap(colunaVisiveis, function (col) { return col.item; });
            if (columns.length > 0) {
                $.each(col, function (i, e) {
                    var formatter = ko.utils.arrayFilter(columns, function (item) {
                        return col[i].field == item.field;
                    });
                    if (formatter.length > 0)
                        col[i].formatter = formatter[0].formatter;
                });
                grid.setColumns(col);
            }
        }

        function getAllColumns() {
            return columns;
        }

        init();

        return {
            "getAllColumns": getAllColumns,
            "destroy": destroy
        };
    }

    // Slick.Controls.ColumnPicker
    $.extend(true, window, { Slick: { Controls: { ColumnPicker: SlickColumnPicker } } });
})(jQuery);