/**************************************************************************
*
*  @@@BUILDINFO@@@ 05targetinfo-2.jsx 2.0.2.77  05-December-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.
**************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//
// class TargetManager
//

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

function TargetManager( defaultTarget, defaultTitle )
{
    this.defaultTarget  = null;
    this.targetsInfo    = new Array;
    this.activeTarget   = null;

    this.broadcaster    = new Broadcaster;    
    
    this.changing       = 0;
	
	globalBroadcaster.registerClient( this );

    var defTarget = 'estoolkit-2.0';
    var defTitle = 'ExtendScript Toolkit 2';
    
    if( defaultTarget )
        defTarget = defaultTarget;
        
    if( defaultTitle )
        defTitle = defaultTitle;
        
    this.setDefault( defTarget, defTitle );        
}

TargetManager.prototype.onNotify = function( reason )
{
	if( reason == 'shutdown' )
	{
	    globalBroadcaster.unregisterClient( this );
		this.unregisterAllClients();
	}
}

//-----------------------------------------------------------------------------
// 
// targetDied(...)
// 
// Purpose: given target shut down
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.targetDied = function( targetName, dontnotify )
{
	var target = this.findTarget( targetName );
	
	if( target )
	{
		this.removeEngines( targetName );

		if( !dontnotify )	    
			this.notifyClients( 'targetDied', target );
	}
}

//-----------------------------------------------------------------------------
// 
// setDefault(...)
// 
// Purpose: set the default target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.setDefault = function( targetName, title )
{
    if( this.findTarget( targetName ) == null )
    {
		if( title[0] >= 'a' && title[0] <= 'z' )
			title = title.toUpperCase()[0] + title.substr (1);

        var info = new TargetInfo( targetName, title, this );
        this.defaultTarget = info;
    }
}

//-----------------------------------------------------------------------------
// 
// addTarget(...)
// 
// Purpose: add a target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.addTarget = function( targetName, title, dontnotify )
{
    if( this.findTarget( targetName ) == null )
    {
		if( title[0] >= 'a' && title[0] <= 'z' )
			title = title.toUpperCase()[0] + title.substr (1);

        var specifier = targetName.split( '-' )[0];
        var ip = specifier.lastIndexOf( '_' );
        
        if( ip >= 0 )
            title += ' (' + specifier.substr( ip+1 ) + ')';
        
        var info = new TargetInfo( targetName, title, this );
        this.targetsInfo.push( info );

        if( !dontnotify )	    
            this.notifyClients( 'addTarget', info );
    }
}

//-----------------------------------------------------------------------------
// 
// addEngines(...)
// 
// Purpose: add engines to target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.addEngines = function( targetName )
{
    var target = this.findTarget( targetName );
    
    if( target )
        target.addEngines();
}

TargetManager.prototype.removeEngines = function( targetName )
{
    var target = this.findTarget( targetName );
    
    if( target )
        target.removeEngines();
}

//-----------------------------------------------------------------------------
// 
// findTarget(...)
// 
// Purpose: find a target by name
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.findTarget = function( targetName )
{
    if( this.defaultTarget && this.defaultTarget.targetName == targetName )
        return this.defaultTarget;
        
    for( var i=0; i<this.targetsInfo.length; i++ )
        if( this.targetsInfo[i].targetName == targetName )
            return this.targetsInfo[i];
            
    return null;
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: Make sure that the target is known; if not, add the target by 
//          target name
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.checkTarget = function( targetName, engineName )
{
	var hasTarget = this.findTarget( targetName );
	
	if( !hasTarget )
	{
	    //
		// Create a target name by upper casing the first character,
		// and appending the version if given
		//
		var temp = targetName.split('-');
		
		// Beautify...
		var displayName = BridgeTalk.getDisplayName( temp[0] );
		
		if( !displayName || !displayName.length )
		{
		    switch( temp[0] )
		    {
			    case "aftereffects":	
			        displayName = "After Effects"; 
			        break;
			        
			    default:
				    displayName = temp[0].substr( 0, 1 ).toUpperCase() + temp[0].substr(1);
		    }
		
		    if( temp.length > 1 )
			    displayName += ' ' + temp[1];
        }
        
		this.addTarget( targetName, displayName, false );
	}
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: get display name for target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.getTargetDisplayName = function( targetName )
{
    var ret = '';
    
	// make sure that any debugger suffix has been stripped
	var target = this.findTarget( targetName.replace( '#estk', '' ) )
	
	if( target )
	    ret = target.title;
	    
	return ret;
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: set active target & engine
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.setActive = function( targetName, engineName, document )
{
    if( !engineName )
        engineName = '';
        
    var target = this.findTarget( targetName );
    
    if( target && ( target.exists( engineName ) || engineName == '' ) )
    {
        //
        // set active target & engine
        //
        this.setActiveTarget( targetName, true );
        target.setActive( engineName );

/* done in TargetInfo.setActive(...)
        
        //
        // set current active debugger
        //
        var dbg = Debugger.find( targetName, engineName );
        
        if( dbg )
            Debugger.setCurrent( dbg );
        else
        {
            if( BridgeTalk.isRunning( targetName ) )
                this.select( targetName, engineName, document );
            else
                Debugger.setCurrent( new Debugger( targetName, engineName ) );
        }
*/        
    }    
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: set active engine of given target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.setActiveEngine = function( targetName, engineName )
{
    var target = this.findTarget( targetName );
    
    if( target && target.exists( engineName ) )
    {
        if( target != this.getActiveTarget() )
            this.setActiveTarget( target.targetName );
            
        target.setActive( engineName );
    }
}

TargetManager.prototype.select = function( targetName, engineName, document )
{
    var target = this.findTarget( targetName );
    
    if( target )
        this.connectDebugger( target, engineName, document );
}

//-----------------------------------------------------------------------------
// 
// setActiveTarget(...)
// 
// Purpose: get/set active target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.setActiveTarget = function( targetName, dontnotify )
{
    this.activeTarget = this.findTarget( targetName );

    if( this.activeTarget && !dontnotify )
        this.notifyClients( 'changeActiveTarget' );
}

TargetManager.prototype.getActiveTarget = function()
{
    if( !this.activeTarget )
        this.setActiveTarget( this.defaultTarget );
        
    return this.activeTarget;
}

//-----------------------------------------------------------------------------
// 
// getTargets(...)
// 
// Purpose: return array of targets
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.getTargets = function()
{
    var targets = new Array;
    
    if( this.defaultTarget )
        targets.push( this.defaultTarget );
        
    for( var i=0; i<this.targetsInfo.length; i++ )
        targets.push( this.targetsInfo[i] );
                
    return targets;
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: get/set connect status of target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.setConnected = function( targetName, connected )
{
    if( !connected )
        connected = false;
        
    var target = this.findTarget( targetName );
    
    if( target )
        target.setConnected( connected );
}

TargetManager.prototype.getConnected = function( targetName, check )
{
    var ret = false;
    
    var target = this.findTarget( targetName );
    
    if( target )
        ret = target.getConnected( check );
        
    return ret;
}

//-----------------------------------------------------------------------------
// 
// setFeature(...)
// 
// Purpose: get/set feature of target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.setFeature = function( targetName, feature, state )
{
    var target = this.findTarget( targetName );
    
    if( target )
        target.setFeature( feature, state );
}

TargetManager.prototype.getFeature = function( targetName, feature )
{
    var ret = false;
    
    var target = this.findTarget( targetName );
    
    if( target )
        ret = target.getFeature( feature );
        
    return ret;
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: connect target/engine to its debugger
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.connectDebugger = function( target, engineName, document )
{
    if( !engineName )
        engineName = '';

	if( engineName == '' )
		Debugger.connect( target.targetName, document );
	else
	{
		var dbg = Debugger.find( target.targetName, engineName );
		
		if( !dbg )
		{
            if( target.engines.length > 0 )		    
		    {
                dbg = currentDebugger;
		
		        // there is a debugger active for this engine. Bring that doc to the front!
		        if( dbg )
    		        dbg.activate();
            }
            else
            {
                this._selectTarget_ = target.targetName;
                this._selectEngine_ = engineName;
                Debugger.doConnect( target.targetName, document, 0, null, this );
            }                
        }
        else
            dbg.activate();
	}
}

TargetManager.prototype.onConnected = function( connected, target, engines )
{
    if( connected )
        this.select( this._selectTarget_, this._selectEngine_ );
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: Check if the connected targets are still running, otherwise 
//          disconnect debugger for target
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.checkConnections = function()
{
    if( this.defaultTarget.connected && !BridgeTalk.isRunning( this.defaultTarget.targetName ) )
        Debugger.disconnect( this.defaultTarget.targetName );
        
    for( var i=0; i<this.targetsInfo.length; i++ )
    {
        if( this.targetsInfo[i].connected && !BridgeTalk.isRunning( this.targetsInfo[i].targetName ) )
            Debugger.disconnect( this.targetsInfo[i].targetName );
    }
}

//-----------------------------------------------------------------------------
// 
// loadTargets(...)
// 
// Purpose: load all available targets
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.loadTargets = function()
{
	var i;
    //
	// we want to offer only CS3 targets
	var apps = BridgeTalk.getTargets();
	var curLocale = $.locale.toLowerCase();
	
	// determine for each app if version and/or locale info needs to be added
	// collect this stuff into the following object, create subobjects holding
	// booleans for versions and locales needed
	var testObj = {};

	for( var pass=1; pass<=2; pass++ )
	{
		for( var i=0; i<apps.length; i++ )
		{
            if( BridgeTalk.getGroupForSpecifier( apps[i] ) == "cs/3" )
            {
			    // the target is now fully qualified
			    var app = BridgeTalk.getSpecifier( apps [i] );
    		
		        var target  = app.split ('-');
		        var version = target [1];
		        var locale  = target [2];
		        target      = target [0];

		        if( BridgeTalk.supportsESTK( target ) )
		        {
		            // Ignore Acrobat 7 for now
		            if (target == "acrobat" && Number (version) < 8)
			            continue;
		            // Ignore the Help Center for now
		            if (target == "helpcenter")
			            continue;
		            // do not load info about myself
		            if (target != "estoolkit")
		            {
			            var appObj = testObj [target];
			            if (!appObj)
				            appObj = testObj [target] = 
			            { needVersion:false, needLocale:false, version:version, locale:locale };
			            if (pass == 1)
			            {
				            // pass 1: collect information
				            if (appObj.version != version)
					            appObj.needVersion = true;
				            if (appObj.locale != locale)
					            appObj.needLocale = true;
			            }
			            else
			            {
				            // pass 2: generate the entries
				            var displayName = BridgeTalk.getDisplayName (app);
    					    
				            // OK, the dislay name is valid - we can use it
				            if (displayName)
				            {
					            // need to add version and/or locale?
					            if (appObj.needVersion && appObj.needLocale)
						            displayName += " (" + version + ", " + locale + ")";
					            else if (appObj.needVersion)
						            displayName += " (" + version + ")";
					            else if (appObj.needLocale)
						            displayName += " (" + locale + ")";

					            this.addTarget( app, displayName, true );
				            }
				        }
			        }
			    }
			}
		}
	}

    if( this.targetsInfo.length > 0 )
    {
        this.activeTarget = this.defaultTarget;
    }
    
	this.notifyClients( 'changeTargets' );
}

//-----------------------------------------------------------------------------
// 
// sendBreakpoints(...)
// 
// Purpose: Send all breakpoints to target/engine
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.sendBreakpoints = function( targetName, engineName, flags )
{
    if( !targetName && this.activeTarget )
        targetName = this.activeTarget.targetName;
        
    if( !engineName && this.activeTarget )
    {
        var target = this.findTarget( targetName );
        
        if( target )
            engineName = target.activeEngine;
    }
    
    if( targetName && targetName.length > 0 && 
	    engineName && engineName.length > 0   )
    {
        var target = this.findTarget( targetName );
        
        if( target )
            target.sendBreakpoints( engineName, flags );
    }
}

//-----------------------------------------------------------------------------
// 
// registerClient(...)
// 
// Purpose: un/register client object to receive notifications
//                   (client objects have to support a function "onTargetsChanged(reason)" )
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.registerClient = function( clientObj )
{ return this.broadcaster.registerClient( clientObj ); }

TargetManager.prototype.unregisterClient = function( clientObj )
{ this.broadcaster.unregisterClient( clientObj ); }

TargetManager.prototype.unregisterAllClients = function()
{ this.broadcaster.unregisterAllClients(); }

//-----------------------------------------------------------------------------
// 
// notifyClients(...)
// 
// Purpose: notify registered client object about changes related to the
//                   targets list
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.notifyClients = function( why, currentTarget )
{
    if( !currentTarget )
        currentTarget = this.getActiveTarget();
        
    this.broadcaster.notifyClients( why, currentTarget );        
}

//-----------------------------------------------------------------------------
// 
// resetChangingFlag(...)
// 
// Purpose:changing flag
// 
//-----------------------------------------------------------------------------

TargetManager.prototype.resetChangingFlag = function()
{
    this.changing = 0;
}

TargetManager.prototype.setIsChanging = function( changing )
{
    if( changing )
        this.changing++;
    else
        this.changing--;
}

TargetManager.prototype.isChanging = function()
{
    return this.changing > 0;
}

///////////////////////////////////////////////////////////////////////////////
//
// class TargetInfo
//

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

function TargetInfo( targetName, title, mgr )
{
    this.mgr            = mgr;
    this.targetName     = targetName;
    this.title          = title;
    this.engines        = new Array;
    this.activeEngine   = null;
    this.connected      = false;
    this.features       = {};
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: Am I the default target
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.isDefault = function()
{
    var ret = false;
    
    if( this.mgr )
        ret = ( this.mgr.defaultTarget == this );
        
    return ret;
}

//-----------------------------------------------------------------------------
// 
// addEngine(...)
// 
// Purpose: add an engine to target
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.addEngines = function( dontnotify )
{
    var old = this.activeEngine;
    
    this.removeEngines();
    
    var debuggers = Debugger.getAll (this.targetName);
    
	for( var i=0; i<debuggers.length; i++ )
	{
		var dbg = debuggers [i];
		
		if( dbg.engine && dbg.engine.length > 0 )
		    this.engines.push( dbg.engine );
	}
	
	if( old && this.exists( old ) )
	    this.activeEngine = old;
	else if( this.engines.length > 0 )
	    this.activeEngine = this.engines[0];

    if( !dontnotify )	    
        this.mgr.notifyClients( 'changeEngines', this );	    
}

//-----------------------------------------------------------------------------
// 
// changeEngine(...)
// 
// Purpose: Add/remove/change engine
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.changeEngine = function( oldName, newName )
{
    if( oldName.length > 0 || newName.length > 0 )
    {
        if( newName.length <= 0 )
        {
            //
            // remove engine from list
            //
            var index = this.find( oldName );
            
            if( index >= 0 )
            {
                this.engines.slice( index, 1 );
                
                for( var i=0; i<Debugger.all.length; i++ )
                {
                    var dbg = Debugger.all[i];
                    
                    if( dbg.target == this.targetName && dbg.engine == oldName )
                    {
                        Debugger.all.slice( i, 1 );
                        break;
                    }
                }
            }
        }
        else if( oldName.length <= 0 )
        {
            //
            // add new engine to list
            //
            if( !this.exists( newName ) )
            {
                this.engines.push( newName );
                
                var dbg = Debugger.find( this.targetName, newName );
                
                if( !dbg )
                    dbg = new Debugger( this.targetName, newName );
            }
        }
        else
        {
            //
            // find existing engine and rename it
            //
            var index = this.find( oldName );
            
            if( index >= 0 )
            {
                this.engines[index] = newName;
                
                var dbg = Debugger.find( this.targetName, newName );
                
                if( !dbg )
                    dbg = new Debugger( this.targetName, newName );
                else
                    dbg.engine = newName;
            }
        }
        
        this.mgr.notifyClients( 'changeEngines', this );
    }
}

//-----------------------------------------------------------------------------
// 
// find(...)
// 
// Purpose: Find array index of given engine
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.find = function( engineName )
{
    var ret = -1;
    
    for( var i=0; i<this.engines.length; i++ )
    {
        if( this.engines[i] == engineName )
        {
            ret = i;
            break;
        }
    }

    return ret;
}

//-----------------------------------------------------------------------------
// 
// exists(...)
// 
// Purpose: given engine already in target
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.exists = function( engineName )
{
    return ( this.find( engineName ) >= 0 );
}

//-----------------------------------------------------------------------------
// 
// setActive(...)
// 
// Purpose: set active engine
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.setActive = function( engineName, dontnotify )
{
    if( !engineName || engineName.length == 0 )
    {
        if( this.engines.length > 0 )
            engineName = this.engines[0];
    }

    if( this.exists( engineName ) )
        this.activeEngine = engineName;
    else
        this.activeEngine = '';

    if( !dontnotify )	    
        this.mgr.notifyClients( 'changeActiveEngine', this );

    //
    // set current active debugger
    //
    var dbg = Debugger.find( this.targetName, this.activeEngine );
    
    if( dbg )
        Debugger.setCurrent( dbg );
    else
    {
        if( BridgeTalk.isRunning( this.targetName ) )
            this.mgr.select( this.targetName, this.activeEngine/*, document*/ );
        else
            Debugger.setCurrent( new Debugger( this.targetName, this.activeEngine ) );
    }
}

//-----------------------------------------------------------------------------
// 
// getActive(...)
// 
// Purpose: get active engine
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.getActive = function()
{
    if( !this.activeEngine || this.activeEngine.length == 0 )
        return null;
        
    return this.activeEngine;
}

//-----------------------------------------------------------------------------
// 
// removeEngines(...)
// 
// Purpose: remove all engines
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.removeEngines = function( dontnotify )
{
    while( this.engines.length > 0 )
        this.engines.pop();
        
    this.activeEngine = null;
    
    if( !dontnotify )	    
        this.mgr.notifyClients( 'removeEngines', this );
}

//-----------------------------------------------------------------------------
// 
// getEngines(...)
// 
// Purpose: return engines list
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.getEngines = function()
{
    return this.engines;
}

//-----------------------------------------------------------------------------
// 
// function(...)
// 
// Purpose: get/set connect status of target
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.setConnected = function( connected )
{
    if( !connected )
        connected = false;
        
    this.connected = connected;
}

TargetInfo.prototype.getConnected = function( check )
{
	if( check && !this.checkConnection() )
		this.connected = false;
		
    return this.connected;
}

TargetInfo.prototype.checkConnection = function()
{
	var ret = true;
	
    if( this.connected && !BridgeTalk.isRunning( this.targetName ) )
	{
        Debugger.disconnect( this.targetName );
		ret = false;
	}
	
	return ret;
}

//-----------------------------------------------------------------------------
// 
// getBreakpointsXML(...)
// 
// Purpose: Return breakpoints for target/engine as XML
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.getBreakpointsXML = function( engineName, flags )
{
    var bplist = null;
    
    if( !flags )
        flags = ( PrefUtils.getValue( 'prefs.debug.dontBreakOnErrors', 'Boolean' ) ? 1024 : 0 );
        
    if( documents.length > 0 && engineName.length > 0 && this.exists( engineName ) )
    {
        bplist = new XML( '<breakpoints engine="' + engineName + '" flags="' + flags + '"></breakpoints>' );
            
        for( var i=0; i<documents.length; i++ )
        {
            if( documents[i].getCurrentTargetName() == this.targetName &&
                documents[i].getCurrentEngineName() == engineName )
            {
                var bps = documents[i].getAllBreakpoints();
                
                var bp          = null;
                var j           = 0;
                
                do
                {
                    bp = bps.child(j);
                    j++;
                    
                    if( bp.toXMLString().length > 0 )
                        bplist.appendChild( bp );
                
                } while( bp.toXMLString().length > 0 )
            }
        }
    }
    
    return bplist;
}

//-----------------------------------------------------------------------------
// 
// sendBreakpoints(...)
// 
// Purpose: Send all breakpoints for engine
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.sendBreakpoints = function( engineName, flags )
{
    var bplist = this.getBreakpointsXML( engineName, flags );
    
    if( bplist )
    {
	    var bt = BridgeTalk.create( this.targetName );
	    bt.body = bplist.toXMLString();
	    bt.safeSend();
    }
}

//-----------------------------------------------------------------------------
// 
// setFeature(...)
// 
// Purpose: get/set feature of target
// 
//-----------------------------------------------------------------------------

TargetInfo.prototype.setFeature = function( feature, state )
{
    this.features[feature] = state;
}

TargetInfo.prototype.getFeature = function( feature )
{
    var ret = false;
    
    if( this.features[feature] )
        ret = true;
        
    return ret;
}
