/**************************************************************************
*
*  @@@BUILDINFO@@@ 72debugger-2.jsx 2.0.1.70  05-June-2007
*  Copyright 2006-2007 Adobe Systems Incorporated
*  All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains the property of
* Adobe Systems Incorporated  and its suppliers,  if any.  The intellectual 
* and technical concepts contained herein are proprietary to  Adobe Systems 
* Incorporated  and its suppliers  and may be  covered by U.S.  and Foreign 
* Patents,patents in process,and are protected by trade secret or copyright 
* law.  Dissemination of this  information or reproduction of this material
* is strictly  forbidden  unless prior written permission is  obtained from 
* Adobe Systems Incorporated.
**************************************************************************/

// The current debugger contains the debugger that has either been selected
// by the user, or by a request connect command from a target application.

var currentDebugger = null;

// for internal use
var internalBT = { count:0 };
        
///////////////////////////////////////////////////////////////////////////////
//
// Debugger broadcaster
//
Debugger.broadcaster = new Broadcaster;

Debugger.registerClient = function( clientObj )
{ return Debugger.broadcaster.registerClient( clientObj ); }

Debugger.unregisterClient = function( clientObj )
{ Debugger.broadcaster.unregisterClient( clientObj ); }

Debugger.notifyClients = function( reason, param01, param02 )
{ Debugger.broadcaster.notifyClients( reason, param01, param02 ); }

// register for Debugger broadcasts
Debugger.registerClient( menus.debug );

//-----------------------------------------------------------------------------
// 
// setupDebugger(...)
// 
// Purpose: Initialize the debugger subsystem. Return false on errors.
// 
//-----------------------------------------------------------------------------

function setupDebugger( remote )
{
	Debugger.connect ("estoolkit-2.0", null, 0);
	return true;
}

///////////////////////////////////////////////////////////////////////////////
//
// Debugger class:
//
// The Debugger object is the core object that talks to the debugging
// backend. There is one Debugger object per active connection.
//

// Debugger status values

Debugger.RUNNING			= localize ("$$$/ESToolkit/Toolbar/Engine/State/Running=running");
Debugger.STOPPED			= localize ("$$$/ESToolkit/Toolbar/Engine/State/Stopped=stopped");
Debugger.WAITING			= localize ("$$$/ESToolkit/Toolbar/Engine/State/Waiting=waiting");
Debugger.INACTIVE			= "";

// The list of all debuggers.

Debugger.all = [];

// The list of all connected applications. This is an object whose
// properties are the BridgeTalk names of all connected apps with
// the value set to true.

Debugger.connected = {};

//-----------------------------------------------------------------------------
// 
// Debugger(...)
// 
// Purpose: ctor
// 
//-----------------------------------------------------------------------------

function Debugger (target, engine)
{
	this.parent				= currentDebugger; // in case the engine is bad
	this.target		        = target;		// the target name
	this.engine             = engine;		// the engine name
	this.dynamic	        = false;		// true if the engine is created on the fly
	this.waiting	        = false;		// true if the engine state is "waiting"
	this.error		        = null;			// on runtime errors, the error message
	this.document	        = null;			// the doc being debugged
	this.frame		        = -1;			// the stack frame we are looking at during debugging
	this.stack		        = "";			// the complete stack trace; force a redisplay of variables if changed
	this.line		        = -1;			// the current line
	this.documents	        = {};			// active documents collection; properties are script IDs
	this.profileLevel       = 0;			// the profiling level
	this.oldStack	        = false;		// for targets with versions <= 3.6.36
	this.resetLevel			= false;		// If set to true, send breakpoints and continue

	this.setState( Debugger.INACTIVE );
	
	// for now: first the static, then the dynamic
//	this.dictionary = app.loadDictionary (target);
//	if (!this.dictionary)
//		this.dictionary = new TargetDictionary (target);

	Debugger.all.push (this);
}

// The documents object holds information about the documents currently being debugged.
// Each property (which is the document's scriptID) contains an object with the following
// properties:
// document:    the Document object
// profData:    the Document profiler data (array of objects, objects containing the props line, hit, time)

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: [static] Connect to a target app. This call attempts to launch the target,
//                   identifies the app as the debugger, collects the list of engines,
//                   creates the necessary debugger instances, and activates the debugger
//                   on the first engine returned. The supplied name is the BridgeTalk name.
//                   If doc and dbgLevel are supplied, the connect request was due to an 
//                   autoconnect from within Debugger.start(). We need to fire a Start commend
//                   with these two arguments if present.
// 
//-----------------------------------------------------------------------------

Debugger.connect = function( target, doc, dbgLevel )
{
	if( !currentDebugger || 
	    ( currentDebugger && ( currentDebugger.target != target || !targetMgr.getConnected( target ) ) ) )
	{
        var busyID = false;
	    
        if( doc )
            busyID = doc.busyID;

	    globalBroadcaster.notifyClients( 'startConnect', target );

        if( !Debugger.doConnect( target, doc, dbgLevel, busyID, Debugger ) )
        {
		    app.stopBusyFor( busyID );
		    globalBroadcaster.notifyClients( 'endConnect', target );
		}
	}
	else if( currentDebugger )
		targetMgr.setActive( currentDebugger.target, currentDebugger.engine, doc );
}

Debugger.doConnect = function( target, doc, dbgLevel, busyID, clientObj )
{
    var ret = false;
    
    if( busyID )
    {
        this.busyID = busyID;
        app.startBusyFor( busyID );
    }

    if( !BridgeTalk.findInstance( target, 'Connect' ) )
    {
	    targetMgr.checkTarget( target );
   	    var bt      = BridgeTalk.create( target, "Connect", true );
	    bt.doc      = doc;
	    bt.dbgLevel = dbgLevel;
	    bt.dbg      = this;
	    bt.busyID   = this.busyID;
	    bt.client   = clientObj;

	    bt.onOwnError = function (bt)
	    {
	        if( this.busyID )
	        {
	            app.stopBusyFor( this.busyID );
	            delete this.busyID;
	        }

			// strip the debugger suffix if present
			var target = this.target.replace( "#estk", "" );

		    if( this.client && this.client.onConnected )
		        this.client.onConnected( false, target, this.doc );
		    
		    globalBroadcaster.notifyClients( 'endConnect', target, this.dbg );
	    }
    	
	    bt.onOwnResult = function (bt)
	    {
		    if( this.busyID )
		    {
		        app.stopBusyFor( this.busyID );
		        delete this.busyID;
            }

		    var engines = Debugger.setupConnection( bt, false, this.client );
    		
		    // strip the debugger suffix if present
		    var target = this.target.replace( "#estk", "" );
    		
		    // tell the TargetManager
		    targetMgr.addEngines( target );
    		
		    if( this.client && this.client.onConnected )
		        this.client.onConnected( true, target, engines, this.dbgLevel, this.doc );
		        
		    //
		    // remove dummy Debugger instances without engine
		    //
            for( var i=Debugger.all.length-1; i>=0; i-- )
            {
                if( Debugger.all[i].target == target && !Debugger.all[i].engine )
                    Debugger.all.splice(i,1);                    
            }
            		        
		    globalBroadcaster.notifyClients( 'endConnect', target, this.dbg );
        }

    	ret = bt.safeSend();
    }
    
    return ret;
}

Debugger.onConnected = function( connected, target, engines, dbgLevel, doc )
{
	if( connected )
	{
		if( target != 'estoolkit-2.0' )
		{
			app.toFront();
		}
		/*
		if( currentDebugger.target == target && doc )
		{
			if( engines == 1 )
				currentDebugger.start( doc, dbgLevel );
			else
			{
				var displayName = targetMgr.getTargetDisplayName( target );
				messageBox ("$$$/ESToolkit/Alerts/PleaseSwitch=Please select target %1!", displayName);
		// TODO
		//					window.engines.active = true;
			}
		}
		*/
	}
}

Debugger.connectSynchronous = function( target, doc, dbgLevel )
{
    function SyncHandler( targetName )
    {
        this.targetName = targetName;
        this.finished   = true;
    }
    SyncHandler.prototype.onNotify = function( reason )
    {
        if( reason == 'startConnect' && arguments[1] == this.targetName )
            this.finished = false;
        if( reason == 'endConnect' && arguments[1] == this.targetName )
            this.finished = true;
    }
    
    var syncObj = new SyncHandler( target );
    
    function checkFinished()
    {
        return !syncObj.finished;
    }
    
    globalBroadcaster.registerClient( syncObj );
    Debugger.connect( target, doc, dbgLevel );

    wait( checkFinished );
    globalBroadcaster.unregisterClient( syncObj );
}

//-----------------------------------------------------------------------------
// 
// remoteConnect(...)
// 
// Purpose: [static] Execute a remote connection request.
// 
//-----------------------------------------------------------------------------

Debugger.remoteConnect = function(bt)
{
    //
    // setup the connection
    //
	Debugger.setupConnection( bt, true/*, Debugger*/ ); // don't pass a callback obj so that onSetupConnection isn't called!

    //
    // probably we had no chance to collect all targets yet,
    // so add it to the TargetManager
    //    
	var target      = bt.sender.replace( "#estk", "" );
	var engine      = bt.headers.Engine;
    var displayName = BridgeTalk.getDisplayName( target );
    targetMgr.addTarget( target, displayName, true );
    targetMgr.addEngines( target );
    
    OMVData.load (target);
}

//-----------------------------------------------------------------------------
// 
// disconnect(...)
// 
// Purpose: [static] Disconnect all active debuggers from a target; called when 
//                   the target goes down.
// 
//-----------------------------------------------------------------------------

Debugger.disconnect = function (target, quiet)
{
    if( targetMgr.getConnected( target ) )
    {
	    targetMgr.setConnected( target, false );

        var lastDebugger = currentDebugger;
        
	    for (var i = 0; i < Debugger.all.length; i++)
	    {
		    var dbg = Debugger.all [i];
	
		    if (dbg.target == target)
		    {
			    if( dbg.state != Debugger.INACTIVE )
			    {
				    // for the first active debugger on a target, display the error message
				    if (!quiet)
				    {
					    errorBox ("$$$/ESToolkit/Alerts/TargetDead=%1 does not respond anymore!^nThe debugging session will be aborted.",
							      targetMgr.getTargetDisplayName (target));
					    quiet = true;
				    }

                    dbg.stop(true);	
			    }
				
				Debugger.all.splice(i,1);
				i--;
		    }
	    }

	    targetMgr.targetDied( target );
    }
}

//-----------------------------------------------------------------------------
// 
// getAll(...)
// 
// Purpose: [static] Get all debuggers for a given target.
// 
//-----------------------------------------------------------------------------

Debugger.getAll = function (target)
{
	var debuggers = [];
	
	for (var i = 0; i < Debugger.all.length; i++)
	{
		var dbg = Debugger.all [i];
		if (dbg.target == target)
			debuggers.push (dbg);
	}
	return debuggers;
}

Debugger.setCurrent = function( dbg )
{
    currentDebugger = dbg;
}

//-----------------------------------------------------------------------------
// 
// setupConnection(...)
// 
// Purpose: [static] Setup a debugger connection by reading the body of the given 
//                   BT message. This message is either a received ConnectRequest 
//                   message, or the reply of a Connect message. This will also 
//                   activate this debugger. Returns the number of engines discovered.
// 
//-----------------------------------------------------------------------------

Debugger.setupConnection = function( bt, remote, clientObj )
{
	var reply       = bt.splitBody();
	var target      = bt.sender.replace ("#estk", "");
	var selEngine   = bt.headers.Engine;
	var selDebugger = null;
	var engines     = 0;

	targetMgr.setConnected( target, true );

	for( var i=0; i<reply.length; i++ )
	{
		if( reply [i].length == 0 )
			// list of supported commands
			break;
			
		var engine = reply [i][0];
		var status = reply [i][1];

		if( !selEngine )
			selEngine = engine;
			
        //			
		// if we are connected by a remote request, the debugger is always active!
		// create the debugger if not yet present
		//
		var dbg = Debugger.find( target, engine );
		
		if( !dbg )
		{
		    //
		    // if there is a Debugger for the target available
		    // which has no engine assigned tom then use that instance
		    //
		    var emptyDbg = Debugger.find( target, '' );

            if( emptyDbg && !emptyDbg.engine )
            {
                dbg = emptyDbg;
                dbg.engine = engine;
            }
            else	    
			    dbg = new Debugger( target, engine );
        }
        
		dbg.dynamic = (status == "dynamic");
		
		if( engine == selEngine )
			selDebugger = dbg;
		
		engines++;
	}
	
	if( clientObj && clientObj.onSetupConnection )
	    clientObj.onSetupConnection( target, selDebugger, remote );

	// Load the OMV for this app
	if( !remote )
	    OMVData.load (target);

	return engines;
}

Debugger.onSetupConnection = function( target, selDebugger, remote )
{
    if( !BridgeTalk.findInstance( target, 'GetInfo' ) )
    {
        //
	    // add the engines
	    //
	    targetMgr.setActiveTarget( target );
	    targetMgr.addEngines( target );
    	
	    if( selDebugger )
	    {
		    if( remote )
		    {
				if( document )
					document.clearProfileData();
    			
			    selDebugger.profileLevel    = 0;
			    selDebugger.error		    = null;
			    selDebugger.documents	    = {};
    			
			    app.toFront();
		    }
    		
		    selDebugger.activate();
    		
		    //
		    // finally, spawn a GetInfo call to retrieve the version independent of BT
		    //
		    var bt = BridgeTalk.create( selDebugger.target, "GetInfo" );
		    bt.dbg = selDebugger;
    		
		    bt.onOwnResult = function (bt)
		    {
			    // line 1: the version, line 2: the supported commands
			    var features  = bt.body.split( '\n' );
			    
			    if( features.length > 1 )
			    {
			        features = features[1].split( ',' );
			        
			        for( var i=0; i<features.length; i++ )
			            targetMgr.setFeature( bt.sender, features[i], true );
			    }
		    }
    		
		    bt.safeSend();
	    }
    }
}

//-----------------------------------------------------------------------------
// 
// find(...)
// 
// Purpose: [static] Find a debugger by target name and engine name.
//					 If no engine name is supplied, find the first engine.
//					 This leads to the debugger using the first engine that
//					 the target returned; the user does not have to select an
//					 engine anymore. This mirrors the behavior for a double-clicked
//					 jsx file with just a #target directive.
//
// 
//-----------------------------------------------------------------------------

Debugger.find = function (target, engine)
{
	// strip the debugger suffix if present
	target = target.replace ("#estk", "");

	for (var i = 0; i < Debugger.all.length; i++)
	{
		var dbg = Debugger.all [i];

		if (dbg.target == target)
		{
			if (dbg.engine == engine || !engine)
				return dbg;
		}
	}
	return null;
}

//-----------------------------------------------------------------------------
// 
// queryExit(...)
// 
// Purpose: [static] Check for any open debug session. If found, ask the user if 
//                   ask is true. if it is OK to stop debugging, and, if so, 
//                   terminate debugging.
// 
//-----------------------------------------------------------------------------

Debugger.queryExit = function (ask)
{
	for (var i = 0; i < Debugger.all.length; i++)
	{
		var dbg = Debugger.all [i];
		if (dbg.isActive())
		{
			if (!ask && !queryBox ("$$$/ESToolkit/Alerts/StopDebugging=Stop debugging?"))
				return false;
			else
				break;
		}
	}

	for (i = 0; i < Debugger.all.length; i++)
	{
		var dbg = Debugger.all [i];
		if (dbg.isActive())
			dbg.stop();
	}
	return true;
}

//////////////////////////////////////////////////////////////////////
//
// Methods
//

//-----------------------------------------------------------------------------
// 
// activate(...)
// 
// Purpose: Mark this debugger as being active (i.e. its engine is running)
// 
//-----------------------------------------------------------------------------

Debugger.prototype.activate = function()
{
	if (this != currentDebugger)
	{
		if (currentDebugger)
			currentDebugger.clearProfData();

		Debugger.setCurrent( this );
		this.getVariables (true);
		this.restoreProfData();
		if (this.document)
			this.setDocument (this.document);
	}
	menus.debug.reflectState();
	targetMgr.setActiveEngine(this.target, this.engine, true);
	breakpoints.update();
}

//-----------------------------------------------------------------------------
// 
// isActive(...)
// 
// Purpose: Is this debugger active?
// 
//-----------------------------------------------------------------------------

Debugger.prototype.isActive = function()
{
	return (this.state == Debugger.RUNNING || this.state == Debugger.STOPPED);
}

//-----------------------------------------------------------------------------
// 
// start(...)
// 
// Purpose: eval the contents of a document in the target engine
// 
//-----------------------------------------------------------------------------

Debugger.prototype.start = function (doc, dbgLevel, saveFiles)
{
    //
    // Save all docs
    //
    if( PrefUtils.getValue( 'prefs.debug.saveBeforeDebug', 'Boolean' ) && saveFiles && !Document.saveAll(true) )
	    return;

    //
    // include path set
    //
    var includePath = '';
    
    if( !doc.includePath || ( doc.includePath && doc.includePath.length == 0 ) )
    {
        var f = new File( doc.scriptID );
        
        if( f.exists )
			doc.includePath = f.parent ? f.parent.absoluteURI : "/";
    }
    
    //
    // check the syntax
    //
    if( doc.checkSyntax( doc.includePath ) )
    {
        // Does the doc contain a #target directive?
        var engine = null;
		// returns [target,engine]
        var target = app.scanForTargetDirective( doc.text, doc.scriptID );

        var targetDebugger = this;

        if( target )
        {
            engine = target[1] ? target[1] : '';
            target = target[0];
			
			if (!target)
				target = this.target;
        }
		
        // expand to full specifier
        // target must not contain a #suffix
        if( target && target.indexOf('#') < 0 )
	        target = BridgeTalk.getSpecifier (target);

		if( !engine || engine.length == 0 )
		{
			var targetObj = targetMgr.findTarget( target );
			
			if( targetObj )
			{
				engine = targetObj.getActive();
				
				if( !engine )
				{
					var engines = targetObj.getEngines()
					
					if( engines.length > 0 )
						engine = engines[0];
				}
			}
		
			if( !engine || engine.length == 0 )	
				engine = this.engine;
    	}
		
        if( !target )
        {
            //
	        // no target given: use this debugger
	        //
	        target = this.target;

	        if (!engine)
		        engine = this.engine;
        }

        //
        // access the internal engine for testing purpose
        // with target directive estoolkit#dbg
        //
        if( target && target == 'estoolkit#dbg' )
        {
            print( eval( doc.text ) );
            return;
            
            /*
            var bt      = new BridgeTalk;
            bt.target   = target;
            bt.body     = doc.text;
            bt.index    = internalBT.count;

            internalBT[internalBT.count++] = bt;
            
            bt.onResult = bt.onError = bt.onTimeout = function(bt)
            {
                print( bt.body );
                internalBT[this.index] = null;
            }
            
            bt.send();
            return;
            */
        }

        if( target )
	        targetDebugger = Debugger.find (target, engine);
        else
	        targetDebugger = null;

        if (!targetDebugger)
        {
	        if( targetMgr.getConnected( target ) )
	        {
				targetDebugger = new Debugger( target, engine );
				/*
		        // The target does not support the given target/engine
		        var displayName = targetMgr.getTargetDisplayName (target);
		        if (!displayName)
			        displayName = target;
		        if (engine.length)
			        displayName += " (" + engine + ")";
		        errorBox ("$$$/ESToolkit/Alerts/CannotConnect=Cannot connect to target %1!", displayName);
				*/
	        }
	        else
			{
		        // no idea if the target contains the engine.
		        // Connect and have start() called again.
		        Debugger.connectSynchronous( target, doc, dbgLevel );                    
                var delayedSrc = 'if(targetMgr.getConnected("' + target + '"))currentDebugger.start( Document.find("'+doc.scriptID+'"),'+dbgLevel+','+saveFiles+');';
                app.scheduleTask( delayedSrc, 1, false );
				return;
			}
        }
        else
        {
	        if( !targetMgr.getConnected( targetDebugger.target ) )
	        {
	            //
		        // oops...no connection...
		        // setup connection synchron and continue if successfull
		        //
		        Debugger.connectSynchronous( targetDebugger.target, doc, dbgLevel );                    
                var delayedSrc = 'if(targetMgr.getConnected("' + targetDebugger.target + '"))currentDebugger.start( Document.find("'+doc.scriptID+'"),'+dbgLevel+','+saveFiles+');';
                app.scheduleTask( delayedSrc, 1, false );
		        
		        return;
	        }
        }
    	
    	if( !this.isActive() )
    	{
            // OK, we came here, so we have a target debugger.
            // This may not be the same as "this", because the doc may have had
            // #target / #targetengine defined...
            targetDebugger.startSession (doc, dbgLevel);
        }
    }
}

//-----------------------------------------------------------------------------
// 
// startSession(...)
// 
// Purpose: Start a debug session without checking any #target / #targetengine
//			in the document.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.startSession = function (doc, dbgLevel)
{
    if( dbgLevel == undefined )
	    dbgLevel = 0;
	
    //
    // If the debug level is 1 (call debugger on break) then set
    // debug level to 2 (call debugger immediately) to set breakpoints
    // again (for targets that create engines on the fly)
    //
    if( dbgLevel == 1 )
    {
        dbgLevel = 2;
        this.resetLevel = true;
    }

    //
    // if this isn't the current debugger then switch to this
    // (switch back if execution failed)
    //
    var oldCurrent = null;
    var oldTarget = null;
    var oldEngine = null;

    if( this != currentDebugger )
    {
	    oldCurrent = currentDebugger;
	    Debugger.setCurrent( this );

	    oldTarget = targetMgr.getActiveTarget();
	    oldEngine = ( oldTarget ? oldTarget.getActive() : null );
	    targetMgr.setActiveEngine( this.target, this.engine, true );
    }
	
    this.profileLevel = PrefUtils.getValue( 'prefs.profiling.profileLevel', 'Number' );
	
    if( this.profileLevel )
        if( doc )
	        doc.clearProfileData();
    else
	    this.profileLevel = 0;
		
    this.setState( Debugger.RUNNING );
    this.error              = null;
    this.line               = -1;
    this.clearDocuments();
    this.setDocument( doc );

    Document.setStatusLine( '', doc );
	
    var bt                  = BridgeTalk.create (this.target, "Eval");
    bt.headers.Engine       = this.engine;
    bt.headers.DebugLevel   = dbgLevel;
    bt.headers.ScriptID     = doc.scriptID;
    bt.headers.Profiling    = this.profileLevel;
    bt.headers.DebugFlags   = PrefUtils.getValue( 'prefs.debug.dontBreakOnErrors', 'Boolean' ) ? 1024 : 0;
	
    // add the debugger for onResult
    bt.dbg                  = this;
	
    bt.onOwnResult = function (bt)
    {
	    this.dbg.stop (true);
	    // the reply is datatype,result
	    var reply = bt.splitBody();
		
	    if( reply && reply.length && reply[0].length )
	        print (reply [0][1]);
    }
    bt.onOwnError = function (bt)
    {
	    this.dbg.stop (true);
	    // display the error message
	    // if there is no line number and script name info, use an alert
	    // but not if the error is "Execution Halted"
	    var errCode = parseInt (bt.headers ["Error-Code"]);
	    if (!bt.headers.ScriptID && errCode != -34)
	    {
		    // if the error code is 32 (kErrBadAction), assume that there
		    // was no engine to execute in.
		    var msg = bt.body;
		    if (errCode == 32)
		    {
			    msg = localize ("$$$/ESToolkit/Error/MissingEngine=Cannot execute script in target engine '%1'!",
							    this.headers.Engine);
			    // reset the current debugger to the parent of this one
			    if (this.dbg.parent)
				    Debugger.setCurrent (this.dbg.parent);
		    }
		    else if (msg == "ENGINE BUSY")
			    msg = localize ("$$$/ESToolkit/Error/EngineBusy=Target engine '%1' is busy!",
							    this.headers.Engine);
		    errorBox (msg);
	    }
    }
	
    // send the text if the doc is modified or out of sync with the disk image
    if( doc.isModified() )
	    bt.body = doc.text;

    this.currentBusyID = doc.busyID;
    app.startBusyFor( this.currentBusyID, false );
    
    if( bt.safeSend() )
    {
        // show that this debugger is active
        this.activate();
    }
    else
    {
	    //
	    // switch back to previous current debugger
	    //
	    if( oldCurrent )
		    Debugger.setCurrent( oldCurrent );
		
	    if( oldTarget )
		    targetMgr.setActiveEngine( oldTarget.targetName, oldEngine, true );
		
	    //
	    // stop debugger
	    //
        bt.onOwnError(bt);
    }
/*	
    //
    // eval command via XML
    //
    if( dbgLevel == undefined )
	    dbgLevel = 0;
	
    //
    // if this isn't the current debugger then switch to this
    // (switch back if execution failed)
    //
    var oldCurrent = null;
    var oldTarget = null;
    var oldEngine = null;

    if( this != currentDebugger )
    {
	    oldCurrent = currentDebugger;
	    Debugger.setCurrent( this );

	    oldTarget = targetMgr.getActiveTarget();
	    oldEngine = ( oldTarget ? oldTarget.getActive() : null );
	    targetMgr.setActiveEngine( this.target, this.engine, true );
    }
	
    this.profileLevel = PrefUtils.getValue( 'prefs.profiling.profileLevel', 'Number' );
	
    if( this.profileLevel )
    {
        if( doc )
	        doc.clearProfileData();
	}
    else
	    this.profileLevel = 0;
		
    this.setState( Debugger.RUNNING );
    this.error              = null;
    this.line               = -1;
    this.clearDocuments();
    this.setDocument( doc );

    Document.setStatusLine( '', doc );
	
    var cmd = new XML( '<eval engine="' + this.engine + '" file="' + doc.scriptID + '" walkstack="true" timeout="0" debug="' + dbgLevel + '" profile="' + this.profileLevel + '"></eval>' );
    var targetObj = targetMgr.findTarget( this.target );
    
    if( targetObj )
    {
        var bps = targetObj.getBreakpointsXML( this.engine, ( PrefUtils.getValue( 'prefs.debug.dontBreakOnErrors', 'Boolean' ) ? 1024 : 0 ) );
        
        if( bps )
            cmd.appendChild( bps );
    }
    
    // send the text if the doc is modified or out of sync with the disk image
    if( doc.isModified() )
    {
        var src = new XML( '<source>' + doc.text + '</source>' );
        cmd.appendChild( src );
    }

    var bt  = BridgeTalk.create( this.target );
    
    bt.body = cmd.toXMLString();
    // add the debugger for onResult
    bt.dbg  = this;
	
    bt.onOwnResult = function (bt)
    {
        //
        // TODO: format of result (XML?)
        //
	    this.dbg.stop (true);
	    // the reply is datatype,result
	    var reply = bt.splitBody();
		
	    if( reply && reply.length && reply[0].length )
	        print (reply [0][1]);
    }
    bt.onOwnError = function (bt)
    {
        //
        // TODO: format of result (XML?)
        //
	    this.dbg.stop (true);
	    // display the error message
	    // if there is no line number and script name info, use an alert
	    // but not if the error is "Execution Halted"
	    var errCode = parseInt (bt.headers ["Error-Code"]);
	    if (!bt.headers.ScriptID && errCode != -34)
	    {
		    // if the error code is 32 (kErrBadAction), assume that there
		    // was no engine to execute in.
		    var msg = bt.body;
		    if (errCode == 32)
		    {
			    msg = localize ("$$$/ESToolkit/Error/MissingEngine=Cannot execute script in target engine '%1'!",
							    this.headers.Engine);
			    // reset the current debugger to the parent of this one
			    if (this.dbg.parent)
				    Debugger.setCurrent (this.dbg.parent);
		    }
		    else if (msg == "ENGINE BUSY")
			    msg = localize ("$$$/ESToolkit/Error/EngineBusy=Target engine '%1' is busy!",
							    this.headers.Engine);
		    errorBox (msg);
	    }
    }
	
    this.currentBusyID = doc.busyID;
    app.startBusyFor( this.currentBusyID, false );
    
    if( bt.safeSend() )
    {
        // show that this debugger is active
        this.activate();
    }
    else
    {
	    //
	    // switch back to previous current debugger
	    //
	    if( oldCurrent )
		    Debugger.setCurrent( oldCurrent );
		
	    if( oldTarget )
		    targetMgr.setActiveEngine( oldTarget.targetName, oldEngine, true );
		
	    //
	    // stop debugger
	    //
        bt.onOwnError(bt);
    }
*/	    
}

//-----------------------------------------------------------------------------
// 
// stop(...)
// 
// Purpose: Stop debugging. Get the final profiling data, the final variables, 
//          and clear the stack trace display.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.stop = function (dontHalt)
{
    app.stopBusyFor( this.currentBusyID );
    
	// halt the engine
	if (this.isActive())
	{
		if (!dontHalt)
			this.execute ("Halt");
	}
	if (this.profileLevel)
		this.getProfData (true);
	this.setStoppedState();

	// no stack display
	callstack.erase();
	this.getVariables (true);
	app.toFront();
}

//-----------------------------------------------------------------------------
// 
// setState(...)
// 
// Purpose: Set the state of the debugger with reflection into the UI.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.setState = function (state)
{
    //
	// cannot set a state of Inactive if the engine is in Waiting state
	//
	if( this.waiting && state == Debugger.INACTIVE )
		state = Debugger.WAITING;

    var oldstate = this.state;		
	this.state = state;
	
	if( this == currentDebugger && oldstate != this.state )
	    Debugger.notifyClients( 'state', this, oldstate, this.state );
}

//-----------------------------------------------------------------------------
// 
// setStoppedState(...)
// 
// Purpose: Put this debugger into a stopped state without sending any messages.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.setStoppedState = function()
{
	this.setState (Debugger.INACTIVE);
	this.error	= null;
	this.frame	= -1;
	this.stack	= "";
    this.line = -1;

	if (this.document)
		this.document.setCurrentLine (this.line, 0xFFFFFF);
    
	this.clearDocuments();
}

//-----------------------------------------------------------------------------
// 
// eval(...)
// 
// Purpose: Do a eval of the supplied text without any breakpoints etc.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.eval = function (text, noReply)
{
	// this BridgeTalk instance does not carry any script ID
	var bt                  = BridgeTalk.create (this.target, "Eval");
	bt.headers.Profiling    = this.profileLevel;
	bt.headers.Engine       = this.engine;
	bt.body                 = text;
	bt.dbg                  = this;
	bt.noReply              = noReply;
	
	bt.onResult = function (bt)
	{
		// the reply is datatype,result
		if (!this.noReply)
		{
			var reply = bt.splitBody();
			var result = '';
			
			if( reply && reply[0] )
			    result = reply[0][1];
			    
			print (localize ("$$$/ESToolkit/Panes/Console/Result=Result:"), ' ', result );
		}
		this.dbg.getVariables();
		this.destroy();
	}
	
	bt.onOwnError = function (bt)
	{
		// the reply is the message
		print (localize ("$$$/ESToolkit/Panes/Console/Error=Error:"), ' ', bt.body);
		app.beep();
	}
	
	bt.onOwnTimeout = function(bt)
	{
	    // ignore timeout
	}
	
	bt.safeSend();
}

//-----------------------------------------------------------------------------
// 
// getVariables(...)
// 
// Purpose: Get the variables of the current scope.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.getVariables = function (all)
{
	// get only for engines that are either not dynamic, or that are active
	if (!this.dynamic || this.state != Debugger.INACTIVE)
		databrowser.getVariables (this.target, this.engine, (this.state != Debugger.STOPPED), all);
	else
		databrowser.erase();
}

//-----------------------------------------------------------------------------
// 
// getProfData(...)
// 
// Purpose: Get the profiling data of this execution.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.getProfData = function (erase)
{
	if (!this.profileLevel)
		return;
	var bt = BridgeTalk.create (this.target, "ProfilerData");
	bt.headers.Engine = this.engine;
	if (erase)
		bt.headers.Clear = "1";
	bt.dbg = this;
	bt.onOwnResult = function (bt)
	{
		if (this.dbg.profileLevel)
		{
			var docObj = null;
			var prevScriptID = null;

			var reply = bt.splitBody();
			// fill this object with existing data for easier access
			var profDataObjs = [];
			if (document.profdata)
			{
				for (var i = 0; i < document.profData.length; i++)
				{
					var profObj = document;profData[i];
					profDataObjs [profObj.line] = profObj;
				}
			}
			for (var i = 0; i < reply.length; i++)
			{
				// line, time, hits, function, module
				var line = +reply [i][0];
				var time = +reply [i][1];
				var hits = +reply [i][2];
				// var func =  reply [i][3];
				var scriptID = reply [i][4];
				// this is only transmitted on change
				if (scriptID)
				{
					// get that doc
					if (!docObj || prevScriptID != scriptID)
					{
						docObj = this.dbg.documents [scriptID];
						if (!docObj)
						{
							doc = Document.find (scriptID);
							if (!doc)
								continue;	// doc seems to be closed already
							docObj = this.dbg.documents [scriptID] = { document:doc, line:-1 };
						}
						// set the profiler data for the previous doc
						if (prevScriptID)
							this.dbg.restoreProfData (prevScriptID);
						prevScriptID = scriptID;
					}
				}
				if (docObj)
				{
				    if( !docObj.profData )
				        docObj.profData = new Array;
				        
				    var entry = profDataObjs [line];
				    if( entry )
				    {
				        entry.hit  = hits;
				        entry.time = time;
				    }
				    else
					{
						var profObj = { line : line, hit : hits, time : time };
				        docObj.profData.push( profObj );
						profDataObjs [line] = profObj;
					}
				}
			}
			// show for the last doc
			if (prevScriptID)
				this.dbg.restoreProfData (prevScriptID);
		}
	}
	bt.safeSend();
}

//-----------------------------------------------------------------------------
// 
// clearProfData(...)
// 
// Purpose: Clear the profiling data for this debugger during deactivation.
//          If the script ID is given, just restore the data for the given document.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.clearProfData = function (scriptID)
{
	if (this.profileLevel)
	{
		if (scriptID)
		{
			// for a specific document
			var docObj = this.documents [scriptID];

			if (docObj)
				docObj.document.clearProfileData();
		}
		else
		{
			for (var scriptID in this.documents)
				this.clearProfData (scriptID);
		}
	}
}

//-----------------------------------------------------------------------------
// 
// restoreProfData(...)
// 
// Purpose: Restore the code profiler data for this debugger during activation.
//          If the script ID is given, just restore data for the given document.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.restoreProfData = function (scriptID)
{
	if (this.profileLevel)
	{
		if (scriptID)
		{
			// for a specific document
			var docObj = this.documents [scriptID];
			
			if( docObj && docObj.profData )
			{
			    docObj.document.profileData = docObj.profData;
			    docObj.document.updateProfData();
			}
		}
		else
		{
			for (var scriptID in this.documents)
				this.restoreProfData (scriptID);
		}
	}
}

//-----------------------------------------------------------------------------
// 
// getHelpTip(...)
// 
// Purpose: Get the help tip text for the given text.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.getHelpTip = function (doc, line, text)
{
	// Can only do help tips if not running if the engine is not dynamic
	if (this.dynamic && !this.isActive())
	{
		doc.helpTip = "";
		return;
	}

	if (this.error && line == this.line)
		// display the error
		doc.helpTip = this.error;
	else if (text.length && !app.checkSyntax (text).error)
	{
		// we create a simple Eval command and ignore any errors
		var bt = BridgeTalk.create (this.target, "Eval");
		bt.headers.Engine = this.engine;
		// we want the target to walk the stack until we have a result
		bt.headers.WalkStack = 1;
		// no script ID - we supply the script on the fly
		bt.doc  = doc;
		bt.text = text;
		bt.dbg  = this;
		// the result handler creates something like 'type name = value'
		// and sets the help tip
		bt.onOwnResult = function (bt) 
		{
			// the doc attached to the BridgeTalk instance
			var doc = this.doc;
			if (doc)
			{
				// the reply of eval is datatype,result
				var reply = bt.splitBody();
				var dataType = '';
				var result   = '';
				
				if( reply && reply.length && reply[0].length )
				{
				    dataType = reply [0][0];
				    result   = reply [0][1];
				}
				
				if (dataType == "Function")
					text = dataType + ' ' + this.text;
				else if (dataType != "undefined")
				{
					if (dataType == "string")
					{
						result = '"' + app.escape (result) + '"';
						// Truncate a string after 20 characters
						if (result.length > 20)
							result = result.substr (0, 20) + '"...';
					}
					text = dataType + ' ' + this.text + ' = ' + result;
				}
				else if (this.text == "undefined")
					text = "";
				doc.helpTip = text;
			}
		}
		// the error handler displays the error
		bt.onOwnError = function (bt)
		{
			// the doc attached to the BridgeTalk instance
			if (this.doc)
				this.doc.helpTip = bt.body;
		}
		bt.body = text;
		bt.safeSend();
	}
	else
		doc.helpTip = "";
}

//-----------------------------------------------------------------------------
// 
// doContinue(...)
// 
// Purpose: Continue the execution after a breakpoint.
//          If the debugger is inactive, start a session.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.doContinue = function (doc, dbgLevel)
{
	if (dbgLevel == undefined)
		dbgLevel = 1;

    Document.setStatusLine( '', doc );

	if (this.state == Debugger.RUNNING)
		return;

	if (this.state == Debugger.STOPPED)
	{
		// clear the current line
		if (this.document)
			this.document.setCurrentLine (this.line, 0xFFFFFF);
		this.execute ("Continue");
	}
	else
	{
		// execute the given document
		// first, check the syntax
		var result = doc.compile( doc.includePath );
		// a compiled script starts with '@'
		if (result[0] == '@')
			// if OK, send over to the target
			this.start (doc, dbgLevel);
		else
		{
			// otherwise, display the error and beep
            Document.setStatusLine( result, doc );
			app.beep();
		}
	}
}

//-----------------------------------------------------------------------------
// 
// execute(...)
// 
// Purpose: Start/continue debugging by issuing the given command if the 
//          debugger is active.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.execute = function (cmd)
{
	if (cmd == "Continue" && this.state != Debugger.STOPPED)
		return;

	var bt                  = BridgeTalk.create (this.target, cmd);
	bt.headers.Engine       = this.engine;
	bt.headers.Profiling    = this.profileLevel;
	bt.headers.IgnoreErrors = 0;
	bt.headers.DebugFlags   = PrefUtils.getValue( 'prefs.debug.dontBreakOnErrors', 'Boolean' ) ? 1024 : 0;
	bt.dbg                  = this;
	
	if (this.document)	// the doc may not be there if there was a load error
		bt.headers.ScriptID = this.document.scriptID;

	// ask whether to clear any runtime error first
	if (cmd != "Halt")
	{
		if (this.error && queryBox ("$$$/ESToolkit/Alerts/ClearErrors=Clear runtime error?"))
		{
			bt.headers.IgnoreErrors = 1;
		}
		if (this.document)
			// re-attach existing breakpoints
			targetMgr.sendBreakpoints( this.target, this.engine );
	}
	
	this.setState (Debugger.RUNNING);
	this.error = null;
	
	bt.safeSend();
	
	// Indicate the execution by switching the document to front
	if (this.document)
		this.document.activate();
}

//-----------------------------------------------------------------------------
// 
// loadScript(...)
// 
// Purpose: Load a script from the target.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.loadScript = function (scriptID)
{
	scripts.loadScript (this.target, this.engine, ScriptID, 
						targetMgr.getTargetDisplayName (this.target), this);
}

//-----------------------------------------------------------------------------
// 
// showNextStatement(...)
// 
// Purpose: Scroll the current document to the current line
// 
//-----------------------------------------------------------------------------

Debugger.prototype.showNextStatement = function()
{
	if (this.state == Debugger.STOPPED)
		callstack.switchToBottom();
}

//-----------------------------------------------------------------------------
// 
// switchFrame(...)
// 
// Purpose: In halt mode, switch to the given stack frame
// 
//-----------------------------------------------------------------------------

Debugger.prototype.switchFrame = function (frame)
{
	if (this.frame != frame)
	{
		var bt = BridgeTalk.create (this.target, "SwitchFrame");
		bt.headers.Engine = this.engine;
		if (this.oldStack)
			frame = callstack.getFrames() - frame;
		bt.body = frame;
		bt.safeSend();
	}
}

//-----------------------------------------------------------------------------
// 
// processMsg(...)
// 
// Purpose: Process a received message
// 
//-----------------------------------------------------------------------------

Debugger.prototype.processMsg = function (bt)
{
	switch (bt.headers.Command)
	{
		case "Print":		// print msg to console
			console.print (bt.body);
			break;

		case "Breakpoints":	// list of moved or removed breakpoints
            // shouldn't happen any more		
			var doc = Document.find (bt.headers.ScriptID);
			if (doc)
				doc.updateBreakpoints (bt);
			break;

		case "Error":	// runtime error
			this.error = bt.headers.ErrorMessage.replace (/\\n-/g, " ");
			
			if( this.error == "ENGINE BUSY" )
			{
			    errorBox( "$$$/ESToolkit/Messages/EngineBusy=The target engine is currently busy." );
			    break;
			}
			else
			{
			    // if the debugger is active, this is a halt at a throw
			    if (this.state == Debugger.RUNNING && bt.headers.ErrorCode == 54)
				    this.error = localize ("$$$/ESToolkit/Messages/ExceptionThrown=JavaScript exception thrown");
                Document.setStatusLine(this.error);
				app.beep();
            }
			// fall thru
		case "Break":	// breakpoint hit
		case "Frame":	// stack frame changed
		{		
			// If in a modal state, do not stop
			if (app.modalState)
			{
				this.state = Debugger.STOPPED;
				this.execute ("Continue");
				break;
			}
			// Create an object containing all important information.
			var breakData = {};
			breakData.line      = parseInt (bt.headers.CurrentLine);
			breakData.frame     = parseInt (bt.headers.Frame);
			breakData.frame		= ((isNaN( breakData.frame ) || breakData.frame < 0) ? 0 : breakData.frame);
			breakData.source	= null;
			breakData.allVars	= false;
			breakData.stack		= null;

		    if( bt.headers.Command != "Frame" )
		    {
		        //
			    // the body contains the stack trace, a newline, and the source
			    //
			    var srcStart		= bt.body.indexOf ("\n\n");
			    breakData.stack		= bt.body;
				
			    if( srcStart >= 0 )
			    {
				    breakData.stack		= bt.body.substr( 0, srcStart + 1 );
				    breakData.source	= bt.body.substr( srcStart + 2 );
			    }
			    //
			    // need to redisplay all vars if the stack changed
			    //
			    breakData.allVars	= (breakData.stack != this.stack);
		    }

            //
		    // set up the document
		    //
			breakData.doc = this.document;
			
		    if( !breakData.doc || ( bt.headers.ScriptID.length > 0 && breakData.doc.scriptID != bt.headers.ScriptID ) )
			    breakData.doc = Document.find( bt.headers.ScriptID );

            var newDocCreated = false;
            
		    if (!breakData.doc)
		    {
		        //
			    // no doc yet - it came from the target
			    //
			    if( File( bt.headers.ScriptID ).exists )
			    {
			        var docWin = scripts.loadFile( bt.headers.ScriptID );
					
				    if( docWin )
				        breakData.doc = docWin.document;
			    }
			    else if( breakData.source )		// supplied by break
			    {
				    var docWin = Document.create( this.title, breakData.source, bt.headers.ScriptID );
					
				    if( docWin )
				        breakData.doc = docWin.document;
			    }
			    else
			    {
				    // no source supplied (pre-x41): set off an async get script request
				    scripts.loadScript( bt.headers.ScriptID, this.title, this.target, this.engine );
				    // may be there already...
				    breakData.doc = Document.find (bt.headers.ScriptID);
			    }
			    
			    newDocCreated = ( breakData.doc != this.document );
			    
			    if( newDocCreated )
			        breakData.doc.window.visible = false;
		    }

			// OK, the breakData has all relevant data:
			// line		- the line number
			// frame	- the stack frame index
			// doc		- the document (may be generated on the fly)
			// allVars	- true to reload all variables into the Data Browser

			if( breakData.doc )
			{
			    breakData.doc.activate();
			    
			    var targetObj = targetMgr.findTarget( this.target );
			    
			    if( targetObj )
			    {
			        targetObj.setActive( this.engine );
			        breakData.doc.selectActiveTarget( targetObj )
			    }
			}
			else
			    break;

		    if( this.resetLevel )
			{
				//
				// If the flag resetLevel is set, then the script was started
				// to run. We got the break here to set breakpoints again and
				// continue (for targets that create engines on the fly)
				//
				this.resetLevel = false;
				targetMgr.sendBreakpoints( this.target, this.engine );
				// Only continue if this is not a real breakpoint
				if (!breakData.doc.getBreakpoint( breakData.line ))
				{
				    if( newDocCreated )
				        breakData.doc.close();
				        
					this.state = Debugger.STOPPED;
					this.execute ("Continue");
					break;	// done with processing
				}
			}

			// If we came here, the debugger needs to be activated, and
			// the breakpoint needs to be displayed
			
			if( breakData.doc )
			    breakData.doc.window.visible = true;

		    this.activate();
			this.setState (Debugger.STOPPED);

		    this.line	= breakData.line;
		    this.frame	= breakData.frame;
			if (breakData.stack)
			{
				this.stack	= breakData.stack;
				callstack.update( breakData.stack );
			}

	        if( this.currentBusyID && breakData.doc != this.document )
	        {
	            if( app.isBusy( this.currentBusyID ) )
	                app.stopBusyFor( this.currentBusyID );
                
                this.currentBusyID = null;
	        }
		    
		    this.setDocument(breakData.doc);

            if( !this.currentBusyID )
            {
                this.currentBusyID = breakData.doc.busyID;

		        if( !app.isBusy( this.currentBusyID ) )
		            app.startBusyFor( this.currentBusyID );
            }

		    // Get local variables, get all variables if the stack trace changed
		    this.getVariables (breakData.allVars);
		    // and get the profiler data
		    if (this.profileLevel)
			    this.getProfData (false);
		    app.toFront();
		}
		break;

		case "Exit":
			this.stop (true);
			break;
	}
}

//-----------------------------------------------------------------------------
// 
// setDocument(...)
// 
// Purpose: Set the current document and highlighting.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.setDocument = function (doc, noErrors)
{
	var color = colors.LightGreen;
	var errorMsg = "";
	if (this.frame == 0 && !noErrors)
	{
		color = colors.Yellow;
		if (this.error)
		{
			color = colors.Coral;
			errorMsg = this.error;
		}
	}
    Document.setStatusLine( errorMsg, doc );
	if (this.line >= 0)
	{
		doc.setCurrentLine (this.line, color);
		// scroll to that line
		doc.setSelection (this.line, 0, true);
	}
	// Add the doc to my documents list if not present
	var docObj = this.documents [doc.scriptID];
	
	if(!docObj)
		this.documents [doc.scriptID] = docObj = { document:doc, profData:null };
		
	// bring the document to front
	if (this.document != doc)
	{
	    if( this.document )
    		this.document.setCurrentLine( this.line, 0xFFFFFF );

		this.document = doc;
    }
    
	if (doc)
		doc.activate();
}

//-----------------------------------------------------------------------------
// 
// closeDocument(...)
// 
// Purpose: Remove a document from the debugger because it is about to being closed.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.closeDocument = function (doc)
{
	delete this.documents [doc.scriptID];
	if (this.document == doc)
		this.document = null;
}

Debugger.prototype.getDocumentsLength = function()
{
    var num = 0;
    
    for( i in this.documents )
        num++;
        
    return num;
}

//-----------------------------------------------------------------------------
// 
// isDocumentActive(...)
// 
// Purpose: Check if the given document is actively being debugged.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.isDocumentActive = function (doc)
{
	return (this.isActive()
	    &&  this.documents [doc.scriptID]
	    && (this.documents [doc.scriptID].document == doc));
}

//-----------------------------------------------------------------------------
// 
// clearDocuments(...)
// 
// Purpose: Erase all documents.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.clearDocuments = function()
{
	this.document	=
	this.lines		= null;
	this.documents	= {};
}

//-----------------------------------------------------------------------------
// 
// toFront(...)
// 
// Purpose: Request a bring-to-front.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.toFront = function()
{
	// up to now every client supports that (pwollek:01/24/2007)
    if (_win)
	{
		var bt = BridgeTalk.create (this.target, "ToFront");
		bt.headers.ID = app.id;
		bt.send();
		return true;
	}
	else
		// Non-Windows: signal app to use BridgeTalk
		return false;
}

//-----------------------------------------------------------------------------
// 
// getCodeHints (text)
// 
// Purpose: Return an array of code hints. The argument is a text string, which
// can either be a class name, an element name, or a class name, a dot and an
// element name. If an OMV for the target app is present, an array of text strings
// is returned that match possible elements. Use this API mainly to find elements
// unless you are sure about the class.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.getCodeHints = function (text)
{
	return OMVData.getCodeHints( this.target, this.engine, text );
}

//-----------------------------------------------------------------------------
// 
// displaySelectedCodeHint (text)
// 
// Purpose: Call this API with the original text selected by the user to cause 
// the OMV UI to update its display to the user selection.
// 
//-----------------------------------------------------------------------------

Debugger.prototype.displaySelectedCodeHint = function (text)
{
	return OMVData.displaySelectedCodeHint( this.target, this.engine, text );
}
