/// class ProspectDirector.Modules.Views.ViewGrid
/// using ProspectDirector.Types.Core.ContextMenu

ProspectDirector.Modules.Views.ViewGrid = (function (options) {

    var 

    PRIVATE = {

        //---------------------------
        //--- CONSTRUCTOR
        //---------------------------

        init: function () {

            options = $.extend({
                selector: null,
                viewStateId: null,
                height: null,
                create: null,
                configurationLoad: null,
                needContext: null,
                rowClick: null,
                rowDblClick: null,
                selectionModel: "none",
                search: true,
                summary: true
            }, options);

            PRIVATE.init_control();

        },

        //---------------------------
        //--- PROPERTIES
        //---------------------------

        get_grid: function () {
            return $(options.selector);
        },

        get_viewStateId: function () {
            return options.viewStateId;
        },

        get_selection: function () {
            return PRIVATE.get_grid().data("selection");
        },

        get_filterables: function () {
            return PRIVATE.get_grid().data("filterables");
        },

        get_toolBar: function () {
            return PRIVATE.get_grid().data("viewGridToolbar");
        },

        get_configuration: function () {
            return PRIVATE.configuration;
        },

        //---------------------------
        //--- INTIALIZERS
        //---------------------------

        init_control: function () {

            options.selectors = {
                search: "[data-role=quick-search]",
                summary: "[data-role=filter-summary]"
            };

            if ($.isFunction(options.create)) {
                $(PRIVATE).bind("create", options.create);
            }

            if ($.isFunction(options.needContext)) {
                $(PRIVATE).bind("needContext", options.needContext);
            }

            if ($.isFunction(options.configurationLoad)) {
                $(PRIVATE).bind("configurationLoad", options.configurationLoad);
            }

            PRIVATE.get_grid().data("viewGrid", PRIVATE);

            PRIVATE.build();

        },

        //---------------------------
        //--- EVENT HANDLERS
        //---------------------------

        dataSource_onChange: function (e) {

            PRIVATE.removeMessage();

            if (PRIVATE.get_grid().data("kendoGrid")) {
                PRIVATE.noRecordsCheck();
                PRIVATE.noColumnsCheck();
            }

        },

        dataSource_onDataRead: function (e) {

            var result = null;

            result = {
                viewStateId: PRIVATE.get_viewStateId(),
                contextualFilters: JSON.stringify(PRIVATE.getContextualFilters()),
                searchTerm: PRIVATE.get_toolBar().getSearchTerm()
            };

            if (options.selection) {
                result.selection = options.selection;
                options.selection = null;
            };

            return result;

        },

        grid_onColumnResize: function (e) {

            var url = ProspectDirector.RUNTIME.resolveUrl("~/viewcolumn/setwidth"),
                grid = PRIVATE.get_grid().data("kendoGrid");

            PD.ajax({
                url: url,
                type: "POST",
                data: {
                    viewStateId: options.viewStateId,
                    columnId: e.column.field,
                    width: e.newWidth
                },
                success: function () {
                    grid._rowHeight = 0;
                    grid.virtualScrollable.refresh();
                }
            });

        },

        grid_onColumnReorder: function (e) {

            var url = ProspectDirector.RUNTIME.resolveUrl("~/viewcolumn/move");

            /* If moving the last column (which is a dummy column), prevent this by moving it back to the last index. Works around lack of support for canceling the column reorder event in kendo grid. */
            if (e.column.field === null) {

                /* A short timeout is required to allow grid column reorder event to bubble before attempting programmatic reorder. */
                setTimeout(function () {
                    e.sender.reorderColumn(e.sender.columns.length - 1, e.column)
                }, 50);

                return;

            }

            /* If moving a column after the last column (which is a dummy column), prevent this by moving it back to its previous index. Works around lack of support for canceling the column reorder event in kendo grid.  */
            if (e.newIndex == e.sender.columns.length - 1) {

                /* A short timeout is required to allow grid column reorder event to bubble before attempting programmatic reorder. */
                setTimeout(function () {
                    e.sender.reorderColumn(e.sender.columns.length - 2, e.column)
                }, 50);

            }

            PD.ajax({
                url: url,
                type: "POST",
                data: {
                    viewStateId: PRIVATE.get_viewStateId(),
                    columnId: e.column.field,
                    index: (e.newIndex == e.sender.columns.length - 1) ? e.sender.columns.length - 2 : e.newIndex
                }
            });

        },

        //---------------------------
        //--- METHODS
        //---------------------------

        build: function () {

            var url = ProspectDirector.RUNTIME.resolveUrl("~/view/getconfiguration?") + $.param({
                viewStateId: PRIVATE.get_viewStateId()
            });

            PD.ajax({
                url: url,
                dataType: "json",
                success: function (configuration) {
                    PRIVATE.configuration = configuration;
                    PRIVATE.buildGrid(configuration);
                    $(PRIVATE).trigger("configurationLoad", configuration);
                }
            });

        },

        buildGrid: function (configuration) {

            if (this.get_grid().length === 0) {
                return;
            }

            /* must add an empty column with no width for other columns to be sized correctly */
            configuration.columns[configuration.columns.length] = {
                field: null,
                width: 2000,
                template: "&nbsp;"
            };

            /* destroy the existing grid instance if one exists */
            if (PRIVATE.get_grid().length > 0 && PRIVATE.get_grid().data("kendoGrid") !== undefined) {
                PRIVATE.get_grid().data("kendoGrid").destroy();
            };

            /* empty the grid DIV */
            PRIVATE.get_grid().empty();

            /* instantiate a new Kendo grid instance */
            PRIVATE.get_grid().kendoGrid({
                autoBind: false,
                dataSource: PRIVATE.buildDataSource(configuration),
                sortable: {
                    mode: "multiple",
                    allowUnsort: true
                },
                resizable: true,
                reorderable: true,
                columns: configuration.columns,
                scrollable: {
                    virtual: true
                },
                height: options.height,
                pageable: {
                    previousNext: false,
                    numeric: false,
                    buttonCount: 0,
                    messages: {
                        display: "Displaying {2} items."
                    }
                },
                columnReorder: $.proxy(PRIVATE.grid_onColumnReorder, PRIVATE),
                columnResize: $.proxy(PRIVATE.grid_onColumnResize, PRIVATE)
            });

            $.removeData(PRIVATE.get_grid(), "selection");
            PRIVATE.get_grid().data("selection", new ProspectDirector.Types.Core.GridSelectionManager({
                grid: PRIVATE.get_grid(),
                keys: configuration.keys,
                selectionMode: options.selectionMode,
                selectOnRightClick: true,
                click: options.rowClick,
                dblclick: options.rowDblClick
            }));

            $.removeData(PRIVATE.get_grid(), "filterables");
            PRIVATE.get_grid().data("filterables", new ProspectDirector.Modules.Views.ViewGrid.Filterables());

            /* add column context menu to components */
            $.removeData(PRIVATE.get_grid(), "rowContextMenu");
            PRIVATE.get_grid().data("rowContextMenu", new ProspectDirector.Types.View.ColumnContextMenuColumn({
                parent: PUBLIC
            }));

            PRIVATE.get_grid().data("viewGridToolbar", new ProspectDirector.Modules.Views.ViewGridToolbar({
                parent: PRIVATE,
                settings: {
                    search: options.search,
                    summary: options.summary
                },
                configuration: configuration
            }));

            /* add filter icons to columnn headers when column has quick filter applied */
            $.each(PRIVATE.getColumnHeaders(), $.proxy(function (idx, element) {
                if ($.inArray($(element).data().field, configuration.filters) > -1) {
                    PRIVATE.get_grid().data("filterables").filter(element);
                }
            }, PRIVATE));

            PRIVATE.get_grid().css({
                borderStyle: "none"
            });

            PRIVATE.get_grid().data("kendoGrid").dataSource.read();

            if (PRIVATE.get_grid().data("filler") !== undefined) {
                PRIVATE.get_grid().data("filler").size();
            }

            /* fire create event */
            $(PRIVATE).trigger("create");

        },

        buildDataSource: function (configuration) {

            var result = null;

            result = new kendo.data.DataSource({
                transport: {
                    read: {
                        type: "POST",
                        url: ProspectDirector.RUNTIME.resolveUrl("~/view/query"),
                        data: $.proxy(PRIVATE.dataSource_onDataRead, PRIVATE)
                    }
                },
                schema: {
                    data: "data",
                    total: "totalCount",
                    model: {
                        id: "ObjectId"
                    }
                },
                serverPaging: true,
                serverSorting: true,
                pageSize: configuration.pageSize,
                sort: configuration.sort,
                change: $.proxy(PRIVATE.dataSource_onChange, PRIVATE),
                error: function () {
                    PRIVATE.addMessage("<span style=\"color:darkred;\">The query could not complete due to an error.</span>");
                }
            });

            return result;

        },

        noColumnsCheck: function () {

            if (PRIVATE.getColumnCount() === 1) {
                PRIVATE.addMessage("Click to add columns", PRIVATE.showDesignDialog);
            };

        },

        noRecordsCheck: function () {

            if (PRIVATE.getRecordCount() === 0) {
                PRIVATE.addMessage("No records found");
            };

        },

        addMessage: function (text, callback) {

            var container = $("<table style=\"height:100%;background-color:#FFFFFF;\" data-role=\"message-container\"><tr><td style=\"text-align:center;vertical-align:middle;\"></td></tr></table>"),
                message = $("<span style=\"font-size:16px;\" data-role=\"message\">" + text + "</span>");

            PRIVATE.removeMessage();

            if ($.isFunction(callback)) {

                message.css({
                    textDecoration: "underline",
                    color: "#0000FF",
                    cursor: "pointer"
                });

                PRIVATE.get_grid().on("click", "[data-role=message-container] [data-role=message]", $.proxy(callback, PRIVATE));

            }

            message.appendTo(container.find("TR > TD"));

            PRIVATE.get_grid().find(".k-grid-content").prepend(container);

        },

        removeMessage: function () {
            PRIVATE.get_grid().find(".k-grid-content [data-role=message-container]").remove();
        },

        getColumnCount: function () {
            return PRIVATE.get_grid().data("kendoGrid").options.columns.length;
        },

        getRecordCount: function () {
            return PRIVATE.get_grid().data("kendoGrid").dataSource.total();
        },

        getContextualFilters: function () {

            var e = {
                filters: []
            };

            $(PRIVATE).trigger("needContext", e);

            return e.filters;

        },

        clearSort: function () {

            var grid = PRIVATE.get_grid().data("kendoGrid");

            grid.dataSource._sort = [];
            grid.dataSource.read();

        },

        clearQuickFilters: function () {

            PD.ajax({
                type: "POST",
                url: ProspectDirector.RUNTIME.resolveUrl("~/viewfilter/clearquick?") + $.param({
                    viewStateId: PRIVATE.get_viewStateId()
                }),
                success: function () {
                    $.each(PRIVATE.getColumnHeaders(), $.proxy(function (idx, element) {
                        PRIVATE.get_grid().data("filterables").unfilter(element);
                    }, PRIVATE));
                    PRIVATE.refresh();
                }
            });

        },

        refresh: function (id) {

            var grid = PRIVATE.get_grid().data("kendoGrid");

            if (id) {
                options.selection = id;
                PRIVATE.get_grid().data("selection").refresh(id);
            }
            else {
                grid.dataSource._skip = 0;
                grid.dataSource.read();
            }

        },

        redraw: function () {
            var kendoGrid = this.get_grid().data("kendoGrid");
            if (kendoGrid) {
                kendoGrid.refresh();
            }
        },

        getColumnHeaders: function () {
            return PRIVATE.get_grid().find(".k-grid-header .k-header");
        },

        filterables: function () {
            return PRIVATE.get_grid().data("filterables");
        },

        showDesignDialog: function () {

            ProspectDirector.Modules.Views.ViewDesignColumnsDialog.Dialog.show({
                params: {
                    viewStateId: this.get_viewStateId()
                },
                callbacks: {
                    ok: $.proxy(function (sender, e) {
                        this.build();
                    }, this)
                }
            });

        }

    },

    PUBLIC = {

        get_viewStateId: PRIVATE.get_viewStateId,
        get_grid: PRIVATE.get_grid,
        get_selection: PRIVATE.get_selection,
        get_configuration: PRIVATE.get_configuration,
        refresh: PRIVATE.refresh,
        redraw: PRIVATE.redraw,
        clearSort: PRIVATE.clearSort,
        clearQuickFilters: PRIVATE.clearQuickFilters,
        build: PRIVATE.build,
        filterables: PRIVATE.filterables,
        getContextualFilters: PRIVATE.getContextualFilters

    };

    PRIVATE.init();

    return PUBLIC;

});

ProspectDirector.Modules.Views.ViewGrid.Filterables = Class.extend({

    filter: function (trigger) {
        if (!this.isFiltered(trigger)) {
            this._addIcon(trigger);
        }
    },

    unfilter: function (trigger) {
        if (this.isFiltered(trigger)) {
            this._getIcon(trigger).remove();
        }
    },

    toggle: function (trigger) {

        if (this.isFiltered(trigger)) {
            this.unfilter(trigger);
        }
        else {
            this.filter(trigger);
        }

    },

    clearAllFilters: function (trigger) {

        var that = this,
            grid = $(trigger).closest(".k-grid");

        grid.find(".k-grid-header .k-header").each(function (index, el) {
            that._getIcon(el).remove();
        });

    },

    isFiltered: function (trigger) {
        return this._getIcon(trigger).length !== 0;
    },

    _getIcon: function (trigger) {
        return $(trigger).find(".k-link .grid-filter");
    },

    _addIcon: function (trigger) {
        $(trigger).children(".k-link").prepend("<img src=\"" + ProspectDirector.RUNTIME.resolveUrl("~/application/icons/misc/filter.png") + "\" class=\"grid-filter\" style=\"vertical-align:middle;padding-right:5px;\">");
    }

});

/**
@class ColumnContextMenuColumn
@namespace ProspectDirector.Types.View
**/
ProspectDirector.Types.View.ColumnContextMenuColumn = ProspectDirector.Types.Core.ContextMenu.extend({

    //===========================
    // CONSTRUCTOR
    //===========================

    init: function (options) {

        this._super($.extend({
            parent: null
        }, options));

    },

    //===========================
    // PROPERTIES
    //===========================

    get_parent: function () {
        return this.options.parent;
    },

    get_kendoGrid: function () {
        return this.get_parent().get_grid().data("kendoGrid");
    },

    get_contextMenuSelector: function () {
        return this.get_parent().get_grid().selector + " .k-grid-header .k-header :not([data-field=\"\"])";
    },

    //===========================
    // PROTECTED METHODS
    //===========================

    _executeCommand: function (command, e) {

        var col = e.$trigger.closest(".k-header"),
            colId = col.data().field;

        this[command](colId, col);

    },

    _configureContextMenu: function (sender, e) {

        var column = $(sender).closest(".k-header"),
            columnId = this.getColumnId(sender),
            isFiltered = this.get_parent().filterables().isFiltered(column);

        if (!isFiltered) {

            e.config.items.addFilter = {
                name: "Filter..."
            };

        };

        if (isFiltered) {

            e.config.items.editFilter = {
                name: "Edit Filter"
            };

            e.config.items.clearFilter = {
                name: "Clear Filter"
            };

        };

        e.config.items.clearAllFilters = {
            name: "Clear All Filters"
        };

        e.config.items.sep1 = "sep1";

        e.config.items.addColumnLeft = {
            name: "Add columns left..."
        };

        e.config.items.addColumnRight = {
            name: "Add columns right..."
        };

        e.config.items.removeColumn = {
            name: "Remove column"
        };

        e.config.items.sep4 = "sep4";

        e.config.items.sortAscending = {
            name: "Sort Ascending"
        }

        e.config.items.sortDescending = {
            name: "Sort Descending"
        }

        if (this.isSorted(columnId)) {

            e.config.items.removeSort = {
                name: "No Sort"
            }

        }

        if (this.isSorted()) {

            e.config.items.sep5 = "sep5";

            e.config.items.clearAllSorted = {
                name: "Clear All Sort"
            }

        }

    },

    //===========================
    // PRIVATE METHODS
    //===========================

    addFilter: function (columnId, column) {
        this.editFilter(columnId, column);
    },

    editFilter: function (columnId, column) {

        var that = this,
            url = ProspectDirector.RUNTIME.resolveUrl("~/viewfilter/addquick?");

        ProspectDirector.Types.Core.Dialogs.QuickFilterEditor.show({
            params: {
                viewStateId: this.get_parent().get_viewStateId(),
                filterId: columnId
            },
            callbacks: {
                ok: function (sender, e) {
                    PD.ajax({
                        url: url + $.param({
                            viewStateId: that.get_parent().get_viewStateId(),
                            filter: JSON.stringify(e)
                        }),
                        success: function (data, jqXHR, status) {
                            that.get_parent().refresh();
                            that.get_parent().filterables().filter(column);
                        }
                    });
                }
            }
        });

    },

    clearFilter: function (columnId, column) {

        var that = this,
            url = ProspectDirector.RUNTIME.resolveUrl("~/viewfilter/removequick?");

        PD.ajax({
            url: url + $.param({
                viewStateId: this.get_parent().get_viewStateId(),
                filterId: columnId
            }),
            success: function (data, jqXHR, status) {
                that.get_parent().refresh();
                that.get_parent().filterables().unfilter(column); ;
            }
        });

    },

    clearAllFilters: function (columnId, column) {

        var that = this,
            url = ProspectDirector.RUNTIME.resolveUrl("~/viewfilter/clearquick?");

        PD.ajax({
            url: url + $.param({
                viewStateId: this.get_parent().get_viewStateId()
            }),
            success: function (data, jqXHR, status) {
                that.get_parent().refresh();
                that.get_parent().filterables().clearAllFilters(column); ;
            }
        });


    },

    addColumnLeft: function (columnId, column) {
        this.addColumn(columnId, false);
    },

    addColumnRight: function (columnId, column) {
        this.addColumn(columnId, true);
    },

    addColumn: function (columnId, addRight) {

        var that = this;

        ProspectDirector.Types.Core.Dialogs.FindColumnInDesign.show({
            params: {
                viewStateId: this.get_parent().get_viewStateId(),
                columnId: columnId,
                insert: 0
            },
            callbacks: {
                ok: function (sender, e) {
                    that.addColumnCallback(columnId, addRight, e);
                }
            }
        });

    },

    addColumnCallback: function (column, addRight, columns) {

        var that = this,
            additions = [];

        for (var i = 0; i < columns.length; i++) {
            additions[additions.length] = columns[i].id;
        }

        PD.ajax({
            url: ProspectDirector.RUNTIME.resolveUrl("~/viewcolumn/addtodesign?"),
            type: "POST",
            data: {
                viewStateId: this.get_parent().get_viewStateId(),
                additions: additions,
                columnId: column,
                insertAfter: addRight
            },
            traditional: true,
            success: function (data, jqXHR, status) {
                that.get_parent().build();
            }
        });

    },

    removeColumn: function (columnId, column) {

        var that = this,
            url = ProspectDirector.RUNTIME.resolveUrl("~/viewcolumn/removefromdesign?")
                    + $.param({
                        viewStateId: this.get_parent().get_viewStateId(),
                        columnId: columnId
                    });

        PD.ajax({
            type: "POST",
            url: url,
            success: function (data, jqXHR, status) {
                that.get_parent().build();
            }
        });

    },

    removeSort: function (columnId, column) {

        var dataSource = this.get_kendoGrid().dataSource,
            sort = dataSource.sort(),
            item = null,
            index = 0;

        for (index; index < sort.length; index++) {
            item = sort[index];
            if (item.field === columnId) {
                sort.splice(index, 1)
                dataSource.sort(sort);
                this.get_parent().refresh();
                index = sort.length;
            }
        }

    },

    clearAllSorted: function (columnId, column) {

        var dataSource = this.get_kendoGrid().dataSource;

        dataSource.sort([])

        this.get_parent().refresh();

    },

    sortAscending: function (columnId, column) {
        this.sortColumn(columnId, "asc");
    },

    sortDescending: function (columnId, column) {
        this.sortColumn(columnId, "desc");
    },

    getSort: function (sort, columnId) {

        var result = null;

        if (columnId !== undefined
            && columnId !== null) {

            $(sort).each(function (i, e) {
                if (e.field === columnId) {
                    result = e;
                    return false;
                }
            });

        }

        return result;

    },

    sortColumn: function (columnId, direction) {

        var dataSource = this.get_kendoGrid().dataSource,
            sort = dataSource._sort.slice(0),
            item = this.getSort(sort, columnId);

        if (item !== null) {
            item.dir = direction;
        }
        else {
            sort[sort.length] = {
                field: columnId,
                dir: direction
            };
        }

        dataSource.sort(sort)

        this.get_parent().refresh();

    },

    isSorted: function (columnId) {

        var result = false,
            sort = this.get_kendoGrid().dataSource._sort;

        if (columnId !== undefined
            && columnId !== null) {

            $(sort).each(function (i, e) {
                if (e.field === columnId) {
                    result = true;
                    return false;
                }
            });

        }
        else {
            result = sort.length;
        }

        return result;

    },

    getColumnId: function (element) {
        return $(element).closest(".k-header").data("field");
    }

});
