// Copyright 2008 ProjectWizards GmbH. All rights reserved.

//console.log("OutlineController.js");

var OutlineController = Base.extend( {
    constructor: function(environment, delegate) {
        this.environment = environment;
        this.rootObjects = [];
        this.selectedObjects = [];
        this.sortFunction = null;
        this.sortDescriptors = null;
        this.flatObjects = null;
        this.childrenKey = "children";
        this.isCollapsedKey = "isCollapsed";
        this.isLeafKey = "isLeaf";
        this.objectsForID = [];
        this.preserveSelection = true;
        this.delegate = delegate;
		this.singleSelection = false;
    },
    
	setSingleSelection: function(flag) {
		this.singleSelection = flag;
	},
	
    setChildrenKey: function(key) {
        this.childrenKey = key;
        this.flatObjects = null;
        this.objectsForID = [];
    },
    
    setIsCollapsedKey: function(key) {
        this.isCollapsedKey = key;
        this.flatObjects = null;
        this.objectsForID = [];
    },
    
    setRootObjects: function(objects) {
        var ids = this.preserveSelection ? this.selectedObjectIDs(): null;        
        this.rootObjects = objects;
        this.flatObjects = null;
        this.objectsForID = [];
        if (this.preserveSelection)
            this.setSelectedObjectIDs(ids);
    },
    
    setSelectedObjects: function(objects) {
        if(this.singleSelection && objects.length > 1)
			return;
        this.selectedObjects = objects;
		if(this.singleSelection && objects && objects.length)
			this.selectedObjects = [objects[0]];
		this.selectedObjects.sort(this.sortFunction);
		if (this.delegate && this.delegate.selectionChanged)
			this.delegate.selectionChanged(this, this.selectedObjects);
    },
    
    selectedObjectIDs: function() {
        var ids = [];
        for (var i = 0; i < this.selectedObjects.length; i ++ )
            ids.push(this.selectedObjects[i].objectID.uri);
        return ids;
    },
    
    setSelectedObjectIDs: function(ids) {
		if(this.singleSelection && this.selectedObjects && this.selectedObjects.length)
			return;
        this.getFlatObjects();
        this.selectedObjects = [];
        for (var i = 0; i < ids.length; i ++ ) {
            var object = this.objectsForID[ids[i]];
            if (object) {
                this.selectedObjects.push(object);
				if(this.singleSelection)
					break;
			}
        }
        this.selectedObjects.sort(this.sortFunction);
        if (this.delegate && this.delegate.selectionChanged)
            this.delegate.selectionChanged(this, this.selectedObjects);
    },
    
    setSortDescriptors: function(descriptors) {
        this.sortDescriptors = descriptors;
        this.flatObjects = null;		
        this.sortFunction = function(a, b) {
            if (descriptors) {
                var descriptor;
                for (var i = 0; i < descriptors.length; i ++ ) {
                    descriptor = descriptors[i];
                    var val1 = a.sortValueForKey(descriptor.key);
                    var val2 = b.sortValueForKey(descriptor.key);
                    if (val1 < val2)
                        return descriptor.ascending ? -1: 1;
                    else if (val1 > val2)
                        return descriptor.ascending ? 1: -1;
                }
            }
            return 0;
        }		
        this.selectedObjects.sort(this.sortFunction);
    },
    
    objectForPersistentID: function(persistentID) {
        return this.objectsForID(persistentID);
    },
    
    getFlatObjects: function() {
        this.flatObjects = [];
        this.objectsForID = [];
        this.appendFlatObjects(this.rootObjects, 0);
		return this.flatObjects;
    },
    
	getAllObjects: function() {
		var me = this;
        allObjects = [];
		function appendObjects(objects, level) {
			if(me.sortFunction){
				try{
					objects.sort(me.sortFunction); 	
				}catch(e){}
			}
			for (var i = 0; i < objects.length; i ++ ) {
				var object = objects[i];
				object.level = level;
				allObjects.push(object);
				if (!object.valueForKey(me.isLeafKey)) {
					var children = object.valueForKey(me.childrenKey);
					if (children)
						appendObjects(children, level + 1);
				}
			}
		}
		appendObjects(this.rootObjects, 0);
        return allObjects;		
	},


    appendFlatObjects: function(objects, level) {
		if(objects){
			if(this.sortFunction){
				try{
					objects.sort(this.sortFunction); 	
				}catch(e){
					// Der IE bricht ab wenn ich der methode sort() eine Sortierfunktion übergebe (Nur im Druckfenster).
				}
			}
			for (var i = 0; i < objects.length; i ++ ) {
				var object = objects[i];
				object.level = level;
				this.flatObjects.push(object);
				this.objectsForID[object.objectID.uri] = object;
				
				if ( ! object.valueForKey(this.isCollapsedKey) && !object.valueForKey(this.isLeafKey)) {
					var children = object.valueForKey(this.childrenKey);
					if (children)
						this.appendFlatObjects(children, level + 1);
				}
			}
		}
    },
    
    
    //	Indenting and Outdenting
    //
    //
    flatIndexOfObject: function(object) {
        for (var i = 0; i < this.flatObjects.length; i ++ )
            if (this.flatObjects[i] == object)
            return i;
        return - 1;
    },
    
    levelForObjectAtFlatIndex: function(index) {
        var object = this.flatObjects[index];
        return object ? object.level: -1;
    },
    
    isObjectAtFlatIndexSelected: function(index) {
        var object = this.flatObjects[index];
        var selObj;
        for (var i = 0; i < this.selectedObjects.length; i ++ )
            if (this.selectedObjects[i] == object)
            return true;
        return false;
    },
    
    firstUnselectedObjectAboveOnSameLevel: function(item) {
        var result = null;
        var row = this.flatIndexOfObject(item);
        var level = item.level;
        while (row >= 0) {
            var iterLevel = this.levelForObjectAtFlatIndex(row);
            if (iterLevel < level)
                break;
            else if (iterLevel == level && !this.isObjectAtFlatIndexSelected(row)) {
                result = this.flatObjects[row];
                break;
            } else row -- ;
        }
        return result;
    },
    
    parentIndexForIndex: function(index) {
        var startLevel = this.levelForObjectAtFlatIndex(index);
        while ( -- index >= 0) {
            var level = this.levelForObjectAtFlatIndex(index);
            if (level < startLevel)
                return index;
        }
        return - 1;
    },
    
    objectAtIndex: function(index) {
        if (index == -1)
            return null;
        var objects = !this.flatObjects || this.flatObjects.length == 0 ? this.getFlatObjects(): this.flatObjects;
        return objects[index];
    },
    
    isParentForObjectAtIndexSelected: function(index) {
        var parentIndex = this.parentIndexForIndex(index);
        var parentItem = this.objectAtIndex(parentIndex);
        return parentIndex !=- 1 && this.selectedObjects.indexOf(parentItem) !=- 1;
    },
    
    isObjectIndentable: function(object) {
        var index = this.flatIndexOfObject(object);
        return( ! this.isParentForObjectAtIndexSelected(index) && this.firstUnselectedObjectAboveOnSameLevel(object));
    },
    
    minOutdentLevel: function() {
        if (this.delegate && this.delegate.minOutdentLevel)
            return this.delegate.minOutdentLevel();
        else return 0;
    },
    
    isObjectOutdentable: function(object) {
        var index = this.flatIndexOfObject(object);
        return ! this.isParentForObjectAtIndexSelected(index) && this.levelForObjectAtFlatIndex(index) > this.minOutdentLevel();
    },
    
    firstSelectedObject: function() {
        return this.selectedObjects && this.selectedObjects.length ? this.selectedObjects[0]: null;
    },
    
    indentationParentObjectForObject: function(object) {
        var result = null;
        var firstUn = this.firstUnselectedObjectAboveOnSameLevel(object);
        if (firstUn)
            result = firstUn;
        else {
            var firstSel = this.firstSelectedObject();
            if (firstSel && firstSel != object)
                result = firstSel;
        }
        return result;
    },
	
	setDelegate: function(delegate){
		this.delegate = delegate;
	}
    
    
});