  ///////////////////
 //   Selection   //
///////////////////

/**
 * Selection as a set of object IDs.
 */
function Selection2() {
    /**
     * Number of selected items.
     */
    this.count = 0;
    /**
     * A map from object IDs to object IDs.
     * @private
     */
    this.data = new LRUKeyList();
    
    /**
     * Index of the selection anchor.
     * The anchor is used for range selects with the Shift key.
     * @private
     */
    this.anchor = 0;
    
    /**
     * Events triggered by this Selection.
     * <dl><dt>Selected</dt><dd>The selection has changed. Parameters:
     * <ul><li>Number of selected elements.</li></ul></dd></dl>
     */
    this.events = new Events();
    
    var Self = this;
    
    this.collection;
    
    this.selectedIndex = 0;
    
    //TODO
    /**this.changed_cb = function() {
        var oldcount = Self.count;
        for (var id in Self.data) {
            if (!(id in Self.storage.indices)) {
                delete Self.data[id];
                Self.count--;
            }
        }
        if (Self.count != oldcount)
            Self.events.post("Selected", Self.count);
    };***/
}

Selection2.prototype = {
    /**
     * Returns the selection status of a single item.
     * @param {Int} index The index of the queried item.
     * @return Boolean
     */
    get: function(index) {
        if (!this.collection) console.error("Selection.get without collection");
        var key = this.collection.objects[index];
        if (!key) return false;
        return this.data.get(key) != null;
    },
    
    /**
     * Returns the selection status of a single item. returns false if ths index
     * is out of range.
     * @param {Int} index The index of the queried item.
     * @return Boolean
     */
    get2: function(index) {
        if (!this.collection) console.error("Selection.get2 without collection");
        var key = collection.objects[index];
        if (!key) return false;
        return this.data.get(key) != null;
    },
    /**
     * Toggles the selection status of a single item.
     * @param {Int} index The index of the toggled item.
     * @return the new selection status of the toggled item.
     * @private
     */
    toggle: function(index) {
        if (!this.collection) console.error("Selection.toggle without collection");
        var key = this.collection.objects[index];
        var oldValue = this.data.get(key) ;
        (oldValue)  ? this.data.remove(key) : this.data.set(key,true);
        this.count += oldValue ? -1 : 1;
        this.events.post("Selected", this.count);
        return !(oldValue != null) ;
    },
    
    /**
     * Deselects the specified serialized object IDs.
     * @param {Object} sids An object with serialized object IDs to deselect
     * as keys.
     */
    deselectSIDs: function(keys) {
        for (var i in keys) {
            var oldValue = this.data.get(keys[i]);
            this.count -= (oldValue) ? 1 : 0;
            this.data.remove(keys[i]);
        }
        this.events.post("Selected", this.count);
    },
    
    /**
     * Selects the specified serialized Keys
     * @param {Object} keys - an Array of objects with serialized Keys
     * @see OXCache.Key
     */
    selectIDs: function(keys) {
    	this.reset();
    	// set new selection    	
        for (var i in keys) {
            this.data.set(keys[i], true);
        }
        this.count = keys.length;
        this.events.post("Selected", this.count);
    },

    /**
     * Clears the entire selection.
     * @private
     */
    reset: function() {
        this.data = new LRUKeyList();
        this.count = 0;
        this.events.post("Selected", this.count);
    },
    
    /**
     * Selects multiple items.
     * @param {Int} from Lower inclusive limit of the selected range.
     * @param {Int} to Upper exclusive limit of the selected range.
     * @private
     */
    select: function(from, to) {
         if (!this.collection) console.error("Selection.select without collection");
        for (var i = from; i < to; i++) {
            var key = this.collection.objects[i];
            var oldValue = this.data.get(key);
            if (!(oldValue)) {
                this.count++;
                this.data.set(key,true);
            }
        }
        this.events.post("Selected", this.count);
    },
    
    /**
     * Returns an array with object IDs of selected items.
     * @type Array
     * @return an array with object IDs of selected items.
     */
    getSelected: function() {
        var myArray = new Array();
        var tmpKeys=this.data.keys();
        //FIX FOR UPDATES AFTER OBJECT IS STILL UPDATED E.G. UPDATE CONTACTS FLAGs two times on same object
        if(!this.collection) { return tmpKeys; }
        for(var i=0;i<tmpKeys.length;i++) {
            myArray.push(this.collection.objects[
                this.collection.map_objects.get(tmpKeys[i]) - 1
            ] || tmpKeys[i]);
        }
	    return myArray;
    },
    
    /**
     * Handles a mouse click.
     * @param {Number} index Index of the clicked item.
     * @param {Event} e An optional event object which specifies which modifier
     * keys were held down at the time of the click.
     */
    click: function(index, e) {
        if (!this.collection) console.error("Selection.click without collection");
        if (index < 0 || index >= this.collection.objects.length) {
            this.reset();
            return;
        }
        if (!e || !(Mac ? e.metaKey : e.ctrlKey)) this.reset();
        if (e && e.shiftKey)
            this.select(Math.min(this.anchor, index),
                Math.max(this.anchor, index) + 1);
        else {
            this.toggle(index);
            this.anchor = index;
        }
    },
    
    /**
     * Sets the storage which is used to convert indices to object IDs.
     * @param {Collection} collection The collection, or null.
     * @param {Int} selectedIndex An optional parameter which specifies
     * the index of an automatically selected element if the selection is empty
     * or becomes empty because of the new collection.
     * @type Boolean
     * @return Whether an element was automatically selected.
     */
    setCollection: function(collection, selectedIndex) {
        var oldcount=this.count;
        if (collection) {
			var keys=this.data.keys();
            for (var id in keys) {
                if (!(collection.map_objects.get(keys[id]))) { 
                    this.data.remove(keys[id]);
                    this.count--;
                }
            }
        }
        this.collection = collection;
        var retval = !this.count;
        if (collection) {
            if (!this.count && selectedIndex != undefined) { 
            	this.click(selectedIndex); 
            } else if (this.count != oldcount) { 
            	this.events.post("Selected", this.count); 
            }
        }
        return retval;
    },
    
    /**
     * @deprecated
     */
    getID: function() {
        return this.data.get(this.data.keys()[0]);
    }
};
