
/**
@class GridSelectionManager
@namespace ProspectDirector.Modules.Core
**/
ProspectDirector.Types.Core.GridSelectionManager = Class.extend({

    //---------------------------
    //--- CONSTANTS
    //---------------------------

    /**
    @property SELECTION_MODE {Object}
    @final
    **/
    SELECTION_MODE: {
        "none": "none",
        "single": "single",
        "multiple": "multiple"
    },

    //--- FIELDS
    //---------------------------

    _selections: [],

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

    /**
    @method init
    @private
    **/
    init: function (options) {

        /* set options */

        this.options = $.extend({}, {
            grid: null,
            pk: "ObjectId",
            keys: ["ObjectId"],
            selectionMode: this.SELECTION_MODE.none,
            selectOnRightClick: false,
            click: null,
            dblclick: null,
            mousedown: null
        }, options);

        /* bind internal event handlers */
        if (this.options.selectionMode !== this.SELECTION_MODE.none) {

            if (!this.get_grid().data("kendoGrid")) {
                return;
            }

            /* unbind existing event handlers */
            this.get_grid().data("kendoGrid").unbind("change");
            this.get_grid().data("kendoGrid").unbind("dataBound");
            this.get_grid().off("click.selectionManager");
            this.get_grid().off("dblclick.selectionManager");
            this.get_grid().off("mousedown.selectionManager");

            /* bind event handlers */
            this.get_grid().data("kendoGrid").bind("change",
                $.proxy(this._onChange, this));

            this.get_grid().data("kendoGrid").bind("dataBound",
                $.proxy(this._onDataBound, this));

            this.get_grid().on("click.selectionManager", ".k-grid-content TR[data-uid]",
                $.proxy(this._onClick, this));

            this.get_grid().on("dblclick.selectionManager", ".k-grid-content TR[data-uid]",
                $.proxy(this._onDblClick, this));

            this.get_grid().on("mousedown.selectionManager", ".k-grid-content TR[data-uid]",
                $.proxy(this._onMouseDown, this));

        }


        /* bind options event handlers */
        if ($.isFunction(this.options.click)) {
            $(this).bind("click", this.options.click);
        }

        if ($.isFunction(this.options.dblclick)) {
            $(this).bind("dblclick", this.options.dblclick);
        }

        if ($.isFunction(this.options.dblclick)) {
            $(this).bind("mousedown", this.options.mousedown);
        }

    },

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

    /**
    @property get_grid {Object}
    **/
    get_grid: function () {
        return this.options.grid;
    },

    /**
    @property get_dataSource {Object}
    **/
    get_dataSource: function () {
        return this.get_grid().data("kendoGrid").dataSource;
    },

    /**
    @property get_selections {Array}
    **/
    get_selections: function () {
        return this._selections;
    },

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

    /**
    @method _onChange
    @private
    **/
    _onChange: function (e) {
        e.preventDefault(e);
    },

    /**
    @method _onDataBound
    @private
    **/
    _onDataBound: function (e) {
        this.restore();
    },

    /**
    @method _onMouseDown
    @private
    **/
    _onMouseDown: function (e) {

        var row = null,
            isSelected = false;

        if (this.options.selectOnRightClick && e.button === 2) {

            row = $(e.target).closest("TR[data-uid]");
            isSelected = row.hasClass("k-state-selected");

            if (!isSelected) {
                this.clear();
                row.addClass("k-state-selected");
            }

            this._persist();

        }

        $(this).trigger("mousedown");

    },

    /**
    @method _onClick
    @private
    **/
    _onClick: function (e) {

        var row = $(e.target).closest("TR[data-uid]"),
            isSelected = row.hasClass("k-state-selected"),
            fireClickEvent = false;

        if (!(e.ctrlKey || e.metaKey) || this.options.selectionMode === this.SELECTION_MODE.single) {

            this.clear();
            row.addClass("k-state-selected");

            if (!isSelected) {
                fireClickEvent = true;
            }

        }
        else {

            if (isSelected) {
                row.removeClass("k-state-selected");
            }
            else {
                row.addClass("k-state-selected");
                fireClickEvent = true;
            }

        }

        this._persist();
        this.restore();

        if (fireClickEvent) {
            $(this).trigger("click", { id: this.get_selections(), data: this.getSelectionsData() });
        }

    },

    /**
    @method _onDblClick
    @private
    **/
    _onDblClick: function (e) {

        var row = $(e.target).closest("TR[data-uid]"),
            rowData = this.getRowData(row);

        $(this).trigger("dblclick", { id: this.get_selections(), data: this.getSelectionsData() });

    },

    //---------------------------
    //--- PRIVATE METHODS
    //---------------------------

    /**
    @method persist
    @private
    **/
    _persist: function (overwrite) {

        var elements = this.get_grid().find(".k-grid-content .k-state-selected"),
            selectionsClone = [],
            selected = [],
            ds = this.get_dataSource(),
            index = 0,
            row = null;

        for (var i = 0; i < elements.length; i++) {

            row = this.getRowData(elements[i]);

            if ($.inArray(row[this.options.pk], this._selections) === -1) {
                this._selections[this._selections.length] = row[this.options.pk];
            }

            selected[selected.length] = row[this.options.pk];

        }

        selectionsClone = this._selections.slice(0);

        for (index = selectionsClone.length; index > -1; index--) {
            if ($.inArray(this._selections[index], selected) === -1) {
                this._selections.splice(index, 1)
            }
        }

    },

    /**
    @method _readDataSource
    @private
    **/
    _readDataSource: function () {

        var grid = this.get_grid().data("kendoGrid");
        grid.dataSource._skip = 0;
        grid.dataSource.read();

    },

    //---------------------------
    //--- PUBLIC METHODS
    //---------------------------

    /**
    @method clear
    **/
    clear: function () {

        this.get_grid().find(".k-grid-content .k-state-selected").removeClass("k-state-selected");
        this._selections = [];

    },

    /**
    @method restore
    **/
    restore: function () {

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

        if (grid) {

            for (var i = 0; i < this._selections.length; i++) {

                if (grid.dataSource.get(this._selections[i]) !== undefined) {

                    this.get_grid().find("tr[data-uid=" + grid.dataSource.get(this._selections[i]).uid + "]").addClass("k-state-selected");

                }

            }

        }

    },

    /**
    @method refresh
    **/
    refresh: function (keys) {

        var index = 0,
            int = null;

        if (keys === undefined) {
            this._readDataSource();
            return;
        }

        if (keys === null) {
            this.clear();
            this._readDataSource();
            return;
        }

        if (!$.isArray(keys)) {
            keys = [keys];
        }

        this.clear();

        for (index = 0; index < keys.length; index++) {
            if ($.isNumeric(keys[index])) {
                int = parseInt(keys[index]);
                this._selections[this._selections.length] = int;
                if (index === 0) {
                    setTimeout($.proxy(function () {
                        this.scrollIntoView(int);
                    }, this), 100);
                }
            }
        }

        this._readDataSource();

    },

    /**
    @method getSelectionsData
    **/
    getSelectionsData: function () {

        var index = 0,
            data = [],
            ids = this.get_selections(),
            ds = this.get_dataSource();

        for (index = 0; index < ids.length; index++) {
            data[data.length] = ds.get(ids[index]);
        }

        return data;

    },

    /**
    @method getRowData
    **/
    getRowData: function (element) {
        return this.get_dataSource().getByUid($(element).data("uid"));
    },

    /**
    @method getRowKeyDataByPK
    **/
    getRowKeyDataByPK: function (id) {

        var index = 0,
            data = this.get_dataSource()._data;

        for (index = 0; index < data.length; index++) {

            if (id === data[index][this.options.pk]) {
                return data[index];
            }

        }

        return null;

    },

    /**
    @method getRowKeyData
    **/
    getRowKeyData: function (element) {

        var row = this.getRowData(element),
            index = 0,
            result = {};

        for (index = 0; i < this.options.keys.length; index++) {
            result[this.options.keys[index]] = row[this.options.keys[index]];
        }

        return result;

    },

    /**
    @method selectRowsByPK
    **/
    selectRowsByPK: function (keys) {

        var index = 0,
            dataRow = null;

        if (!$.isArray(keys)) {
            keys = [keys];
        }

        this.clear();

        for (index = 0; index < keys.length; index++) {

            dataRow = this.getRowKeyDataByPK(keys[index]);

            this._selections[this._selections.length] = dataRow[this.options.pk];

            this.get_grid().find("TR[data-uid=" + dataRow.uid + "]").addClass("k-state-selected");

        }

    },

    /**
    @method scrollIntoView
    **/
    scrollIntoView: function (id) {

        var data = this.getRowKeyDataByPK(id),
            uid = null,
            row = null;

        if (data !== null) {
            uid = data.uid;
        }

        if (uid !== null) {
            row = this.get_grid().find("TR[data-uid=" + uid + "]").first();
            this.get_grid().find(".k-grid-content").scrollTop(row.offset().top);
        }


    },

    selectFirst: function () {

        var data = this.get_dataSource().data();

        if (data.length > 0) {
            this.selectRowsByPK(data[0].id);
        }

    }

});