﻿/*
 * Ext Scheduler v1.5 beta
 * Copyright(c) 2009-2010 Mats Bryntse Consulting
 * mats@ext-scheduler.com
 * http://www.ext-scheduler.com/license.html
 *
 */
 
Ext.ns('Sch');

/**
 * @class Sch.EventSelectionModel
 * @extends Ext.grid.AbstractSelectionModel
 * This class provides the basic implementation event selection in a grid.
 * @constructor
 * @param {Object} config The object containing the configuration of this model.
 */
Sch.EventSelectionModel = function(config){
    Ext.apply(this, config);

    this.selected = new Ext.CompositeElementLite();

    this.addEvents(
        /**
	     * @event beforeeventselect
	     * Fires before a cell is selected, return false to cancel the selection.
	     * @param {SelectionModel} this
	     * @param {Number} rowIndex The selected row index
	     * @param {Number} colIndex The selected cell index
	     */
	    "beforeeventselect",
       
        /**
	     * @event selectionchange
	     * Fires when the active selection changes.
	     * @param {SelectionModel} this
	     * @param {Object} selection null for no selection or an object with two properties
         * <div class="mdetail-params"><ul>
         * <li><b>cell</b> : see {@link #getSelectedCell} 
         * <li><b>record</b> : Ext.data.record<p class="sub-desc">The {@link Ext.data.Record Record}
         * which provides the data for the row containing the selection</p></li>
         * </ul></div>
	     */
	    "selectionchange"
    );

    Sch.EventSelectionModel.superclass.constructor.call(this);
};

Ext.extend(Sch.EventSelectionModel, Ext.grid.AbstractSelectionModel,  {
    /*
     * @cfg multiSelect true to allow selection of multiple events
     */
    multiSelect : false,
    
    /**
     * @cfg {String} selectedClass
     * A CSS class to apply to each selected item in the view (defaults to 'sch-event-selected').
     */
    selectedClass : 'sch-event-selected',
    
    /** @ignore */
    initEvents : function(){
        this.grid.on("eventclick", this.onEventClick, this);
        
        this.grid.getView().on({
            scope: this,
            refresh: this.onViewRefresh,
            rowupdated: this.onRowUpdated,
            beforerowremoved: this.clearSelections,
            beforerowsinserted: this.clearSelections
        });
    },
    
    deselectEvent : function(s, r) {
        this.deselect(this.grid.eventPrefix + r.id);
    },
    
    onRowUpdated : function(v, index, r){
        var count = this.selected.getCount(),
            resourceId = r.id;
        
        // Remove selected status after an item has been updated
        for (var i = count - 1; i >= 0; i--){
            var item = this.selected.item(i),
                eventRecord = this.grid.getEventRecordFromDomId(item.dom.id);
                
            // If an item is not found in the store or it is no longer in the DOM, unselect it
            if (!eventRecord || resourceId === eventRecord.get('ResourceId')) {
                this.selected.removeElement(item);
            }
        }
    },

	//private
    onViewRefresh : function(){
        this.clearSelections(true);
    },

    /**
     * Clears all selections.
     * @param {Boolean} suppressEvent (optional) True to skip firing of the selectionchange event
     */
    clearSelections : function(suppressEvent, skipUpdate){
        if(this.selected.getCount() > 0){
            if(!skipUpdate){
                this.selected.removeClass(this.selectedClass);
            }
            this.selected.clear();
            if(!suppressEvent){
                this.fireEvent("selectionchange", this, this.selected.elements);
            }
        }
    },

    /**
     * Returns <tt>true</tt> if there is a selection.
     * @return {Boolean}
     */
    hasSelection : function(){
        return this.selection ? true : false;
    },
    
    // private
    onEventClick : function(g, record, node, e){
        if(e.ctrlKey && this.isSelected(node)){
            this.deselect(node);
        }else{
            this.select(node, this.multiSelect);
        }
    },
    
    /**
     * Gets the number of selected nodes.
     * @return {Number} The node count
     */
    getSelectionCount : function(){
        return this.selected.getCount();
    },

    /**
     * Gets the currently selected nodes.
     * @return {Array} An array of HTMLElements
     */
    getSelectedNodes : function(){
        return this.selected.elements;
    },

    /**
     * Returns true if the passed node is selected, else false.
     * @param {HTMLElement/Number} node The node or node index to check
     * @return {Boolean} True if selected, else false
     */
    isSelected : function(node){
        return this.selected.contains(this.getNode(node).id);
    },

    /**
     * Deselects a node.
     * @param {HTMLElement/string} node The node to deselect
     */
    deselect : function(nodeInfo){
        var node = this.getNode(nodeInfo);
        if(this.isSelected(node)){
            node = this.getNode(node);
            this.selected.removeElement(node);
            Ext.fly(node).removeClass(this.selectedClass);
            this.fireEvent("selectionchange", this, this.selected.elements);
        }
    },

    /**
     * Selects a set of nodes.
     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node,
     * id of a template node or an array of any of those to select
     * @param {Boolean} keepExisting (optional) true to keep existing selections
     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
     */
    select : function(nodeInfo, keepExisting, suppressEvent){
        if(Ext.isArray(nodeInfo)){
            if(!keepExisting){
                this.clearSelections(true);
            }
            for(var i = 0, len = nodeInfo.length; i < len; i++){
                this.select(nodeInfo[i], true, true);
            }
            if(!suppressEvent){
                this.fireEvent("selectionchange", this, this.selected.elements);
            }
        } else{
            var node = this.getNode(nodeInfo);
            if(!keepExisting){
                this.clearSelections(true);
            }
            if(node && !this.isSelected(node)){
                if(this.fireEvent("beforeventselect", this, node, this.selected.elements) !== false){
                    Ext.fly(node).addClass(this.selectedClass);
                    this.selected.add(node);
                    if(!suppressEvent){
                        this.fireEvent("selectionchange", this, this.selected.elements);
                    }
                }
            }
        }
    },
    
    /**
     * Gets a template node.
     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
     * @return {HTMLElement} The node or null if it wasn't found
     */
    getNode : function(nodeInfo){
        if(typeof nodeInfo === 'string'){
            return document.getElementById(nodeInfo);
        }
        return nodeInfo;
    },
    
    // private, required for editing functionality when inheriting from EditorGridPanel
    onEditorKey : Ext.emptyFn
});
