


    function OnBodyLoad()
    {
        
        if (document.readyState)
        {
            // this is ie - we have a readyState property - no need to simulate one.
        }
        else
        {
            // this is Mozilla - it does not have a ready state property - so we will make one.
            document.readyState = "complete";        
        }
    }

   var notrace = 1;

   function trace( type, message )
   {
		if
			(notrace)
		{
		}
		else
		{
			if (type == null)
			{
				type = "Trace";
			}
			if (message == null)
			{
				message = "";
			}
			console.log( type+":"+ message );
		}
   }

	function Popup( width, url, onload )
	{
        var b = documentManager.topManager ().create ( "floatingFrame" );
        b.safeSetRectangle ( 30, 30, width, 0 );
        b.start ();
        b.load ( url );
        if (onload != null)
    	{
    		b.onLoad = onload;
    	}
        return b;
	}

	function PopupWH( width, height, url, onload )
	{
        var b = documentManager.topManager ().create ( "floatingFrame" );
        b.safeSetRectangle ( 30, 30, width, height );
        b.start ();
        b.load ( url );
        if (onload != null)
    	{
    		b.onLoad = onload;
    	}
        return b;
	}

	/** Add some code to disable the firebug console trace if we are running in IE **/

	/*if (notrace)
	{		
		if (!("console" in window) || !("firebug" in console))
		{
		    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
		    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
		
		    window.console = {};
		    for (var i = 0; i < names.length; ++i)
		        window.console[names[i]] = function() {}
		}
	}*/	
	
	
   /*** 
        to make the document manager work correctly we need to know when the document has
        initialised. For IE we do this by watching the readyState, but Mozilla and others 
        don't support this. So we need a way to indicate when these browsers have completed 
        loading the document. The solution is to put an onload handler on the body element. 
        At first I tried to do this in script, but until the document has loaded mozilla returns
        null for the body element, so I can't assign this handler in the initialise routine.
        so instead we require that the following onLoadHandler is called whenever the document 
        manager is used.
   
   ***/
   
   function onLoadHandler()
   {
            if ( document.readyState )
            {
            }
            else
            {
                document.readyState = "complete";
                trace("setting document readystate to complete");
            }
    }   
   // trace( "callback", "some message " );
   
   var debugTrace = false;
   if ( debugTrace ) document.write("Entering documentManager<br>");  

    if ( window.documentManager != null ) {
        alert ( "WARNING\r\ndocumentManager included on page more than once" );
    }

function alertObjProp(obj)
{
  var s="";
  for(var prop in obj)
  {
    try
    {
        var t = typeof(obj[prop]);
        if ( t == "string" || t == "number" )
        {
            s+='{'+prop+'='+obj[prop]+'} ';
        }
    }
    catch ( ex ){}
  }
  return s;
}
function alertObjProp2(obj)
{
  var s="";
  for(var prop in obj)
  {
    var t = typeof(obj[prop]);
    if ( t == "number" )
    {
        s+='{'+prop+'='+obj[prop]+'} ';
    }
    else
    {
        s+='{'+prop+'='+typeof(obj[prop])+'} ';
    }
  }
  return s;
}


//--------------------------------------------------------
    function fnGetLangCode() {
      var strApp = navigator.userLanguage.toLowerCase();
        var twoLtrCode = strApp.charAt(0)+strApp.charAt(1);
        switch (twoLtrCode){
          case "en":threeLtrCode = "ENG";break;
            case "fr":threeLtrCode = "FRE";break;
            case "de":threeLtrCode = "GER";break;
            case "nl":threeLtrCode = "DUT";break;
            default:threeLtrCode = "ENG";
    }
        return(threeLtrCode);
    }

    
//--------------------------------------------------------

    function trim(text)
    {      
       var index = 0;               
       var newText = "";            
       var lastSpacePos = -1;       
       var reached = false;         
       for (index = 0; index < text.length; index++){   
          if (text.charAt(index) != " "){reached = true;}
          if (reached) {newText += text.charAt(index);}
       }   
       reached = false;
       for (index = newText.length; index >= 0; index--){   
          if (!reached){   
             if ((newText.charAt(index) != " ") && (index !=newText.length)){
                lastSpacePos = index + 1;
                reached = true;
             }
          }
       }   
       if (lastSpacePos != -1){newText = newText.substring(0, lastSpacePos);}
       return newText;
    }

//--------------------------------------------------------
        function dataStoreObject ()
        {
            this.fields = new Object ();
        }
        
        dataStoreObject.prototype.isDefined = function ( fieldName, propertyName ) {

            var fieldObject = this.fields [ fieldName ];
            
            if ( ( typeof fieldObject ) == "undefined" ) return false;
            
            if ( ( typeof fieldObject [ propertyName ] ) == "undefined" ) return false;

            return true;
        }

        dataStoreObject.prototype.isFieldDefined = function ( fieldName ) {

            var fieldObject = this.fields [ fieldName ];
            
            if ( ( typeof fieldObject ) == "undefined" ) return false;

            return true;
        }

        dataStoreObject.prototype.remove = function ( fieldName, propertyName ) {
        
            var fieldObject = this.fields [ fieldName ];
            
            if ( ( typeof fieldObject ) == "undefined" ) return false;
            
            if ( ( typeof fieldObject [ propertyName ] ) == "undefined" ) return false;
            
            delete fieldObject [ propertyName ];

            for ( var i in fieldObject ) { return true; }
            
            delete this.fields [ fieldName ];

            return true;
        }

        dataStoreObject.prototype.getFieldObject = function ( fieldName ) {

            var result = this.fields [ fieldName ];
            
            if
                ( result == null )
            {
                result = new Object;
                this.fields [ fieldName ] = result;
            }

            return result;
        }

        dataStoreObject.prototype.write = function ( fieldName, propertyName, value ) {

            var fieldObject = this.getFieldObject ( fieldName );
            fieldObject [ propertyName ] = value;
        }

        dataStoreObject.prototype.read = function ( fieldName, propertyName ) {

            var fieldObject = this.getFieldObject ( fieldName );
            var result = fieldObject [ propertyName ];

            if
                ( result == null )
            {
                // Both must be set to real null...
                
                fieldObject [ propertyName ] = null;
                result = null;
            }

            return result;
        }

        //--------------------------------------------------------
        
        function databaseObject ()
        {
            this.dataStore = new dataStoreObject ();
            this.undoHistory = new Array ();
            this.redoHistory = new Array ();
            this.undoTransaction = null;
            this.redoTransaction = null;
            this.historyIndex = 0;
            this.undoCount = null;
            this.historyIndexTop = 0;
            this.mode = "";
            this.newIdentifier = 0;
        }

        databaseObject.prototype.newFieldName = function () {

            return "_" + this.newIdentifier++;
        }
    
        databaseObject.prototype.read = function ( fieldName, propertyName ) {
        
            return this.dataStore.read ( fieldName, propertyName );
        }

        databaseObject.prototype.write = function ( fieldName, propertyName, value ) {
        
            if
                ( this.mode == "" )
            {
                this.dataStore.write ( fieldName, propertyName, value );
                
                return;
            }
        
            if
                ( this.mode == "transaction" )
            {
                var oldValue = this.dataStore.read ( fieldName, propertyName );
                
                if
                    ( value != oldValue )
                {
                    var oldState = this.undoTransaction;
                
                    if
                        ( ! oldState.isDefined ( fieldName, propertyName ) )
                    {
                        oldState.write ( fieldName, propertyName, oldValue );
                        this.undoCount++;
                    }
                    else
                    if
                        ( oldState.read ( fieldName, propertyName ) == value )
                    {
                        oldState.remove ( fieldName, propertyName );
                        this.undoCount--;
                    }
                
                    this.redoTransaction.write ( fieldName, propertyName, value );
                    this.dataStore.write ( fieldName, propertyName, value );
                }
                
                return;
            }
            
            alert ( "Can't write during " + this.mode + " mode" );
        }

        databaseObject.prototype.transactionStarted = function () {

            return ( this.mode == "transaction" );
        }

        databaseObject.prototype.startTransaction = function () {
        
            if
                ( this.mode != "" )
            {
                //alert ( "Can't start transaction during " + this.mode + " mode" );
            }
            else
            {
                this.undoTransaction = new dataStoreObject ();
                this.redoTransaction = new dataStoreObject ();

                this.mode = "transaction";
                this.undoCount = 0;
            }
        }
        
        databaseObject.prototype.endTransaction = function () {
        
            if
                ( this.mode != "transaction" )
            {
                //alert ( "Can't end transaction during " + this.mode + " mode" );
            }
            else
            {
                if
                    ( this.undoCount != 0 )
                {
                    this.undoHistory [ this.historyIndex ] = this.undoTransaction;
                    this.redoHistory [ this.historyIndex ] = this.redoTransaction;
                    this.historyIndex++;
                    this.historyIndexTop = this.historyIndex;
                }
                
                this.mode = "";

                return ( this.undoCount != 0 );
            }
            return false;
        }
        
        databaseObject.prototype.changed = function () {

            return ( this.undoCount != 0 );
        }
        
        databaseObject.prototype.canUndo = function () {
        
            return ( this.historyIndex > 0 );
        }

        databaseObject.prototype.canRedo = function () {
        
            return ( this.historyIndex < this.historyIndexTop );
        }

        databaseObject.prototype.imposeChanges = function ( fields ) {

            for ( var fieldName in fields ) {

                var field = fields [ fieldName ];

                for ( var propertyName in field ) {

                    this.dataStore.write ( fieldName, propertyName, field [ propertyName ] );
                }
            }
        }

        databaseObject.prototype.undo = function ( object, methodName ) {
        
            if
                ( this.mode != "" )
            {
                alert ( "Can't undo during " + this.mode + " mode" );
            }
            else
            {
                if
                    ( this.historyIndex > 0 )
                {
                    this.mode = "undo";
                    
                    this.historyIndex--;

                    this.imposeChanges ( this.undoHistory [ this.historyIndex ].fields );

                    object [ methodName ] ( this.undoHistory [ this.historyIndex ].fields );
                    
                    this.mode = "";
                }
            }
        }

        databaseObject.prototype.redo = function ( object, methodName ) {
            if
                ( this.mode != "" )
            {
                alert ( "Can't redo during " + this.mode + " mode" );
            }
            else
            {
                if
                    ( this.historyIndex < this.historyIndexTop )
                {
                    this.mode = "redo";
                    
                    this.imposeChanges ( this.redoHistory [ this.historyIndex ].fields );

                    object [ methodName ] ( this.redoHistory [ this.historyIndex ].fields );

                    this.historyIndex++;

                    this.mode = "";
                }
            }
        }
        //--------------------------------------------------------
        
        /**
			every element which is managed by the document manager has a handle
			these handles are stored in a handle manager
			
			@constructor 
        **/
        function handleManagerObject ()
        {
            this.objects = new Object ();
            this.handle = 0;
        }

        /**
			returns a new handle for the object passed.
		**/

        handleManagerObject.prototype.newHandleForObject = function ( object ) {
            
            var h = this.handle;
			this.handle++;
            this.objects [ h ] = object;
            return h;
        }

        /**
			given a handle, returns the associated object
		**/
        
        handleManagerObject.prototype.getObject = function ( handle ) {
        
            return this.objects [ handle ];
        }

        /**
			removes a given handle.
		**/
        
        handleManagerObject.prototype.removeHandle = function ( handle ) {
        
            delete this.objects [ handle ];
        }

        /**
			removes an array of all objects, can be indexed by handle.
		**/

        handleManagerObject.prototype.getObjects = function () {

            return this.objects;
        }

        //--------------------------------------------------------

        function updateObject ( oInterface )
        {
            this.fields = new Object ();
            this.oInterface = oInterface;
        }
        
        updateObject.prototype.newFieldName = function () {
        
            return this.oInterface.newFieldName ();
        }

        updateObject.prototype.read = function ( fieldName, propertyName ) {

            return this.oInterface.read ( fieldName, propertyName );
        }

        updateObject.prototype.write = function ( fieldName, propertyName, value ) {

            var fieldObject = this.fields [ fieldName ];
            
            if
                ( fieldObject == null )
            {
                fieldObject = new Object;
                this.fields [ fieldName ] = fieldObject;
            }

            fieldObject [ propertyName ] = value;
        }

        updateObject.prototype.isWriteDefined = function ( fieldName, propertyName ) {

            var fieldObject = this.fields [ fieldName ];
            
            if ( ( typeof fieldObject ) == "undefined" ) return false;
            
            if ( ( typeof fieldObject [ propertyName ] ) == "undefined" ) return false;

            return true;
        }

        updateObject.prototype.peekWrite = function ( fieldName, propertyName ) {

            var fieldObject = this.fields [ fieldName ];
        
            if
                ( fieldObject != null )
            {
                return fieldObject [ propertyName ];
            }
            return null;
        }

        //--------------------------------------------------------

		/**
			a queue handling class
			@constructor
		**/
		
        function queueObject ()
        {
            this.content = null;
        }

		/**
			returns true if the queue is empty
		**/

        queueObject.prototype.isEmpty = function () {

            return this.content == null;
        }

		/**
			returns count of items in the queue
		**/

        queueObject.prototype.count = function () {

            if
                ( this.content == null )
            {
                return 0;
            }
            else
            {
                return this.next - this.first;
            }
        }

		/**
			puts an object int the queue
		**/

        queueObject.prototype.put = function ( object ) {

            if
                ( this.content == null )
            {
                this.content = new Object;
                this.content [ 0 ] = object;
                this.first = 0;
                this.next = 1;
            }
            else
            {
                this.content [ this.next ] = object;
                this.next++;
            }
        }

		/**
			gets an object from the queue
		**/

        queueObject.prototype.get = function () {

            var result = this.content [ this.first ];

            this.first++;
            
            if
                ( this.first == this.next )
            {
                this.content = null;
            }

            return result;
        }

        //--------------------------------------------------------

        function interfaceObject ( database )
        {
            this.database = database;

            this.dependencies = new dataStoreObject ();
            this.connections = new Object ();
            
            this.objects = new handleManagerObject ();
            this.readWrite = new Object ();

            this.clientHandle = null;
            this.updating = false;

            this.thingsToDo = new queueObject ();

            this.dependentProcessHandles = new Object ();
            this.dependentObserverHandles = new Object ();
        }

        interfaceObject.prototype.addDependencies = function ( handle, fields ) {

            for ( var fieldName in fields ) {

                for ( var propertyName in fields [ fieldName ] ) {

                    var handleMap = this.dependencies.read ( fieldName, propertyName );
                    
                    if
                        ( handleMap == null )
                    {
                        handleMap = new Object ();
                        this.dependencies.write ( fieldName, propertyName, handleMap );
                    }

                    if
                        ( handleMap [ handle ] == null )
                    {
                        var connections = this.connections [ handle ];
                
                        if
                            ( connections == null )
                        {
                            connections = new dataStoreObject ();
                            this.connections [ handle ] = connections;
                        }

                        connections.write ( fieldName, propertyName, true );

                        handleMap [ handle ] = true;
                    }
                }
            }
        }

        interfaceObject.prototype.removeDependencies = function ( handle ) {

            var connections = this.connections [ handle ];

            var empty;
            
            if
                ( connections != null )
            {
                for ( var fieldName in connections.fields ) {

                    for ( var propertyName in connections.fields [ fieldName ] ) {

                        var handleMap = this.dependencies.read ( fieldName, propertyName );
                    
                        delete handleMap [ handle ];

                        empty = true;

                        for ( var h in handleMap ) { empty = false; break; }

                        if
                            ( empty )
                        {
                            // This item has no dependent processes...

                            this.dependencies.remove ( fieldName, propertyName );
                        }
                    }
                }
                
                delete this.connections [ handle ];
            }
        }

        interfaceObject.prototype.detatch = function ( object ) {

            var handle = object.interfaceHandle;

            if
                ( handle != null )
            {
                this.removeDependencies ( handle );
            
                delete this.readWrite [ handle ];
                
                this.objects.removeHandle ( handle );
            }

            object.bDetatched = true;
        }

        interfaceObject.prototype.read = function ( fieldName, propertyName ) {
        
            if
                ( this.clientHandle == null )
            {
                alert ( "Illegal out of context read to " + fieldName + "." + propertyName );
                
                return null;
            }
            else
            {
                this.clientReads.write ( fieldName, propertyName, true );

                if ( this.clientWrites != null ) {
                    if ( this.clientWrites.isDefined ( fieldName, propertyName ) ) {
                        //alert ( "CHANGED FIELD READ AFTER WRITE\r\n\r\nFIELD " + fieldName + ":" + propertyName + " WAS '" + this.database.read ( fieldName, propertyName ) + "' IS NOW '" + this.clientWrites.read ( fieldName, propertyName )+ "'" );
                        return this.clientWrites.read ( fieldName, propertyName );
                    }
                }

                return this.database.read ( fieldName, propertyName );
            }
        }
    
        interfaceObject.prototype.write = function ( fieldName, propertyName, value ) {
        
            if
                ( this.clientHandle == null )
            {
                alert ( "Illegal out of context write to " + fieldName + "." + propertyName );
                
                return null;
            }
            else
            {
                if
                    ( this.readWrite [ this.clientHandle ] )
                {
                    if
                        ( value == this.database.read ( fieldName, propertyName ) )
                    {
                        this.clientWrites.remove ( fieldName, propertyName );
                    }
                    else
                    {
                        this.clientWrites.write ( fieldName, propertyName, value );
                    }
                }
                else
                {
                    alert ( "Read only process attempted to write to " + fieldName + "." + propertyName );
                }
            }
        }

        interfaceObject.prototype.applyChanges = function ( changes ) {

            for ( var fieldName in changes.fields ) {

                var fieldObject = changes.fields [ fieldName ];

                for ( var propertyName in fieldObject ) {
                        
                    var value = fieldObject [ propertyName ];

                    if
                        ( this.database.read ( fieldName, propertyName ) != value )
                    {
                        this.database.write ( fieldName, propertyName, value );

                        if
                            ( this.dependencies.isDefined ( fieldName, propertyName ) )
                        {
                            var handleMap = this.dependencies.read ( fieldName, propertyName );

                            for ( var h in handleMap ) {

                                if
                                    ( this.readWrite [ h ] )
                                {
                                    this.dependentProcessHandles [ h ] = true;
                                }
                                else
                                {
                                    this.dependentObserverHandles [ h ] = true;
                                }
                            }
                        }
                    }
                }
            }
        }

        interfaceObject.prototype.notifyChanges = function () {

            var done = true;

            this.updating = true;
            this.quiet = false;

            for ( var i in this.dependentProcessHandles ) { done = false; break; }

            if
                ( ! done )
            {
                // Let all the objects make their changes...

                var updates = new dataStoreObject ();
                var change = false;

                for
                    ( var handle in this.dependentProcessHandles )
                {
                    if
                        ( this.connections [ handle ] != null )
                    {
                        this.clientHandle = handle;
                        this.clientWrites = new dataStoreObject ();
                        this.clientReads = new dataStoreObject ();
                    
                        this.objects.getObject ( handle ).notifyChange ();

                        this.clientHandle = null;

                        this.removeDependencies ( handle );
                        this.addDependencies ( handle, this.clientReads.fields );

                        // Merge the changes and check for conflicts...

                        for ( var fieldName in this.clientWrites.fields ) {

                            var fieldObject = this.clientWrites.fields [ fieldName ];

                            for ( var propertyName in fieldObject ) {
                                    
                                var value = fieldObject [ propertyName ];

                                if
                                    ( updates.isDefined ( fieldName, propertyName ) )
                                {
                                    if
                                        ( value != updates.read ( fieldName, propertyName ) )
                                    {
                                        alert ( "Update conflict on " + fieldName + "." + propertyName );
                                    }
                                }
                                else
                                {
                                    updates.write ( fieldName, propertyName, value );
                                    change = true;
                                }
                            }
                        }
                    }
                }

                this.dependentProcessHandles = new Object ();

                if ( change ) this.applyChanges ( updates );

                done = true;

                for ( var i in this.dependentProcessHandles ) { done = false; break; }
            }

            if
                ( done )
            {
                for ( var i in this.dependentObserverHandles ) { done = false; break; }

                if
                    ( ! done )
                {
                    for ( var handle in this.dependentObserverHandles ) {

                        if
                            ( this.connections [ handle ] != null )
                        {
                            this.clientHandle = handle;
                            this.clientWrites = null;
                            this.clientReads = new dataStoreObject ();

                            this.objects.getObject ( handle ).notifyChange ();

                            this.clientHandle = null;

                            this.removeDependencies ( handle );
                            this.addDependencies ( handle, this.clientReads.fields );
                        }
                    }

                    this.dependentObserverHandles = new Object ();

                } else {

                    if
                        ( this.thingsToDo.count () )
                    {
                        var thingToDo = this.thingsToDo.get ();

                        if
                            ( thingToDo.action == "update" )
                        {
                            this.applyChanges ( thingToDo.changes );

                            this.notifyChanges ();
                        }
                        else
                        if
                            ( thingToDo.action == "attatch" )
                        {
                            var object = thingToDo.object;

                            if ( ! object.bDetatched ) {

                                var handle = object.interfaceHandle;
                                var readWrite = thingToDo.readWrite;

                                if ( handle == null ) {

                                    handle = this.objects.newHandleForObject ( object );
                                    object.oInterface = this;
                                    object.interfaceHandle = handle;
                                }

                                if ( this.connections [ handle ] == null ) {

                                    this.connections [ handle ] = new dataStoreObject ();
                                }

                                this.readWrite [ handle ] = readWrite;

                                if
                                    ( readWrite )
                                {
                                    this.dependentProcessHandles [ handle ] = true;
                                }
                                else
                                {
                                    this.dependentObserverHandles [ handle ] = true;
                                }
                                this.notifyChanges ();
                            }
                        }
                    }
                    else
                    {
                        this.quiet = true;
                    }
                }
            }

            this.updating = false;
        }
        
        interfaceObject.prototype.attatch = function ( object, readWrite ) {

            this.thingsToDo.put ( { action:"attatch", object:object, readWrite:readWrite } );
        }

        interfaceObject.prototype.update = function ( changes ) {

            this.thingsToDo.put ( { action:"update", changes:changes } );
        }
        
        interfaceObject.prototype.syncUpdate = function ( changes ) {

            this.fullUpdate ();

            this.update ( changes );

            this.fullUpdate ();
        }

        interfaceObject.prototype.fullUpdate = function () {

            do { this.notifyChanges (); } while ( ! this.quiet );
        }

        interfaceObject.prototype.undo = function () {
        
            this.fullUpdate ();

            this.database.undo ( this, "applyGlobalChange" );
        }
        
        interfaceObject.prototype.redo = function () {
        
            this.fullUpdate ();

            this.database.redo ( this, "applyGlobalChange" );
        }
        
        interfaceObject.prototype.applyGlobalChange = function ( fields ) {

            if
                ( this.updating )
            {
                alert ( "ERROR: global change during update" );
            }
            else
            {
                var handles = new Object ();

                for ( var fieldName in fields ) {

                    var field = fields [ fieldName ];

                    for ( var propertyName in field ) {

                        var handleMap = this.dependencies.read ( fieldName, propertyName );
                        
                        if
                            ( handleMap != null )
                        {
                            for ( var h in handleMap ) {
                            
                                handles [ h ] = true;
                            }
                        }
                    }
                }

                this.updating = true;

                for ( var h in handles ) {
                
                    if
                        ( this.connections [ h ] )
                    {
                        this.clientHandle = h;
                        this.clientWrites = new dataStoreObject ();
                        this.clientReads = new dataStoreObject ();

                        this.objects.getObject ( h ).notifyChange ();
                        
                        this.clientHandle = null;

                        this.removeDependencies ( h );
                        this.addDependencies ( h, this.clientReads.fields );
                    }
                }

                this.updating = false;
            }
        }

        interfaceObject.prototype.newFieldName = function () {
        
            return this.database.newFieldName ();
        }

        interfaceObject.prototype.observedFieldNames = function () {

            // This is an ABBOMINATION and must be removed as soon as possible

            var result = new Array ();

            for ( var fieldName in this.dependencies.fields ) {

                if
                    ( this.dependencies.isFieldDefined ( fieldName ) )
                {
                    result [ result.length ] = fieldName;
                }
            }

            return result;
        }

        interfaceObject.prototype.fnStartTransaction = function () {
            this.database.startTransaction ();
        }
        interfaceObject.prototype.fnEndTransaction = function () {
            return this.database.endTransaction ();
        }
        interfaceObject.prototype.fnUndo = function () {
            this.undo ();
        }
        interfaceObject.prototype.fnRedo = function () {
            this.redo ();
        }

//--------------------------------------------------------

if ( debugTrace ) document.write("Step 2<br>");  


    
	/**
		DocumentManager is the main class for managing objects and events
		within an HTML window. Each frame can 		
		 @constructor 
	**/
    function DocumentManager ()
    {
    }
    
	var documentManager = new DocumentManager ();
	
	documentManager.dateCreated = ""+new Date()+""+Math.random();
    
	/**
        manages all handles allocated but this document manager. a handle 
        is attatched to each DOM element managed by the document manager
        call backs are routed from the DOM to the document manager using handles
        This I think avoid the circular reference issue which would otherwise cause a 
        memory leak.
        
        @type handleManagerObject
    **/
    DocumentManager.prototype.childManager = null;
    
    /**
        The parent document manager, if we are a child frame, or a floating frame window,
        we will have a parent manager, otherwise not.
        
        @type DocumentManager
    **/
    DocumentManager.prototype.parent = null;
    
    /**
        contains the handle of this window in it's parent. I think this mostly 
        @type string
        
    **/
    DocumentManager.prototype.handleInParent = null;
    
    /**
        contains the "database" of field values, there is only one of these, 
        so if this is a child document manager, we just reference our parents database
        @type databaseObject
    **/
    
    DocumentManager.prototype.database = null;
    
    /**
        this is the "interface" object though which we interact with the database, 
        again it seems there is only one of these, so if have a parent we reference 
        the parent one.
        
    **/
    
    DocumentManager.prototype.oInterface = null;
    
    /**
        When binding to objects, we use this prefix for all attributes, to provide a "namespace"
        which avoids clashes. It has value "ALSi"
        
        @type string
    **/
    DocumentManager.prototype.attributePrefix = "ALSi";
    
    
    /**
        not sure yet
    **/
    DocumentManager.prototype.attactments = null;
    
    /**
        a list of functions to be performed on startup, you can add to this list by calling 
        addStartup
    **/
    
    DocumentManager.prototype.onresizes = null;
    
    /**
        a list of functions to be performed when the document is resized
        we do this becuase not all browsers support onsize
    
        @type array
    **/

    DocumentManager.prototype.startups = null;
    
    /**
        a list of functions to be performed on shutdown
    
        @type array
    **/


    DocumentManager.prototype.shutdowns = null;
    
    /**
        err not sure yet
        
    **/
    DocumentManager.prototype.windows = null;
    
    /**
        holds function constructors for class of element
        which the document manager could bind to
    **/
    DocumentManager.prototype.constructors = null;
    
    DocumentManager.prototype.types = null;
    
    /**
        holds the list of tasks to be sheduled 
    **/
    DocumentManager.prototype.tasks = null;
    
    /**
        holds a set of global values 
    **/
    DocumentManager.prototype.globals = null;
    
    /**
        translates codes into langauge specific strings, 
        useful for validation prompts for example ( eg NotANumber )
    **/
    
    DocumentManager.prototype.translations = null;
    
	/**
		@private
		called later in this file, this first phase of intialisation could be
		moved to the constructor, since I made this an object.
	
	**/

    DocumentManager.prototype.buttonState = "";
    
    /**
        set in the mouseDown event to have the state of the mouse down button
        when the mouse was clicked, cleared in the mouse up event.
        
        This is necessary becuase mozilla will only let us read the mouse button 
        state when the mouse button goes down.
        
        it can have the value "" for none
        "left" for left button.
        "right" for the right button.
        
    **/
	
    DocumentManager.prototype.getInterface = function() {
        return this.oInterface;
    }
    
    DocumentManager.prototype.initialise = function () {
        trace("","initialise called");
        this.ready = false;

        this.childManager = new handleManagerObject ();
        this.parent = this.getParentManager ();

        if
            ( this.parent != null )
        {
            this.handleInParent = this.parent.attatchChild ( this );
            
            this.database = this.parent.database;
            this.oInterface = this.parent.getInterface();
        }
        else
        {
            this.database = new databaseObject ();
            this.oInterface = new interfaceObject ( documentManager.database );
        }

        this.attributePrefix = "ALSi";
        
        this.attatchments = new Object ();
        this.newProcesses = new Array ();
        this.startups = [];
        this.shutdowns = [];
        this.onresizes = [];
        this.windows = new Array ();

        this.constructors = new Object ();
        this.types = new Object ();

        this.objects = new Array ();
        this.tasks = new Array ();

        this.globals = new Object ();
        this.translations = new Object ();

        this.setTimer ();
        
        // was onbeforeunload - which is ie specific
        window.onunload = this.doUnload;
        
        
    }

	
	/**
		returns the transaction manager for this document manager.
		I'm guessing that only the top level document manager has one of
		these, but I'm not sure yet.
	**/
    DocumentManager.prototype.getTransactionManager = function () {
        var tm = this.transactionManager;
        if ( tm == null ) {
            tm = this.findNamedObject ( "transactionManager" );
        }
        if ( tm == null ) {
            tm = this.oInterface;
        }
        return tm;
    }

	/**
		set's the global property "name" to the value object, if a function
		is passed, then when we get the global property the corresponding 
		function is called
	**/
    DocumentManager.prototype.setGlobalProperty = function ( name, object ) {

        this.globals [ name ] = object;
    }

	/**
		gets the value of a global property, if the property is a function,
		the function is evaluated to determine the result.
	**/

    DocumentManager.prototype.getGlobalProperty = function ( name ) {

        var object = this.globals [ name ];

        if (  object != null ) {

            if ( typeof object == "function" ) {

                return object ();
            }
            else
            {
                return object;
            }
        }

        return ( void 0 );
    }

	/**
		Gets the value of a global properties, from this, and all child 
		managers. ( maybe there is a child manager for each frame )  
	**/
	
    DocumentManager.prototype.getGlobalPropertiesRecursive = function ( name ) {

        result = [];
        var value = this.getGlobalProperty ( name );

        if
            ( value != null )
        {
            result [ 0 ] = value;
        }

        for ( var h in this.childManager.objects ) {

            result = result.concat ( this.childManager.objects [ h ].getGlobalPropertiesRecursive ( name ) );
        }

        return result;
    }

	/**
		attach the given child 
	**/
    DocumentManager.prototype.attatchChild = function ( object ) {

        return this.childManager.newHandleForObject ( object );
    }

	/**
		returns the top level document manager
	**/
    DocumentManager.prototype.topManager = function () {

        if ( this.parent == null ) return this;

        return this.parent.topManager ();
    }

	/**
		returns a "string id" for this document manager
	**/
	
    DocumentManager.prototype.getId = function () {

        if ( this.handleInParent == null ) {
        
            return "";
        }
        else
        {
            var result = this.parent.getId ();
            
            if ( result != "" ) result += ",";
            
            return result + this.handleInParent;
        }
    }
	
	/**
		returns a document manager given a string id
	**/
	
    DocumentManager.prototype.getFromId = function ( id ) {

        if ( this.parent != null ) {
        
            return this.parent.getFromId ( id );
        }
        else
        {
            var result = this;
            var handles = id.split ( "," );

            for ( var i = 0; i < handles.length; i++ ) {

                var result = result.childManager.getObject ( handles [ i ] );

                if ( result == null ) break;
            }

            return result;
        }
    }

	/**
		not sure yet
	**/
    DocumentManager.prototype.childReady = function ( handle ) {

        var object = this.childManager.getObject( handle );

        for ( var h in this.windows ) {

            var window = this.windows [ h ];

            if ( window != null )
            {
                if ( window [ "documentManager" ] == object )
                {
                    this.objects [ h ].loaded ( window );
                }
            }
        }
    }

	/**
		finds a child given a handle
	**/
	
    DocumentManager.prototype.findChild = function ( handle ) {

        var object = this.childManager.getObject ( handle );

        for ( var h in this.windows ) {

            var window = this.windows [ h ];

            if
                ( window != null )
            {
                if
                    ( window [ "documentManager" ] == object )
                {
                    return this.objects [ h ];
                }
            }
        }

        return null;
    }

	/**
		closes the given child handle. ( the objects close method is called )
	**/
    DocumentManager.prototype.closeMe = function ( handle ) {
        
        var object = this.findChild ( handle );

        if ( object != null ) object.close ();

        this.addImperativeTask ( new Function ( "documentManager.resetGlobalFocus();" ) );
    }

	/**
		moves the given document manager to dx and dy ?
		@public 
	**/
	
    DocumentManager.prototype.move = function ( dx, dy ) {

        if
            ( this.parent )
        {
            this.parent.moveMe ( this.handleInParent, dx, dy );
        }
    }

	/**
		moves the given child object to x and y.
		@public 
		
	**/
    DocumentManager.prototype.moveMe = function ( handle, dx, dy ) {

        var object = this.findChild ( handle );

        if ( object != null ) object.move ( dx, dy );
    }

	/**
		changes the size of the document manager window to dx,dy ?
		can only be used if we have a parent document manager.
	**/
	
    DocumentManager.prototype.size = function ( dx, dy ) {

        if
            ( this.parent )
        {
            this.parent.sizeMe ( this.handleInParent, dx, dy );
        }
    }

	/**
		resize the given child object, to size dx,dy, by calling the child objects
		size function.
	**/
	
    DocumentManager.prototype.sizeMe = function ( handle, dx, dy ) {

        var object = this.findChild ( handle );

        if ( object != null ) object.size ( dx, dy );
    }

	/**
		closes the document manager window, works by deferring to the parent window.
	**/
	
    DocumentManager.prototype.close = function () {

        if
            ( this.parent != null )
        {
            this.parent.closeMe ( this.handleInParent );
        }
    }

	/**
	    returns the *object* (floatingFrameObject) belonging to the outer frame's DM
        which houses this DM's frame- or null if this DM's frame is not a DM
        floating frame.
	**/
	
    DocumentManager.prototype.getContainer = function () {

    
        if
            ( this.parent != null )
        {
            return this.parent.findChild ( this.handleInParent );
        }

        return null;
    }

	/**
        Returns the outer most *object* (floatingFrameObject) in an un-broken chain of
        nested floating frames (as getContainer- but iterates if the container's DM is
        its self contained in an outer floating frame).
        UNTESTED.
    **/

    DocumentManager.prototype.getTopContainer = function () {


        var result = this.getContainer ();
        var next = result;

        while ( next != null ) {

            next = result.manager.getContainer ();

            if ( next != null ) result = next;
        }

        return result;
    }

    
    /**
		return next "available" zIndex ( from 10 )
    **/
    
    DocumentManager.prototype.nextZIndex = function () {

        if ( this.zIndex == null ) this.zIndex = 10;

        return this.zIndex++;
    }


	/**
		detaches the given child
	**/
    DocumentManager.prototype.detatchChild = function ( handle ) {

        this.childManager.removeHandle ( handle );
    }

	/**
		detaches the document manager from a window, called when the window
		is closing.
	**/
	
    DocumentManager.prototype.detatch = function () {

        trace("","DocumentManager.detatch called");
        this.doFunctions ( this.shutdowns );
        this.clearHandlers ();

        if
            ( this.parent != null )
        {
            this.parent.detatchChild ( this.handleInParent );

            for ( var h in this.attatchments ) {
                this.oInterface.detatch ( this.attatchments [ h ] );
            }

            if
                ( this.focusObject != null )
            {
                this.setGlobalFocus ( null, null );
            }

            if ( window.disconnectAll !== ( void 0 ) ) {

                disconnectAll ();
            }
        }
    }

	/**
		called when the window is unloaded, just invokes detatch
	**/

    DocumentManager.prototype.doUnload = function () {

        trace("","DocumentManager.doUnload called");
        documentManager.detatch ();
    }


	/**
		not really sure of the full implications of this
		calls the list of functions provided, each function is done
		within the context of a new update object, and has a new 
		transactionBaseObject
	**/


    DocumentManager.prototype.doFunctions = function ( list ) {

        for ( var i = 0; i < list.length; i++ ) {

            var transactionFunction = list [ i ];
            var updates = new updateObject ();
            var o = new transactionBaseObject ( updates, this.database );

            o.f = transactionFunction;

            o.f ();

            this.applyChanges ( updates );
        }
    }

	/**
		called when the document manager is to start, ie when the window in which the
		document manager is loaded.
	**/
	
    DocumentManager.prototype.start = function ( documentElement ) {
        if ( window.onunload == this.doUnload ) window.onunload = null;

        // new function call which document manager will call before it starts
        preDocumentManagerStart();
        
        this.hoverObject = null;
        this.selectedObject = null;
        this.focusObject = null;
        
        this.hoverRectangle = null;

        this.documentElement = documentElement.body;
        this.rootObject = this.create ( "container" );

        this.rootObject.start ( this.documentElement );

        this.attatchNewProcesses ();

	
        documentElement.onclick = this.doClick;
        documentElement.ondblclick = this.doDoubleClick;
        documentElement.onmousedown = this.doMouseDown;
        documentElement.onmousemove = this.doMouseMove;
        documentElement.onmouseup = this.doMouseUp;
        documentElement.ondragstart = this.doDragStart;
        documentElement.onselectstart = this.doSelectStart;

        if ( document.onkeypress == null )
        {
            onkeypress = this.doKeyPress;
        }

        documentElement.onkeydown = this.doKeyDown;
        documentElement.onkeyup = this.doKeyUp;
        
        // put the resize handler on the window instead of the document element.
        
        window.onresize = this.doResize;
        
        // was document.onunload - changed to window.onunload
        window.onunload = this.doUnload;
        
        if ( this.parent != null )
        {
			trace(" childReady ");
            this.parent.childReady ( this.handleInParent );
        }

        this.doFunctions ( this.startups );

        this.ready = true;

        window.onfocus = this.windowGetsFocus;

        if ( this.rootObject.first == null )
        {
            this.focusStarted = true;
        }
        else
        {
            var bBounceFocus = false;
            var bBodyHasFocus = false;
            var elFocus = document.activeElement;
            
            /***document.activeElement***/
            if (elFocus == null)
            {
                elFocus = document.body;
                //alert(elFocus.tagName);
            }
            if ( elFocus != null ) {
                if ( elFocus.tagName != null ) {
                    if ( elFocus.tagName == "BODY" ) {
                        bBodyHasFocus = true;
                    } else {
                        var strHandle = this.getElementHandle ( elFocus );
                        if ( strHandle != null ) {
                            var object = this.getObject ( strHandle );
                            if ( object != null ) {
                                if ( object.localFocusElement == elFocus ) {
                                    bBounceFocus = true;
                                }
                            }
                        }
                    }
                }
            }
            if ( bBounceFocus ) {
                window.focus ();
            } else {
                this.focusStarted = true;
                if ( bBodyHasFocus ) {
                   // put back document.selection.empty ();
                }
            }
        }

        if ( this.doAfterLoad !== ( void 0 ) ) this.doAfterLoad ();
    }

	/** returns the version of the document manager 
	**/
    DocumentManager.prototype.getVersion = function () { return 1.0 }

	/**
		returns the parent document manager - or maybe null ?
	**/
    DocumentManager.prototype.getParentManager = function () {

        if
            ( parent != self )
        {
            if
                ( parent.documentManager != null )
            {
                if
                    ( parent.documentManager.getVersion != null )
                {
                    if
                        ( parent.documentManager.getVersion () == this.getVersion () )
                    {
                        return parent.documentManager;
                    }
                }
            }
        }
    }
    
    /***
		registers a class of "document manager- managed element", and associates a construtor for this class
		this is related to how binding is done.
    ***/
    DocumentManager.prototype.registerClass = function ( name, constructor ) {
    
        name = name.toLowerCase ();

        if
            ( this.constructors [ name ] != null )
        {
            alert ( "class name " + name + " re-registered." );
        }

        this.constructors [ name ] = constructor;
        

    }

	/***
		registers a type with the documents manager, provides a means of
		abstracting class names ? not sure of the use yet.
	**/
    DocumentManager.prototype.registerType = function ( name, constructor ) {

        name = name.toLowerCase ();

        if
            ( this.types [ name ] != null )
        {
            alert ( "type name " + name + " re-registered." );
        }

        this.types [ name ] = constructor;
    }

	/***
		returns the constructor for a given type name
	**/

    DocumentManager.prototype.getTypeConstructor = function ( name ) {

        return this.types [ name.toLowerCase () ];
    }

	/***
		instructs the document manager to manage a given object, and sets
		its handle and manager properties
	
	***/
    DocumentManager.prototype.manage = function ( object ) {

        var newHandle = this.objects.length;
        this.objects [ newHandle ] = object;
        object.handle = newHandle;
        object.manager = this;

//		alert ( "DM: creating " + newHandle );
    }

	/***
		creates an instance of a given "document manager" class of object
		and manages it.
	***/

    DocumentManager.prototype.create = function ( name ) {
    
        name = name.toLowerCase ();

        var constructor = this.constructors [ name ];
        
        if ( constructor == null )
        {
            alert ( "class name " + name + " not registered." );
        }
        else
        {
            var object = new constructor ();

            this.manage ( object );

            return object;
        }
        
        return null;
    }


	/**
		stops the document manager managing the object with the given handle.
		
	**/
	
    DocumentManager.prototype.remove = function ( handle ) {

        if
            ( this.objects [ handle ] == null )
        {
            alert ( "@@@" );
        }
        else
        {
            var object = this.objects [ handle ];

            // alert ( "DM: removing " + handle );

            if ( object.parent != null ) {

                object.parent.remove ( object );
            }

            if
                ( this.focusObject == object )
            {
                this.setGlobalFocus ( this, null );
                object.focus = false;
            }

            if ( this.selectedObject == object ) {
                this.setSelectedObject ( null );
            }

            if ( this.hoverObject == object ) {
                this.hoverObject = null;
                this.updateHover ();
            }
            
            delete this.objects [ handle ];

            if
                ( this.windows [ handle ] != null )
            {
                delete this.windows [ handle ];
            }

            if
                ( this.attatchments [ handle ] != null )
            {
                this.oInterface.detatch ( this.attatchments [ handle ] );

                delete this.attatchments [ handle ];
            }
        }
    }

	/**
		schedules removal of the specified handle 
	**/
    
    DocumentManager.prototype.removeLater = function ( handle ) {

        this.addTask ( new Function ( "documentManager.remove ( " + handle + " );" ), -2 );
    }


	/***
		gets an object given a handle
	***/
    DocumentManager.prototype.getObject = function ( handle ) {
		if (this == null)
		{
			
			//debugger;
			return null;		
		}
		if (this.objects == null)
		{
			
			//debugger;
			return null;
		}
		else
        {
			var o = this.objects [ handle ]; 
			if
				(o==null)
			{
				//trace("handle lookup failed");
				//trace(""+this);
				//trace( ""+this.objects );
			}
			return o;
		}
    }
    
    /**
		undo or redoes a transaction, typically a field change for example
    **/
    
    DocumentManager.prototype.globalUndo = function ( doUndo ) {

        this.getTransactionManager ().fnEndTransaction ();

        if
            ( doUndo )
        {
            this.getTransactionManager ().fnUndo ();
        }
        else
        {
            this.getTransactionManager ().fnRedo ();
        }
        
        if
            ( this.hoverObject != null )
        {
            this.hoverObject = null;
            this.updateHover ();
        }

        this.getTransactionManager ().fnStartTransaction ();
    }
    
    /**
		creates a call back function to a managed object
    **/
    DocumentManager.prototype.createCallback = function ( object, method, parameter ) {
		
		//var o = this.getObject ( object.handle );
		//if
		//	(o != object )
		//{
		//}
		//else
		//{
		//    alert("createCallBack ok");
		//}
		
		// so in safari - the problem appears to be that this call to create a function, does not bind to the document manager we wish it to, instead
		// document manager seems to be evaluated - when the callback is made, and can be different to the context in which the callback was created.
		
		var t = "return documentManager.callback2 ( " + object.handle + ", '" + method + "', '" + parameter + "','"+documentManager.dateCreated+"' )";
        return new Function ( t );
    }

    /**
		schedules a task to be done
    **/

    DocumentManager.prototype.addTask = function ( functionCall, priority ) {

        this.addTaskObject ( { object:functionCall, priority:priority } );
    }

    /**
		schedules a task which must be done ?
    **/

    DocumentManager.prototype.addImperativeTask = function ( functionCall ) {

        this.addTaskObject ( { object:functionCall, imperative:true } );
    }

	/***
		helper function to assist in implementing  addTask and addImperative task
	***/
	
    DocumentManager.prototype.addTaskObject = function ( taskObject ) {
        //trace("fish", "addtaskobject is called");
        //trace("fish", taskObject.object.toString());
        //trace("fish", taskObject.method? taskObject.method:"");
        if
            ( taskObject.priority == null )
        {
            taskObject.priority = 0;
        }
        if
            ( taskObject.imperative == null )
        {
            taskObject.imperative = false;
        }

        this.tasks [ this.tasks.length ] = taskObject;
    }


	/***
	   should be called when the contents of a page have been changed externally to notify the
	   document manager of the change I think.
	***/
	
    DocumentManager.prototype.viewUpdated = function () {

        if
            ( this.parent != null )
        {
            this.size ();
        }
        else
        {
            documentManager.updateHoverRectangle ();
            documentManager.updateFocusRectangle ();
        }
    }

	/***
		performs the outstanding tasks - this is scheduled on a timer
	***/
	
    DocumentManager.prototype.doTasks = function () {
        
        if
            ( this.tasks.length != 0 )
        {
			trace("fish", "called doTasks - something to do");
            var task = null;
            var newTasks = [];
            var tasks = [];
            var pTask = false;
            var maxPriority;

            for ( var i = 0; i < this.tasks.length; i++ ) {

                with ( this.tasks [ i ] ) {

                    if
                        ( ! imperative )
                    {
                        if ( ! pTask ) {

                            pTask = true;
                            maxPriority = priority;
                        }
                        else
                        if
                            ( priority > maxPriority )
                        {
                            maxPriority = priority;
                        }
                    }
                }
            }

            for ( var i = 0; i < this.tasks.length; i++ ) {

                var task = this.tasks [ i ];

                if
                    ( task.imperative )
                {
                    tasks [ tasks.length ] = task;
                    done = true;
                }
                else
                {
                    var done = false;

                    if
                        ( pTask )
                    {
                        if
                            ( task.priority == maxPriority )
                        {
                            pTask = false;
                            tasks [ tasks.length ] = task;
                            done = true;
                        }
                    }

                    if
                        ( ! done )
                    {
                        newTasks [ newTasks.length ] = task;
                    }
                }
            }

            this.tasks = newTasks;

            for ( var i = 0; i < tasks.length; i++ ) {

                var task = tasks [ i ];
                var result;

                if
                    ( task.method == null )
                {
                    //trace("fish", task.object.toString());
                    result = task.object ();
                }
                else
                {
                    trace("fish", "calling method "+ task.method);
                    result = task.object [ task.method ] ( task.parameter );
                }

                if
                    ( result == "repeat" )
                {
                    this.addTaskObject ( task );
                }
            }
        }

        if
            ( this.parent == null )
        {
            this.oInterface.notifyChanges ();
        }

        if
            ( this.timeOut != null )
        {
            if
                ( ( ( new Date () ).getTime () - this.lastTime ) > this.timeOut )
            {
                this.timeOut = null;

                if
                    ( this.onTimeOut != null )
                {
                    this.onTimeOut ();
                }
            }
        }
    }

	/**
		tell the document manager that this is the legend editor
	**/
    DocumentManager.prototype.setIsLegendEditor = function () {
        this.bIsLegendEditor = true;
    }
    
    /***
		returns true if this is the legend editor
    ***/
    
    DocumentManager.prototype.getIsLegendEditor = function () {
        return this.bIsLegendEditor == true;
    }
    
    /***
		sets the timeout function to be called if there is no
		activity for a number of seconds
    ***/
    DocumentManager.prototype.setOnTimeOut = function ( action, seconds ) {
        this.lastTimeOutHandler = action;
        this.doSetOnTimeOut ( action, seconds, false );
    }
    
    /***
		call a function when activity is detected.
    ***/
    
    DocumentManager.prototype.setOnActivity = function ( action ) {
        this.lastActivityHandler = action;
        this.doSetOnActivity ( action, false );
    }


    /***
		removes the timeout and inactivity handlers.
    ***/

    DocumentManager.prototype.clearHandlers = function () {
        this.doSetOnTimeOut ( this.lastTimeOutHandler, 0, true );
        this.doSetOnActivity ( this.lastActivityHandler, true );
    }
    
    /***
		something to do with timeouts ???
    ***/
    DocumentManager.prototype.doSetOnTimeOut = function ( action, seconds, bRemove ) {
        if ( this.parent != null ) {
            if ( ! this.parent.getIsLegendEditor () ) {
                this.parent.doSetOnTimeOut ( action, seconds, bRemove );
                return;
            }
        }
        if ( bRemove ) {
            if ( this.onTimeOut == action ) {
                this.timeOut = null;
                this.onTimeOut = null;
            }
        } else {
            if
                ( ( seconds != null ) && ( action != null ) )
            {
                this.lastTime = new Date ();
                this.timeOut = seconds * 1000;
                this.onTimeOut = action;
            }
            else
            {
                this.timeOut = null;
                this.onTimeOut = null;
            }
        }
    }

    /***
		something to do with activity
    ***/

    DocumentManager.prototype.doSetOnActivity = function ( action, bRemove ) {
        if ( this.parent != null ) {
            if ( ! this.parent.getIsLegendEditor () ) {
                this.parent.doSetOnActivity ( action, bRemove );
                return;
            }
        }
        if ( bRemove ) {
            if ( action == this.onActivity ) {
                this.onActivity = null;
            }
        } else {
            if
                ( action == null )
            {
                this.onActivity = null;
            }
            else
            if
                ( this.onActivity == null )
            {
                this.onActivity = action;
            }
        }
    }

    //    setNamedItem and removeNamedItem set and unset a 'local' value
    //    for a given arbitary named item.
    //    getNamedItemsGlobal returns a LIST of all such item values (with the
    //    specified name) that are currently set by any DMs across the entire frame
    //    hierarchy (from the root down).
    //    See other parts of the DM for internal use of 'named items'

    DocumentManager.prototype.setNamedItem = function ( name, item ) {

        if ( this.localItems == null ) this.localItems = {};

        this.localItems [ name ] = item;
    }


    /**
      removes a "local item"  
    **/
    DocumentManager.prototype.removeNamedItem = function ( name ) {

        if ( this.localItems != null ) {
        
            delete this.localItems [ name ];
        }
    }

    /**
        returns a list of name item values ? - wonder how this is used
    **/
    DocumentManager.prototype.getNamedItemsRecursive = function ( name ) {

        var result = [];

        if ( this.localItems != null ) {

            var value = this.localItems [ name ];

            if ( value != null ) result [ result.length ] = value;
        }

        for ( var h in this.childManager.objects ) {

            result = result.concat ( this.childManager.objects [ h ].getNamedItemsRecursive ( name ) );
        }

        return result;
    }

    /**
        gets a globally named item
    **/
    DocumentManager.prototype.getNamedItemsGlobal = function ( name ) {

        if ( this.parent != null ) {

            return this.parent.getNamedItemsGlobal ( name );
        }

        return this.getNamedItemsRecursive ( name );
    }

	/***
		called to set a timer to invoke the documentManagers doTimer function
	
	***/
	
    DocumentManager.prototype.setTimer = function () {

        //trace("","setTimer");
        var time = 100;

        if ( this.tasks.length != 0 ) time = 10;

        if ( this.timer != null ) delete this.timer;
        
        //trace("","setTimeout");
        this.timer = window.setTimeout ( "documentManager.doTimer()", time );
        //trace("","did setTimeout");
    }
    
    /***
		this is regualarly called by a timer function.
		it's task is to run all scheduled tasks, and then
		schedule itself to be run again
    ***/
    
    DocumentManager.prototype.doTimer = function () {
        this.doTasks ();
        this.setTimer ();
    }

	/***
		????
	***/
    DocumentManager.prototype.applyChanges = function ( updates ) {
        //debugger;
        this.oInterface.syncUpdate ( updates );
    }

	/***
		I think fields have some standard properties, which we can use to work out if changes hae been 
		made ???
	***/
    DocumentManager.prototype.registerFieldProperties = function ( fieldName, properties ) {

        var update = new updateObject ();

        update.write ( fieldName, "checked", false );
        update.write ( fieldName, "edit", false );
        update.write ( fieldName,"changed", false );

        if
            ( properties != null )
        {
            for ( var propertyName in properties ) {
            
                update.write ( fieldName, propertyName, properties [ propertyName ] );
            }
        }

        this.oInterface.syncUpdate ( update );
    }

	/***
		I think fields have some standard properties, which we can use to work out if changes have been 
		made ???
	***/

    DocumentManager.prototype.makeTypeObjectForElement = function ( element, fieldName ) {

        var parameters = null;
        var objectLiteral = element.getAttribute ( this.attributePrefix + "TypeMap" );

        if
            ( ( objectLiteral != null ) && ( objectLiteral != "" ) )
        {
            eval ( "parameters = " + objectLiteral + ";" ); 
        }

        if
            ( parameters != null )
        {
            var type = parameters [ "Type" ];

            if
                ( type == null )
            {
                type = parameters [ "type" ];
            }
        }
        else
        {
            type = element.getAttribute ( this.attributePrefix + "Type" );
        }

        if
            ( type == null )
        {
            type = "default";
        }

        var constructor = this.getTypeConstructor ( type );

        if
            ( constructor == null )
        {
            alert ( "Standard type '" + type + "' not known" );
        }
        else
        {
            var validator = new constructor ();

            if ( type != "default" ) {

                var list = this.getFieldsByType ( type );

                list [ list.length ] = fieldName;
            }

            if
                ( parameters != null )
            {
                for ( var pName in parameters ) {

                    validator.parameters [ pName ] = parameters [ pName ];
                }
            }

            for ( var pName in validator.parameters ) {

                var value = element.getAttribute ( this.attributePrefix + pName );

                if
                    ( value != null )
                {
                    validator.parameters [ pName ] = value;
                }
            }

            return validator;
        }

        return null;
    }

    DocumentManager.prototype.registerFieldType = function ( fieldName, element ) {

        var validator = this.makeTypeObjectForElement ( element, fieldName );

        if
            ( validator != null )
        {
            validator.fieldName = fieldName;

            validator.initialise ();

            this.attatch ( validator, true );
        }
    }

    DocumentManager.prototype.getFieldsByType = function ( type ) {

        if ( this.parent ) {

            return this.parent.getFieldsByType ( type );
        }
        else
        {
            var key = type.toString ().toLowerCase ();

            if ( this.typeToField == null ) this.typeToField = {};

            if ( this.typeToField [ key ] == null ) this.typeToField [ key ] = [];

            return this.typeToField [ key ];
        }
    }

    DocumentManager.prototype.getBestFieldOfTypes = function ( types ) {

        var list = [];

        for ( var i = 0; i < types.length; i++ ) {

            var type = types [ i ];

            list = list.concat ( this.getFieldsByType ( type ) );
        }

        if
            ( list.length == 0 )
        {
            return null;
        }
        else
        if
            ( list.length > 1 )
        {
            var focusObject = this.getGlobalFocus ();

            if ( focusObject != null ) {

                if ( focusObject.fieldName != null ) {

                    for ( var i = 0; i < list.length; i++ ) {

                        if ( list [ i ] == focusObject.fieldName ) {

                            return list [ i ];
                        }
                    }
                }
            }
        }

        return list [ 0 ];
    }

    DocumentManager.prototype.attatch = function ( object, readWrite ) {

        if
            ( object.handle == null )
        {
            this.manage ( object );
        }

        this.oInterface.attatch ( object, readWrite );

        this.attatchments [ object.handle ] = object;
    }

    DocumentManager.prototype.attatchNewProcesses = function () {

        for ( var i = 0; i < this.newProcesses.length; i++ ) {

            this.attatch ( this.newProcesses [ i ].object, this.newProcesses [ i ].readWrite );
        }

        this.newProcesses = new Array ();
    }

    DocumentManager.prototype.addNewProcessObject = function ( processObject, readWrite ) {

        var i = this.newProcesses.length;

        this.newProcesses [ i ] = { object:processObject, readWrite:readWrite };
    }

    DocumentManager.prototype.addNewProcess = function ( processFunction, readWrite ) {

        var processObject = new processBaseObject ();

        processObject.notifyChange = processFunction;

        this.addNewProcessObject ( processObject, readWrite );
    }

    /*** 
        add's a rule. a rule is a function which reads data from the database and performs some
        action as a result. rules are executed each time the data upon which they are dependant changes.
        rules result in data being written back, such as marking fields valid or not
    ***/
    
    DocumentManager.prototype.addRule = function ( ruleFunction ) {
    
        this.addNewProcess ( ruleFunction, true );
    }
    
    /***
        add's a watch function,watch functions are like rules, but they don't make changes.
    ***/
    DocumentManager.prototype.addWatch = function ( watchFunction ) {
    
        this.addNewProcess ( watchFunction, false );
    }

    /***
        add's a startup function - a function which will be called when the documents is ready
    ***/
    DocumentManager.prototype.addStartup = function ( f ) {

        this.startups [ this.startups.length ] = f;
    }

    /***
        add's a function to be called when the document is resized.
    ***/

    DocumentManager.prototype.addOnResize = function ( f ) {

        this.onresizes [ this.onresizes.length ] = f;
    }

    /***
        adds a function to be called when the document is shutting down
        when the window is unloaded.    
    ***/
    DocumentManager.prototype.addShutdown = function ( f ) {

        //    Functions to be called when this window is unloaded.

        this.shutdowns [ this.shutdowns.length ] = f;
    }

    
    /**
        I think this is to do with applying a set of actions which
        are added as a unit to the undo stack ??
    ***/
    DocumentManager.prototype.apply = function ( transactionFunction ) {

        var updates = new updateObject ();
        var o = new transactionBaseObject ( updates, this.database );

        o.f = transactionFunction;

        o.f ();

        this.applyChanges ( updates );
    }


    /**
        puts the focus on the first control element.
    **/
    DocumentManager.prototype.focusOnFirstEditableControlElement = function () {

        var o = this.rootObject.getFirstEditableControl ();

        if ( o != null ) {

            o.pluginElement.focus();
        }
    }

    /** focuses and selects the first editable control element 
    **/
    DocumentManager.prototype.focusOnAndSelectFirstEditableControlElement = function () {

        var o = this.rootObject.getFirstEditableControl ();

        if ( o != null ) {

            o.pluginElement.focus();

            if ( o.pluginElement.select != null ) {

                o.pluginElement.select();
            }
        }
    }

    /**
        called when the window gets the focus - default does nothing
    **/
    DocumentManager.prototype.windowGetsFocus = function () {
    }
    
    /**
        called by a control when it recieves the focus - used to manage 
        the global focus
    **/
    DocumentManager.prototype.controlGetsFocus = function ( handle ) {
		trace("documentManager.controlGetsFocus "+handle);

        if
            ( this.ready )
        {
            var object = this.getObject ( handle );

            this.focusStarted = true;
            
            try
            {
                this.setGlobalFocus ( this, object );
            }
            catch
                (err)
            {
                trace("error setting global focus "+ err.message );
                //debugger;
                this.focusStarted = false;
            }
        }
    }
    
    /**
        called by a control when it looses the focus - used to manage 
        the global focus
    **/
    
    DocumentManager.prototype.controlLoosesFocus = function ( handle ) {
		trace("documentManager.controlLoosesFocus "+handle);
        if
            ( this.ready )
        {
            if
                ( ! this.focusStarted )
            {
                var object = this.getObject ( handle );

                this.focusStarted = true;

                if
                    ( object.localFocusElement != null )
                {
                    object.localFocusElement.focus ();
                }
            }
        }
        trace("end documentManager.controlLoosesFocus "+handle);

    }

    /**
        calls back the object with given handle,
        and will call the named method, passing the named parameter
        this indirected means of managing callbacks probably fixes the bad memory leaks which would occur if we used closures directly
    **/
    
	var MAX_DUMP_DEPTH = 2;

       

    function dumpObj(obj, name, indent, depth) {

              if (depth > MAX_DUMP_DEPTH) {

                     return indent + name + ": <Maximum Depth Reached>\n";

              }

              if (typeof obj == "object") {

                     var child = null;

                     var output = indent + name + "\n";

                     indent += "&nbsp;&nbsp;&nbsp;";

                     for (var item in obj)

                     {

                           try {

                                  child = obj[item];

                           } catch (e) {

                                  child = "<Unable to Evaluate>";

                           }

                           if (typeof child == "object") {

                                  output += ":object<br>\r\n"; /*+dumpObj(child, item, indent, depth + 1); */

                           } else {

                                  output += indent + item + ": " + child + "<br>\r\n";

                           }

                     }

                     return output;

              } else {

                     return obj;

              }

       }


    DocumentManager.prototype.callback2 = function ( handle, method, parameter, docManID ) {

        trace("documentManager.callback "+handle);
		if (method != null) trace("documentManager.callback "+method);
		
		var o;
		if
			(docManID != this.dateCreated)
		{
			// so strangely - when we use Safari - it can be the case that the documentManager 
			// for this page, is not the document manager which was in use when the callback was created
			// so if this happens, we need to try to find the real document mananger to be used.
			// so far this always seems to be the parent document manager.
			// so we need to see if we can find the object
			
			if
				(this.parent.dateCreated == docManID )
			{
				
				o = this.parent.getObject(handle);
			}
			else
			{
				alert("call back will fail, this must be another nasty safari case, docman is not parent as expected");
			}
		}
		else
		{
			o = this.getObject ( handle );
        }
		
        if
            ( o != null )
        {
			
			//trace(dumpObj(o,"obj","",1));
			
			//var fn = o [ method ];
			
            try
			{
				var result = o [ method ] ( parameter );
				return result;
			}
			catch (e)
			{
				alert("Callback failed");
				alert("docMan = "+documentManager.dateCreated);
				alert(alertObjProp2(o));
			    trace(method);
				alert(e);
			}
            return false;
        }
		else
		{
			trace("call back failed, because cound not find object with handle "+handle);
		}
        
        return false;
    }
    
    /**
        called when we detect activity, mouse move, focus change etc
    **/
    DocumentManager.prototype.activity = function () {
        if ( this.parent != null ) {
            if ( ! this.parent.getIsLegendEditor () ) {
                this.parent.activity ();
                return;
            }
        }

        if
            ( this.onActivity != null )
        {
            var a = this.onActivity;

            this.onActivity = null;

            a ();
        }
    }

    /**
    
    **/
    DocumentManager.prototype.setGlobalFocus = function ( manager, object ) {

        if
            ( this.parent != null )
        {	
            this.parent.setGlobalFocus ( manager, object );
        }
        else
        {
            if
                ( this.globalFocusManager != manager )
            {
                if
                    ( this.globalFocusManager != null )
                {
                    this.globalFocusManager.setFocus ( null );
                }
            }

            this.globalFocusManager = manager;

            if
                ( this.globalFocusManager != null )
            {
                this.globalFocusManager.setFocus ( object );
            }
        }
    }

    DocumentManager.prototype.resetGlobalFocus = function () {

        if
            ( this.parent != null )
        {	
            this.parent.resetGlobalFocus ();
        }
        else
        {
            if
                ( this.globalFocusManager )
            {
                if
                    ( this.globalFocusManager.focusObject != null )
                {
                    var o = this.globalFocusManager.focusObject;
                    var boolFail = false;

                    o.setFocus ( false );

                    if ( o.callControlFocus ) {
                        boolFail = ! o.callControlFocus ();
                    }

                    if ( boolFail ) {
                        this.setGlobalFocus ( null, null );
                    } else {
                        o.setFocus ( true );
                    }
                }
            }
        }
    }

    DocumentManager.prototype.getGlobalFocus = function () {

        if
            ( this.parent != null )
        {	
            return this.parent.getGlobalFocus ();
        }
        else
        {
            if
                ( this.globalFocusManager )
            {
                return this.globalFocusManager.focusObject;
            }
        }

        return null;
    }

    DocumentManager.prototype.setGlobalFocusUndo = function () {

        if
            ( this.parent != null )
        {	
            this.parent.setGlobalFocusUndo ();
        }
        else
        {
            if
                ( this.globalFocusManager != null )
            {
                this.globalFocusManager.setFocusUndo ();
                this.globalFocusManager = null;
            }
        }
    }

    DocumentManager.prototype.setFocusUndo = function () {

        if
            ( this.focusObject != null )
        {
            if
                ( this.focusObject.editable )
            {
                this.database.write ( this.focusObject.fieldName, "edit", false );
            }

            this.focusObject.setFocus ( false );

            if
                ( this.focusObject.showFocus )
            {
                this.hideFocus ();
            }

            this.focusObject = null;

            window.focus ();
        }
    }

    DocumentManager.prototype.setFocus = function ( object ) {

        if
            ( this.focusObject != object )
        {
            var clearOld = false;

            if
                ( this.focusObject != null )
            {
                this.focusObject.setFocus ( false );
                
                if
                    ( this.focusObject.editable )
                {
                    var update = new updateObject ();
                    
                    update.write ( this.focusObject.fieldName, "edit", false );
                    
                    if
                        (
                            ( this.database.read ( this.focusObject.fieldName, "value" ) != this.oldFocusValue ) ||
                            ( this.database.read ( this.focusObject.fieldName, "valid" ) != this.oldFocusValid )
                        )
                    {
                        update.write ( this.focusObject.fieldName, "checked", false );
                        update.write ( this.focusObject.fieldName, "changed", true );
                    }

                    this.oInterface.syncUpdate ( update );
                }

                clearOld = this.focusObject.showFocus;
            }

            this.getTransactionManager ().fnEndTransaction ();
            this.getTransactionManager ().fnStartTransaction ();

            this.focusObject = object;

            this.oldFocusValue = null;
            this.oldFocusValid = null;

            if
                ( this.focusObject != null )
            {
                this.focusObject.setFocus ( true );
                
                if
                    ( this.focusObject.editable )
                {
                    var update = new updateObject ();
                    
                    update.write ( this.focusObject.fieldName, "edit", true );
            
                    this.oInterface.syncUpdate ( update );

                    this.oldFocusValue = this.database.read ( this.focusObject.fieldName, "value" );
                    this.oldFocusValid = this.database.read ( this.focusObject.fieldName, "valid" );
                }

                if
                    ( this.focusObject.showFocus )
                {
                    this.updateFocus ();
                }
                else
                if
                    ( clearOld )
                {
                    this.hideFocus ();
                }
            }
            else
            {
                var obError = null;
                if
                    ( clearOld )
                {
                    this.hideFocus ();
                }
                try {
                    this.documentElement.document.selection.empty ();
                }
                catch ( obError ) {
                }
            }
        }
    }

    DocumentManager.prototype.scanChildren = function ( element ) {

        //children--childNodes
          var coll = element.childNodes;  
        if
            ( coll != null )
        {
            var l = coll.length;
                
            if
                ( l >= 1 )
            {
                for ( var i = 0; i < l; i++ ) {
                    
                    var e = coll [ i ];
                    var handle = null;
                    if (e.getAttribute) handle = e.getAttribute ( "objectHandle" );
                        
                    if
                        ( handle != null )
                    {
                        this.objects [ handle ].element = e;
                    }
                    
                    this.scanChildren ( e )
                }
            }
        }
    }

    DocumentManager.prototype.allBoundObjects = function ( element ) {

        var result = [];
        //children--childNodes
        if ( element.childNodes != null ) { 
        //children--childNodes
            for ( var i = 0; i < element.childNodes.length; i++ ) {
                //children--childNodes
                var e = element.childNodes [ i ];
                var handle = null;
                if (e.getAttribute) handle = e.getAttribute ( "objectHandle" );

                if ( handle != null ) {

                    var o = this.objects [ handle ];

                    if ( o != null ) {

                        result [ result.length ] = o;
                    }
                }
                else
                {
                    result = result.concat ( this.allBoundObjects ( e ) );
                }
            }
        }

        return result;
    }

    DocumentManager.prototype.bindChildElements = function ( element ) {

        var e = element;

        while ( e != null ) {

            if (e.nodeType != 9)
            {
                var handle = e.getAttribute ( "objectHandle" );
    
                if ( handle != null ) {
    
                    var o = this.objects [ handle ];
    
                    if ( o != null ) {
    
                        if ( o.traverseChildren != null ) {
    
                            o.traverseChildren ( element );
    
                            return;
                        }
                    }
                }
            }

            e = e.parentNode;
        }
    }

    DocumentManager.prototype.removeChildElements = function ( element ) {
        var arrayObs = this.allBoundObjects ( element );
        for ( var numIndex = 0; numIndex < arrayObs.length; numIndex++ ) {
            this.remove ( arrayObs [ numIndex ].handle );
        }
    }

    DocumentManager.prototype.findControls = function ( element ) {
    
        var result = new Array ();

        if
            ( element.focus != null )
        {
            if
                ( element.value != null )
            {
                result [ 0 ] = element;

                return result;
            }
        }
        //children--childNodes
        var coll = element.childNodes;
            
        if
            ( coll != null )
        {
            for ( var i = 0; i < coll.length; i++ ) {
                    
                var e = coll [ i ];

                result = result.concat ( this.findControls ( e ) );
            }
        }
        
        return result;
    }
    
    DocumentManager.prototype.findName = function ( element ) {

        var name = element.getAttribute ( this.attributePrefix + "Name" );

        if
            ( name == null )
        {
            name = element.getAttribute ( "name" );
        }

        if
            ( name != null )
        {
            return name;
        }
        //children--childNodes
        var coll = element.childNodes;
            
        if
            ( coll != null )
        {
            for ( var i = 0; i < coll.length; i++ ) {
                    
                var e = coll [ i ];

                name = this.findName ( e );

                if
                    ( name != null )
                {
                    return name;
                }
            }
        }
        
        return null;
    }

    DocumentManager.prototype.getElementHandle = function ( element ) {

        while
            ( element != null )
        {
            var handle = element.objectHandle;
            
            if
                ( handle != null )
            {
                return handle;
            }

            element = element.parentNode;
        }
        
        return null;
    }
/*
    var EventWrapper = function ( toBeWrapped )
    {
        this.wrapped = toBeWrapped;
        if ( event )
        {// Mozilla
        }
        else
        {// IE
        }
    }
*/
function getTargetElement( e )
{
    var element;
    try
    {
        if ( e.target )
        {
            element = e.target;
        }
        else
        if ( e.srcElement )
        {
            element = e.srcElement;
        }
        if ( element )
        {
            if ( element.nodeType == 3 )// Safari browser bug
            {
                element = element.parentNode;//parentNode
            }
        }
    }
    catch ( ex )
    {
        //alert( "function getTargetElement( "+e+")" );
    }
    return element;
}
function getKeyCode( e )
{
	if (!e) return null;
	
    var code;
    if ( e.keyCode )
    {
        code = e.keyCode;
    }
    else
    if ( e.which )
    {
        code = e.which
    }
    return code;
}
DocumentManager.prototype.doSomething = function(e)
{
    if (!e) e = window.event;
    var element = getTargetElement( e );
    var code = getKeyCode( e );

	alert( "Event type is "+e.type );
}
    DocumentManager.prototype.doClick = function ( e )
    {
//        if (!e) var e = window.event;
//        var element = getTargetElement( e );
//        var code = getKeyCode( e );
    }
    DocumentManager.prototype.doDoubleClick = function ( e )
    {
        if (!e) e = window.event;
        var element = getTargetElement( e );

        var object = documentManager.getObject ( documentManager.getElementHandle ( element ) );
        if ( object != null ) {
            if ( object.onDoubleClick != null ) {
                object.onDoubleClick ();
            }
        }
    }
    
    DocumentManager.prototype.onKeyDown = function ( e ) {
        if (!e) e = window.event;
        var element = getTargetElement( e );
        var code = getKeyCode( e );

        if
            ( code == 38 )
        {
            // Up arrow
        }
        else
        if
            ( code == 40 )
        {
            // Down arrow
        }
        else
        if
            ( code == 37 )
        {
            // Left arrow
        }
        else
        if
            ( code == 39 )
        {
            // Right arrow
        }
        else
        if
            ( code == 9 )
        {
            // Tab key
        }
        
        return false;
    }

    DocumentManager.prototype.doKeyDown = function ( e ) {
        if (!e) e = window.event;
        var element = getTargetElement( e );
        var code = getKeyCode( e );

        documentManager.activity ();

        var handled = false;

        documentManager.controlToggle = ( code == 17 );

        if
            ( e.ctrlKey )
        {
            if ( code == 221 ) // If Ctrl-] then set controlToggle to enable popup using keyboard scanner
            {
                documentManager.controlToggle = true; 
            }
            else
            if ( code == 222 ) // If Ctrl-| then set commandToggle to enable next key is command using keyboard scanner
            {
                documentManager.commandToggle = true; 
            }
            else
            if
                ( ( code == 89 ) || ( code == 90 ) )
            {
                var undo = ( code == 90 );
                if ( documentManager.focusObject != null ) {
                    if ( documentManager.focusObject.bRetainFocusOnUndo != true ) {
                        documentManager.setGlobalFocusUndo ();
                    }
                }
                documentManager.addTask ( new Function ( "documentManager.globalUndo ( " + undo + ");" ) );
                handled = true;
            }
        }

        if
            ( ! handled )
        {
            if
                ( documentManager.focusObject != null )
            {
                if
                    ( documentManager.focusObject.onKeyDown != null )
                {
                    handled = documentManager.focusObject.onKeyDown ();
                }
            }
        }

        if
            ( ! handled )
        {
            if
                ( documentManager.selectedObject != null )
            {
                if
                    ( documentManager.selectedObject.onKeyDown != null )
                {
                    handled = documentManager.selectedObject.onKeyDown ();
                }
            }
        }

        if
            ( ! handled )
        {
            handled = documentManager.onKeyDown ();

//            if
//                ( ! handled )
//            {
//                // Sink backspace- the default is to make the browser go-back...
//
//                if
//                    ( code == 8 )
//                {
//                    if ( browserVersion < 5 ) {
//
//                        handled = true;
//
//                       if
//                            ( documentManager.focusObject != null )
//                        {
//                            if
//                                ( documentManager.focusObject.editable || documentManager.focusObject.allowBackSpace )
//                            {
//                                handled = false;
//                            }
//                        }
//                    }
//                    else
//                    {
//                        if
//                           ( documentManager.focusObject != null )
//                        {
//                            handled = true;
//
//                            if
//                                ( documentManager.focusObject.editable || documentManager.focusObject.allowBackSpace )
//                            {
//                                handled = false;
//                            }
//                        }
//                    }
//                }
//            }
        }

        

        if
            ( handled )
        {
            //event.keyCode = 0;
            e.cancelBubble = true;
            if ( e.stopPropagation ) e.stopPropagation();
            return false;
        }
        
        return true;
    }

    //    If any DM uses setNamedItem to set "keyPressHandler"
    //    to a function then that function will be called when ever a keyPress event
    //    occurs in ANY DM (the function is passed a key code and returns a Boolean
    //    which if true implies that the function handled the keyPress- otherwise
    //    the keyPress is handled in the default way by the DM in which the event
    //    occurred). This mechanism allows one or more DMs (a character picker, for
    //    example) to intercept and optionally handle keyPress events occurring in
    //    ALL DM controlled frames.

    DocumentManager.prototype.doKeyPress = function (e) {
        
        if (!e) e = window.event;
        var element = getTargetElement( e );
        var code = getKeyCode( e );

        if
            ( this.oldOnKeyPress != null )
        {
            this.oldOnKeyPress ();
        }
        else
        {
            var handlers = documentManager.getNamedItemsGlobal ( "keyPressHandler" );
            var handled = false;

            for ( var i = 0; i < handlers.length; i++ ) {

                handled = handlers [ i ] ( code );

                if ( handled ) break;
            }

            if ( ! handled ) {

                if
                    ( ( code == 26 ) || ( code == 25 ) )
                {
                    // Sink ctrl-y and ctrl-z...

//                    event.keyCode = 0;
                    return;
                }

                if ( documentManager.commandToggle )
                {
                    // Sink command character
                    if ( code == 28 ) // Ctrl-|
                    {
//                      event.keyCode = 0;
                        return;
                    }
                    // Handle commands
                        var w = findChildWindowWithProperty( window, "InterpretBarCode" );//lcorbeil is this IE specific?
                        if ( w != null )
                        {
                            switch ( code )
                            {
                                case 65:	// Command A
                                        w.InterpretBarCode( "AAF" );
                                    break;
                                case 66:	// Command B
                                        w.InterpretBarCode( "CAN" );
                                    break;
                                case 67:	// Command C
                                        w.InterpretBarCode( "CON" );
                                    break;
                                case 68:	// Command D
                                        w.InterpretBarCode( "DEF" );
                                    break;
                                case 69:	// Command E
                                        w.InterpretBarCode( "DEA" );
                                    break;
                                case 70:
                                        w.InterpretBarCode( "ENT" );
                                    break;
                                case 71:
                                        w.InterpretBarCode( "FIN" );
                                    break;
                                case 72:
                                        w.InterpretBarCode( "ISS" );
                                    break;
                                case 73:
                                        w.InterpretBarCode( "PEA" );
                                    break;
                                case 74:
                                        w.InterpretBarCode( "PEB" );
                                    break;
                                case 75:
                                        w.InterpretBarCode( "PEC" );
                                    break;
                                case 76:
                                        w.InterpretBarCode( "PED" );
                                    break;
                                case 77:
                                        w.InterpretBarCode( "PEE" );
                                    break;
                                case 78:
                                        w.InterpretBarCode( "NET" );
                                    break;
                                case 79:
                                        w.InterpretBarCode( "PAY" );
                                    break;
                                case 80:
                                        w.InterpretBarCode( "PYA" );
                                    break;
                                case 81:
                                        w.InterpretBarCode( "PYI" );
                                    break;
                                case 82:
                                        w.InterpretBarCode( "REF" );
                                    break;
                                case 83:
                                        w.InterpretBarCode( "REN" );
                                    break;
                                case 84:
                                        w.InterpretBarCode( "RET" );
                                    break;
                                case 85:
                                        w.InterpretBarCode( "SLP" );
                                    break;
                                case 86:
                                        w.InterpretBarCode( "STO" );
                                    break;
                                case 87:
                                        w.InterpretBarCode( "VTR" );
                                    break;
                                case 88:
                                        w.InterpretBarCode( "WAI" );
                                    break;
                                case 89:
                                        w.InterpretBarCode( "WRO" );
                                    break;
                            }
                        }
                        else
                        {
                            alert("Script not found");
                        }

                    // If the command wasn't handled the command character is thrown away
//                    event.keyCode = 0;
                    documentManager.commandToggle = false;
                    return;
                }


                if
                    ( documentManager.focusObject != null )
                {
                    if
                        ( documentManager.focusObject.onKeyPress != null )
                    {
                        handled = documentManager.focusObject.onKeyPress ();
                    }
                }
                
                if
                    ( ! handled )
                {
                    if
                        ( code == 13 )
                    {
                        // Sink enter...

                        // handled = true;
                    }

                    if
                        ( code == 27 )
                    {
                        // Sink escape...

                        handled = true;
                    }
                }
            }

            if
                ( handled )
            {
//                event.keyCode = 0;
                e.cancelBubble = true;
                if ( e.stopPropagation() ) e.stopPropagation();
                return false;
            }
        }
    }
    
    DocumentManager.prototype.doKeyUp = function (e) {
        if (!e) e = window.event;
        var element = getTargetElement( e );
        var code = getKeyCode( e );

        var handled = false;
    
        if ( code == 17 ) {

            if ( documentManager.controlToggle ) {

                var m = documentManager;

                while ( m != null ) {

                    var f;
                    if
                        (m.documentElement.document)
                    {
                        f = m.documentElement.document.parentWindow.launchGlobalMenu;
                    }
                    else if
                        (m.documentElement && m.documentElement.contentWindow)
                    {
                        f = m.documentElement.contentWindow.parentWindow.launchGlobalMenu;
                    }

                    if ( f != null ) {

                        m = null;

                        f ();
                    }
                    else
                    {
                        m = m.parent;
                    }
                }
            }

            documentManager.controlToggle = false;
        }

        if
            ( ! handled )
        {
            if
                ( documentManager.focusObject != null )
            {
                if
                    ( documentManager.focusObject.onKeyUp != null )
                {
                    handled = documentManager.focusObject.onKeyUp ();
                }
            }
        }
    }

    DocumentManager.prototype.setSelectedObject = function ( object ) {
        if ( this.selectedObject != object ) {
            if ( this.selectedObject != null ) {
                if ( this.selectedObject.hoverOut != null ) {
                    if ( this.selectedObject != this.hoverObject ) {
                        this.selectedObject.hoverOut ();
                    }
                }
            }
            this.selectedObject = object;
            if ( this.selectedObject != null ) {
                if ( this.selectedObject.hoverIn != null ) {
                    if ( this.selectedObject != this.hoverObject ) {
                        this.selectedObject.hoverIn ();
                    }
                }
            }
        }
        this.setHoverObject ( object );
    }

    DocumentManager.prototype.setHoverObject = function ( object ) {
        if ( this.hoverObject != object ) {
            var clearOld = false;
            if ( this.hoverObject != null ) {
                if ( this.hoverObject.hoverOut != null ) {
                    if ( this.hoverObject != this.selectedObject ) {
                        this.hoverObject.hoverOut ();
                    }
                }
                clearOld = this.hoverObject.showHover;
            }
            this.hoverObject = object;
            if ( this.hoverObject != null ) {
                if ( this.hoverObject.hoverIn != null ) {
                    if ( this.hoverObject != this.selectedObject ) {
                        this.hoverObject.hoverIn ();
                    }
                }
                if ( this.hoverObject.showHover ) {
                    this.updateHover ();
                } else if ( clearOld ) {
                    this.hideHover ();
                }
            } else if ( clearOld ) {
                this.hideHover ();
            }
        }
    }

    DocumentManager.prototype.doHover = function ( element ) {
        var object = this.getObject ( this.getElementHandle ( element ) );
        this.setHoverObject ( object );
        if ( object != null ) {
            if ( object.selectable != null ) {
                if ( object.selectable () ) {
                    this.setSelectedObject ( object );
                }
            }
        }
    }

    DocumentManager.prototype.updateHoverRectangle = function () {
        if
            ( this.hoverRectangle )
        {
            this.hoverRectangle.fnUpdate ();
        }
    }

    DocumentManager.prototype.hideHover = function () {
        if
            ( this.hoverRectangle != null )
        {
            this.hoverRectangle.fnHide ();
        }

        this.updateHoverRectangle ();
    }

    DocumentManager.prototype.updateHover = function () {

        var object = this.hoverObject;
        var show = false;

        if
            ( object != null )
        {
            show = object.showHover;
        }

        if
            ( show )
        {
            var element = object.outerElement;

            if ( object.showFocusElement != null ) element = object.showFocusElement;

            if
                ( this.hoverRectangle == null )
            {
                this.hoverRectangle = new cHighlightRectangle ( "hover" );
                this.hoverRectangle.fnSetThickness ( 2 );
                this.hoverRectangle.fnSetColor ( "bisque" );
            }

            this.hoverRectangle.fnSetElement ( element );
            this.hoverRectangle.fnShow ();
        }
        else
        {
            if
                ( this.hoverRectangle != null )
            {
                this.hoverRectangle.fnHide ();
            }
        }

        this.addTaskObject ( { object:this, method:"updateHoverRectangle", priority:1 } );
    }

    DocumentManager.prototype.updateFocusRectangle = function () {

        if
            ( this.focusRectangle )
        {
            this.focusRectangle.fnUpdate ();
        }
    }

    DocumentManager.prototype.hideFocus = function () {

        if
            ( this.focusRectangle != null )
        {
            this.focusRectangle.fnHide ();
        }
    }

    DocumentManager.prototype.updateFocus = function () {

        var object = this.focusObject;
        var show = false;

        if
            ( object != null )
        {
            show = object.showFocus;
        }

        if
            ( show )
        {
            var advice = this.focusObject.advice;
            var element = object.outerElement;

            if ( advice == null ) advice = "";

            if
                ( advice != "" )
            {
                advice = this.translateAdvice ( advice );
            }

            if ( object.showFocusElement != null ) element = object.showFocusElement;

            if
                ( this.focusRectangle == null )
            {
                this.focusRectangle = new cHighlightRectangle ( "focus" );
                this.focusRectangle.fnSetThickness ( 3 );
            }

            this.focusRectangle.fnSetElement ( element );
            this.focusRectangle.fnSetAdvice ( advice );
            this.focusRectangle.fnShow ();

            if ( advice != "" ) {
                this.focusRectangle.fnSetAdvicePosition ( object.getInheritedAttribute ( this.attributePrefix + "AdvicePosition" ) );
            }
        }
        else
        {
            if
                ( this.focusRectangle != null )
            {
                this.focusRectangle.fnHide ();
            }
        }
    }


if ( debugTrace ) document.write("Step 3<br>");  

    function cHighlightRectangle ( strName ) {
        this.elOwner = null;
        this.arrayBits = null;
        this.numThickness = 3;
        this.strAdvice = "";
        this.strColor = "darkorange";
        this.strName = strName;
    }

        cHighlightRectangle.prototype.fnCreateBits = function ( el ) {
            var elParent = el.parentNode;
            if ( this.arrayBits != null ) {
                for ( var i = 0; i < this.arrayBits.length; i++ ) {
                    var elBit = this.arrayBits [ i ];
                    if ( elBit.parentNode != null ) {
                        elBit.style.display = "none";
                    }
                }
            }
            this.arrayBits = [];
            var elPrev = el.previousSibling;
            while ( elPrev != null ) {
                if ( elPrev.strRectName != null ) {
                    if ( elPrev.strRectName == this.strName ) {
                        this.arrayBits [ this.arrayBits.length ] = elPrev;
                    }
                    elPrev = elPrev.previousSibling;
                } else {
                    break;
                }
            }
            if ( this.arrayBits.length != 0 ) {
                this.arrayBits.reverse ();
                this.arrayBits [ 5 ].style.visibility = "hidden";
            } else {
                for ( var i = 0; i < 6 ; i++ ) {
                    var elBit = document.createElement ( "div" );
                    elParent.insertBefore ( elBit, el );
                    elBit.strRectName = this.strName;
                    this.arrayBits [ i ] = elBit;
                }
            }
            for ( var i = 0; i < 6 ; i++ ) {
                var elBit = this.arrayBits [ i ];
                elBit.style.position = "absolute";
                elBit.style.display = "none";
                elBit.style.width = 0;
                elBit.style.height = 0;
                if ( i == 4 ) {
                    elBit.className = "advice-style";
                } else {
                    elBit.style.fontSize = "0pt";
                    if ( i == 5 ) {
                        elBit.style.visibility = "hidden";
                    }
                }
            }
            this.elOwner = el;
            this.bHidden = true;
        }
        cHighlightRectangle.prototype.fnPingUpdate = function () {
            this.bWaiting = false;
            if ( this.elWaiting != this.elOwner ) {
                this.bSecond = false;
            }
            this.fnUpdate ();
        }
        cHighlightRectangle.prototype.fnUpdate = function () {
            if ( this.elOwner != null ) {
                if ( this.elOwner.parentNode != null ) {
                    var elAdvice = this.arrayBits [ 4 ];
                    if ( this.strAdvice == "" ) {
                        elAdvice.style.display = "none";
                    }
                    if ( ( ! this.bHidden ) && ( ! this.bWaiting ) ) {
                        var elB = this.arrayBits [ 5 ];
                        var obRect = getBoundingClientRect (this.elOwner);
                        var numWidth = obRect.right - obRect.left;
                        var numHeight = obRect.bottom - obRect.top;
                        var numT = this.numThickness;
                        if ( ! this.bSecond ) {
                            elB.style.left = obRect.left;
                            elB.style.top = obRect.top;
                        }
                        if ( browserVersion < 5.5 ) {
                            if ( ! this.bSecond ) {
                                this.bSecond = true;
                                this.bWaiting = true;
                                this.elWaiting = this.elOwner;
                                documentManager.addTaskObject ( { object:this, method:"fnPingUpdate", imperative:true } );
                                return;
                            } else {
                                this.bSecond = false;
                            }
                        }
                        var obRectB = getBoundingClientRect (elB);
                        var numOffsetLeft = obRectB.left - obRect.left;
                        var numOffsetTop = obRectB.top - obRect.top;
                        var numLeft = obRect.left - numOffsetLeft;
                        var numTop = obRect.top - numOffsetTop;

                        with ( this.arrayBits [ 0 ].style ) {
                            top = numTop - numT - 1;
                            left = numLeft - numT - 1;
                            width = numWidth + ( numT + 1 ) * 2;
                            height = numT;
                            backgroundColor = this.strColor;
                        }
                        with ( this.arrayBits [ 1 ].style ) {
                            top = numTop - 1;
                            left = numLeft - numT - 1;
                            width = numT;
                            height = numHeight + 2;
                            backgroundColor = this.strColor;
                        }
                        with ( this.arrayBits [ 2 ].style ) {
                            top = numTop + numHeight + 1;
                            left = numLeft - numT - 1;
                            width = numWidth + ( numT + 1 ) * 2;
                            height = numT;
                            backgroundColor = this.strColor;
                        }
                        with ( this.arrayBits [ 3 ].style ) {
                            top = numTop - 1;
                            left = numLeft + numWidth + 1;
                            width = numT;
                            height = numHeight + 2;
                            backgroundColor = this.strColor;
                        }
                        if ( this.strAdvice != "" ) {
                            with ( elAdvice.style ) {
                                if ( this.strAdvicePosition == "below" ) {

                                    left = numLeft - 4;
                                    top = numTop + numHeight + 5;
                                }
                                else if ( this.strAdvicePosition == "belowFlushRight" )
                                {
                                    left = numLeft + numWidth - 95;
                                    top = numTop + numHeight + 5;
                                    textAlign = "center";
                                }
                                else
                                {
                                    left = numLeft + numWidth + 10;
                                    top = numTop - numT
                                }
                                width = 100;
                                height = 20;
                                elAdvice.innerText = this.strAdvice;
                                this.arrayBits [ 4 ].style.display = "block";
                            }
                            elAdvice.style.display = "block";
                        }
                    }
                }
            }
        }
        cHighlightRectangle.prototype.fnSetElement = function ( el ) {
            if ( this.elOwner != el ) {
                this.fnCreateBits ( el );
                this.elWaiting = null;
            }
        }
        cHighlightRectangle.prototype.fnSetDisplay = function ( strDisplay ) {
            for ( var i = 0; i < 6; i++ ) {
                var el = this.arrayBits [ i ];
                el.style.display = strDisplay;
            }
        }
        cHighlightRectangle.prototype.fnHide = function () {
            if ( ! this.bHidden ) {
                this.bHidden = true;
                if ( this.elOwner != null ) {
                    this.fnSetDisplay ( "none" );
                }
            }
        }
        cHighlightRectangle.prototype.fnShow = function () {
            if ( this.bHidden ) {
                this.bHidden = false;
                if ( this.elOwner != null ) {
                    if ( this.elOwner.parentNode != null ) {
                        this.fnSetDisplay ( "block" );
                        this.fnUpdate ();
                    }
                }
            }
        }
        cHighlightRectangle.prototype.fnSetAdvice = function ( strAdvice ) {
            if ( strAdvice != this.strAdvice ) {
                this.strAdvice = strAdvice;
                this.fnUpdate ();
            }
        }
        cHighlightRectangle.prototype.fnSetAdvicePosition = function ( strPosition ) {
            this.strAdvicePosition = strPosition;
            this.fnUpdate ();
        }
        cHighlightRectangle.prototype.fnSetThickness = function ( numThickness ) {
            this.numThickness = numThickness;
            this.fnUpdate ();
        }
        cHighlightRectangle.prototype.fnSetColor = function ( strColor ) {
            this.strColor = strColor;
            this.fnUpdate ();
        }

    DocumentManager.prototype.getAbsoluteBodyOffset = function ( element ) {
        var obRects = getBoundingClientRect(element);
        var obBody = document.body;
        var numX = ( obRects.left ) + document.body.scrollLeft;
        var numY = ( obRects.top ) + document.body.scrollTop;
        numX -= element.document.body.clientLeft;
        numY -= element.document.body.clientTop;
        return { x:numX, y:numY };
    }
    
    DocumentManager.prototype.getOffset = function ( reference, element ) {

        var x = 0;
        var y = 0;
        var p = element;

        while
            ( ( p != reference.offsetParent ) && ( p != null ) )
        {
            x += p.offsetLeft;
            y += p.offsetTop;

            if
                ( p.scrollTop != null )
            {
                y -= p.scrollTop;
            }
            if
                ( p.scrollLeft != null )
            {
                x -= p.scrollLeft;
            }

            p = p.offsetParent;
        }
        
        return { x:x, y:y };
    }

    DocumentManager.prototype.scrollIntoView = function ( element ) {

        var parent = element.offsetParent;
        var height = element.offsetHeight;

        var y = 0;

        while ( parent != null ) {

            y += element.offsetTop;

            var top = parent.scrollTop;
            var bottom = top + parent.offsetHeight;
            var done = false;

            if ( height > parent.offsetHeight ) {

                if ( ( ( y + height ) > top ) && ( y < bottom ) ) return;
            }

            if
                ( ( y + height ) > bottom )
            {
                var delta = ( ( y + height ) - bottom );

                parent.scrollTop += delta;

                top = parent.scrollTop;
                bottom = top + parent.offsetHeight;

                done = true;
            }

            if
                ( y < top )
            {
                parent.scrollTop -= ( top - y );

                done = true;
            }

            if ( done ) return true;

            element = parent;
            parent = element.offsetParent;
        }

        return false;
    }
    
    DocumentManager.prototype.translateAdvice = function ( advice ) {

        if
            ( this.parent )
        {
            return this.parent.translateAdvice ( advice );
        }

        var result = this.translations [ advice.toLowerCase () ];

        if
            ( ( result != null ) && ( result != "" ) )
        {
            return result;
        }

        return advice;
    }

    DocumentManager.prototype.mapAdviceText = function ( fromString, toString ) {

        if
            ( this.parent )
        {
            this.parent.mapAdviceText ( fromString, toString );
        }

        this.translations [ fromString.toLowerCase () ] = toString;
    }


    var buttonState = "";
    
    DocumentManager.prototype.doMouseDown = function ( e ) {
	    trace("mouseDown");
        if (!e) e = window.event;
        var element = getTargetElement( e );
//        var code = getKeyCode( e );
        //this.buttonState = "";
        if
            (e.which)
        {
			trace("which branch");
            if
                (e.button == 0)
            {
                buttonState = "left";
            }
			else if
				(e.button == 1)
			{
			   // this is what happens with Safari 
			   buttonState = "left";
			}
            else if
                (e.button == 2)
            {
                buttonState = "right";
            }
            else
            {
				trace("e.button is "+e.button);
				trace("e.which is "+ e.which );
                buttonState = "";
            }
        }
        else
        {
            if 
                (e.button == 1)
            {
                buttonState = "left";
            }
            else if
                (e.button == 2 )
            {
                buttonState = "right";
            }
            else
            {
                buttonState = "";
            }
        }
        
        if
            (buttonState != "")
        {
            trace("buttonstate = "+buttonState);
        }
        
        documentManager.obLastMouseDownObject = documentManager.getObject ( documentManager.getElementHandle ( element ) );

        documentManager.activity ();

        documentManager.startDrag ( e );
    }

    DocumentManager.prototype.getInheritedAttribute = function ( element, attribute ) {

        var result = null;

        while
            ( element != null )
        {
            result = element.getAttribute( attribute );

            if ( result != null ) break;

            if
                ( element == document.body )
            {	
                element = null;
            }
            else
            {
                element = element.parentNode;
            }
        }
        
        return result;
    }

    DocumentManager.prototype.startDrag = function ( e ) {
        
        trace("", "document manager start drag called");
        
        if (!e) e = window.event;
        var element = getTargetElement( e );
        var code = getKeyCode( e );

        while ( element != null )
        {
            var object = this.getObject ( this.getElementHandle ( element ) );

            if
                ( object == null )
            {
                return;
            }
            else
            {
                if
                    ( object.doDrag != null )
                {
                    this.dragObject = object;
                    this.mouseDownX = e.screenX;
                    this.mouseDownY = e.screenY;

                    if
                        ( object.startDrag != null )
                    {
                        object.startDrag ();
                    }

                    return;
                }

                element = element.parentNode;
            }
        }
    }

    DocumentManager.prototype.doMouseMove = function (e) {
        if (!e) e = window.event;
//        var element = getTargetElement( e );
//        var code = getKeyCode( e );

        if ( ( documentManager.lastMouseX != e.screenX ) || ( documentManager.lastMouseY != e.screenY ) ) {
            documentManager.lastMouseX = e.screenX;
            documentManager.lastMouseY = e.screenY;
            documentManager.activity ();
            documentManager.actionMouseMove ( e );
        }
    }

    DocumentManager.prototype.actionMouseMove = function ( e ) {
        if (!e) e = window.event;
        var element = getTargetElement( e );
//        var code = getKeyCode( e );

        if ( this.lastHoverElement != element ) {
            this.lastHoverElement = element;
            this.doHover ( element );
        }
        
        //trace("buttonstate = "+buttonState);
        
        var buttons = e.button;
        if 
            (e.which)
        {
            
            if 
                (buttonState == "left")
            {
                buttons = 1;
            }
            else if
                (buttonState == "right")
            {
                buttons = 2;
            }
            else
            {
                buttons = 0;
            }
        }
        this.notifyMouseMove ( e.screenX, e.screenY, buttons );
    }

    DocumentManager.prototype.notifyMouseMove = function ( x, y, buttons ) {

        if
            ( this.parent != null )
        {
            this.parent.notifyMouseMove ( x, y, buttons );
        }
        else
        {
            this.performMouseMove ( x, y, buttons );
        }
    }

    DocumentManager.prototype.performMouseMove = function ( x, y, buttons ) {

        if
            ( this.dragObject != null )
        {
            trace("","DocumentManager.performMouseMove with non empty dragObject");
            trace("", "button state is "+buttonState );
			trace("", "buttons is " + buttons);
			trace("","fish");
            if
                ( buttons == 1  || buttonState == "left")
            {
                var dx = x - this.mouseDownX;
                var dy = y - this.mouseDownY;

                this.mouseDownX = x;
                this.mouseDownY = y;

                this.dragObject.doDrag ( dx, dy );
            }
            else
            {
                this.doDragStop ();
            }
        }

        var children = this.childManager.getObjects ();

        for ( var h in children ) {

            try
                {
                    children [ h ].performMouseMove ( x, y, buttons );
                }
            catch (e)
            {
                //alert(e.message);
                //alert(e.name);
            }
        }
    }

    DocumentManager.prototype.doMouseUp = function ( e ) {
        if (!e) e = window.event;
        var element = getTargetElement( e );
//        var code = getKeyCode( e );
		trace("mouseUp");
        buttonState = "";

        var obLastMouseDownObject = documentManager.obLastMouseDownObject;
        documentManager.obLastMouseDownObject = null;
        if
            ( documentManager.dragObject != null )
        {
            documentManager.doDragStop ();
        }

        {
            var object = documentManager.getObject ( documentManager.getElementHandle ( element ) );
            if
                ( object != null )
            {
                if ( object == obLastMouseDownObject ) {
                    if ( element != object.localFocusElement ) {
                        if ( object.onClick != null ) {
    //						if ( document.selection.type != "Text" ) {
                                object.onClick ( e );
    //						}
                        }
                    }
                }
            }
        }
    }

    DocumentManager.prototype.doDragStop = function () {

        if
            ( this.dragObject != null )
        {
            if
                ( this.dragObject.stopDrag != null )
            {
                this.dragObject.stopDrag ();
            }

            this.dragObject = null;
        }

        this.resetGlobalFocus ();
    }

    DocumentManager.prototype.doDragStart = function () {
    }

    DocumentManager.prototype.doSelectStart = function () {
    }

    DocumentManager.prototype.doResize = function () {
        if ( ! documentManager.bDoingResize ) {
            documentManager.bDoingResize = true;
            documentManager.addTaskObject ( { object:documentManager, method:"actionResize", priority:2 } );
        }
    }

	var lastWindowWidth = -1;
	var lastWindowHeight = -1;



    DocumentManager.prototype.windowSize = function ()
    {
            var myWidth = 0, myHeight = 0;
    
            if( typeof( window.innerWidth ) == 'number' ) {
                //Non-IE
                myWidth = window.innerWidth;
                myHeight = window.innerHeight;
            } 
            else if
                ( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) 
            {
                myWidth = document.documentElement.clientWidth;
                myHeight = document.documentElement.clientHeight;
            }
            else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) 
            {
                myWidth = document.body.clientWidth;
                myHeight = document.body.clientHeight;
            }
        return {  width: myWidth , height: myHeight };
    }
	/***
		called when the document is being resized
		we could enhance this to allow us to support browsers which do not fire
		an on-size event.
	***/
		
    DocumentManager.prototype.actionResize = function () {

		var myWidth = 0, myHeight = 0;
		
		if( typeof( window.innerWidth ) == 'number' ) {
			//Non-IE
			myWidth = window.innerWidth;
			myHeight = window.innerHeight;
		} 
		else if
			( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) 
		{
			myWidth = document.documentElement.clientWidth;
			myHeight = document.documentElement.clientHeight;
		}
		else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) 
		{
			myWidth = document.body.clientWidth;
			myHeight = document.body.clientHeight;
		}
		
		if ((myWidth != lastWindowWidth) || (myHeight != lastWindowHeight))
		{
			
			lastWindowHeight = myHeight;
			lastWindowWidth  = myWidth;
				
			trace("","action Resize");
			documentManager.updateHoverRectangle ();
			documentManager.updateFocusRectangle ();
			trace("","do onresizes");
			this.doFunctions ( this.onresizes );
			trace("","done");
		}
        this.bDoingResize = false;
    }

    DocumentManager.prototype.startupWatchdog = function () {
    //alert( 'startupWatchdog '+document.readyState );
        trace("startupWatchdog called");
        if (document.readyState)
        {
            if ( document.readyState == "complete" )
            {
                
                if
                    (document != null)
                {
                    if
                        (document.body != null)
                    {
                        trace("readyState is complete - calling start");
                        documentManager.start ( document );
                    }
                    else
                    {
                        trace("readyState is complete but the document body element does not yet exist - spooky");
                    }
                }
                
            }
            else
            {
                return "repeat";
            }
        }
        else
        {
            // there is an expectation here that eventually the readyState property will
            // be created by an onload handler, maybe put some kind of friendly warning if
            // we keep looping round here more that a few times 
            
            return "repeat";        
        }
    }


    DocumentManager.prototype.findNamedObject = function ( name ) {

        if ( window.findNamedObject ) {

            return findNamedObject ( name );
        }

        if
            ( this.parent != null )
        {
            return this.parent.findNamedObject ( name );
        }

        return null;
    }

    DocumentManager.prototype.fetchEnumResource = function ( enumName ) {

        function mapFromRaw ( object ) {

            if
                ( object.charCodeAt == ( void 0 ) )
            {
                var map = {};

                for ( var i = 0; i < object.length; i++ ) {

                    map [ object [ i ] [ 0 ] ] = mapFromRaw ( object [ i ] [ 1 ] );
                }

                return map;
            }

            return object;
        }

        var result = [];

        if ( ( this.styleSet == null ) || ( this.appServer == null ) ) {

            alert ( "DOCUMENT MANAGER CAN'T FETCH RESOURCES WITHOUT A FETCHR OBJECT AND A STYLE SET" );
        }
        else
        {
            var r = null;

            this.appServer.ClearCmd();
            this.appServer.CmdPrefix = "APS_RESOURCE?" + this.styleSet;
            this.appServer.CmdSet("Method","Fetch");
            this.appServer.CmdSet("Resources", enumName );
            this.appServer.CmdSet("Style", "ALSi" );
            this.appServer.DoCmd();

            eval ( "r = " + this.appServer.TextResponse );
            var table = r [ enumName ];

            if ( table == null ) {

                alert ( "RESOURCE:" + enumName + " NOT FOUND" );
            }
            else
            {
                for ( var i = 0; i < table.length; i++ ) {

                    var value = table [ i ] [ 0 ];
                    var map = mapFromRaw ( table [ i ] [ 1 ] );
                    var text = map.text;
                    
                    if ( text == null ) {
                    
                        text = "";
                    }

                    result [ result.length ] = { value:value, text:text };
                }
            }
        }

        return result;
    }
    DocumentManager.prototype.setControlToNewValue = function ( el, str ) {
        var bDone = false;
        if ( el.value.length == str.length ) {
            var range = document.selection.createRange ();
            if ( range.text == "" ) {
                if ( el.createTextRange != null ) {
                    var rangeEl = el.createTextRange ();
                    var numCharIndex = -1;
                    if ( rangeEl.inRange ( range ) ) {
                        range.setEndPoint ( "StartToStart", rangeEl );
                        numCharIndex = range.text.length;
                    } else if ( el == range.parentElement () ) {
                        range.text = "\u0001";
                        numCharIndex = el.value.indexOf ( "\u0001" );
                    }
                    el.value = str;
                    bDone = true;
                    if ( numCharIndex >= 0 ) {
                        rangeEl = el.createTextRange ();
                        rangeEl.moveStart ( "character", numCharIndex );
                        rangeEl.collapse ( true );
                        rangeEl.select ();
                    }
                }
            }
        }
        if ( ! bDone ) {
            el.value = str;
        }
    }
    /***
		this function is obsolete because we always use the script based fetcher.
		
    ***/
    DocumentManager.prototype.setUseScriptHTTPFetcher = function ( bSet ) {
		
        this.bUseScriptHTTPFetcher = ( ( bSet == "1" ) || ( bSet == true ) );
    }

	/****
		determine whether to use the script based fetcher or not always use the script based fether
	****/    
	
    DocumentManager.prototype.getUseScriptHTTPFetcher = function () {
        /*if ( this.bUseScriptHTTPFetcher ) {
            return true;
        }
        if ( this.parent != null ) {
            return this.parent.getUseScriptHTTPFetcher ();
        }
        return false;*/
        return true;
    }
    
    /**
		tries to set the focus on given element 
    **/
    DocumentManager.prototype.trySetFocus = function ( el ) {
        var bError = false;
        var obError = null;
        try { el.focus (); }
        catch ( obError ) {
            var numCode = obError.number & 0xFFFF;
            bError = true;
            if ( numCode == 2110 ) {
                // Control is invisible...
            } else {
                throw ( obError );
            }
        }
        return ! bError;
    }

// initialise the document manager here


//--------------------------------------------------------

        function baseObject ()
        {
            this.manager = null;
            this.handle = null;

            this.parent = null;
            this.previous = null;
            this.next = null;

            this.showHover = false;
            this.showFocus = true;

            this.editable = false;

            this.focus = false;
            this.valid = true;
            this.disabled = false;
            this.advice = null;
        }

        baseObject.prototype.setFocus = function ( focusOn ) {
        
            if
                ( this.focus != focusOn )
            {
                this.focus = focusOn;
                
                if
                    ( focusOn )
                {
                    this.focusIn ();
                }
                else
                {
                    this.focusOut ();
                }
            }
        }
        
        baseObject.prototype.createCallback = function ( method, parameter ) {

            return this.manager.createCallback ( this, method, parameter );
        }
        
        baseObject.prototype.scanChildElements = function ( element ) {
            //children--childNodes
            var coll = element.childNodes;
                
            if
                ( coll != null )
            {
                var l = coll.length;
                    
                for ( var i = 0; i < l; i++ ) {
                        
                    var e = coll [ i ];
                    var handle = e.getAttribute ( "objectHandle" );
                            
                    if
                        ( handle != null )
                    {
                        this.renderHandleIntoElement ( handle, e );
                    }
                    else
                    {
                        this.scanChildElements ( e )
                    }
                }
            }
        }

        baseObject.prototype.renderTemplateIntoElement = function ( template, element ) {
        
            element.innerHTML = template;
            this.scanChildElements ( element );
        }
        
        baseObject.prototype.getInheritedAttribute = function ( attribute ) {

            return this.manager.getInheritedAttribute ( this.outerElement, attribute );
        }
        
        baseObject.prototype.focusOut = function () {}
        baseObject.prototype.focusIn = function () {}
        baseObject.prototype.renderHandleIntoElement = function ( handle, element ) {
        
            element.innerHTML = "<SPAN style=color:red>HANDLE:" + handle + "</SPAN>";
        }


        function xDocumentManager_Startup()
        {
            documentManager.initialise ();
            documentManager.addTask ( documentManager.startupWatchdog );
        
        }

        // initialise now.
        xDocumentManager_Startup();
