﻿/**************************************************************************
*
*  @@@BUILDINFO@@@ 22breakpoints-2.jsx 3.0.0.14  27-February-2008
*  ADOBE SYSTEMS INCORPORATED
*  Copyright 2010 Adobe Systems Incorporated
*  All Rights Reserved.
* 
* NOTICE:  Adobe permits you to use,  modify, and  distribute this file in
* accordance with the terms of the Adobe license agreement accompanying it.
* If you have received this file from a source other than Adobe, then your
* use, modification, or distribution of it requires the prior written
* permission of Adobe.
*
**************************************************************************/

/*
Breakpoints are kept as XML. This XML has the same format as the XML understood
by the ESTK debugging backend in the target:

<breakpoints engine="..." flags="n">
    <breakpoint file="..." line="..." [enabled="..."] [hits="..."] [count="..."]>[cond]</breakpoint>
	...
</breakpoints>
 
- engine is the target engine.
- flags are the debug flags (especially 1024 - don't stop on guarded exceptions).
- enabled is true or false, and optional (default: true).
- hits is the hit count.
- count is the real hit count. If not supplied when setting (or < 0), keep the real hit count.
- cond is the optional condition.

Just send this table over to the target to set breakpoints. No response is expected.
When getting breakpoints, use a body of <get-breakpoints engine="..."/>. The returned
data is again the same list as above. There is no way to detect invalid breakpoints.
*/

//
// host object for breakpoints pane
//
breakpoints =   {
                    pane            : null,             // the pane
                    name            : 'breakpoints',    // unique name
                    title           : '$$$/ESToolkit/Panes/Breakpoints/Title=Breakpoints',
                    menu            : '$$$/ESToolkit/Menu/Window/Breakpoints/Title=&Breakpoints',
                    iconDefault     : '#PBreakpoints_N',
                    iconRollover    : '#PBreakpoints_R'
                };          

//
// register for panes initialization
//
globalBroadcaster.registerClient( breakpoints, 'initPanes' );

//-----------------------------------------------------------------------------
// 
// breakpoints.onNotify(...)
// 
// Purpose: Process broadcast messages
// 
//-----------------------------------------------------------------------------

breakpoints.onNotify = function( reason )
{
    if( reason == 'initPanes' )
    {
        this.init();
    }
    else if( this.pane )
    {
	    switch( reason )
	    {
	        case 'shutdown':
	            this.pane.list.removeAll();
	            globalBroadcaster.unregisterClient( this );
	            break;
	            
	        case 'activeDocChanged':
	        {
	            this.updatePane();
	            
	            if( document )
                    this.pane.infogrp.targetField.textselection = document.paneTitle;
	            else
	                this.pane.infogrp.targetField.text = '';
            }
            break;
	    }
    }
}

//-----------------------------------------------------------------------------
// 
// breakpoints.init(...)
// 
// Purpose: Create and setup breakpoints palette
// 
//-----------------------------------------------------------------------------

breakpoints.init = function()
{
    //
    // create and register pane
    //
    var res = panes.createPaneObj( this,
                                    """list: ListBox 
                                       {
	                                       preferredSize: [10, 20],
	                                       alignment: ['fill', 'fill' ]	
	                                   },
                                       infogrp : Group
                                       {
                                           orientation : 'row',
                                           margins      : 0,
                                           spacing      : 0,
                                           alignment	: ['fill','bottom'],
                                           targetField: EditText
                                           {
                                               properties	: { readonly: true },
                                               alignment	: ['fill','bottom'],
                                               characters : 40
                                           },
                                           sizeBoxSpacer    : Group
                                           {
                                               alignment	: ['right','bottom'],
                                               preferredSize        : [14,1]
                                           }
                                       }""" );

    //
    // register for additional broadcast messages
    //	
	globalBroadcaster.registerClient( this, 'shutdown,activeDocChanged' );

    ///////////////////////////////////////////////////////////////////////////////
    //
    // object methods
    //
    
	//-----------------------------------------------------------------------------
	// 
	// breakpoints.breakpointDialog(...)
	// 
	// Purpose: Create and execute breakpoint dialog
	// 
	//-----------------------------------------------------------------------------
	
	this.breakpointDialog = function( bp, add )
	{
		if (!document)
			return;

		workspace.storeFocus();
		
	    var title = add ? '$$$/ESToolkit/Dialogs/Breakpoint/Title=Add Breakpoint'
						: '$$$/ESToolkit/Dialogs/Breakpoint/TitleModify=Modify Breakpoint';
	    
	    var dlg = new Window(
	           """prefdialog {
	                text : '""" + title + """',
	                properties : { name : 'breakpoint' },

	                groupAll : Group
	                {
	                    orientation : 'column',
	                    alignChildren : 'right',

                        groupLine : Group
                        {
                            orientation : 'row',

	                        staticLine : StaticText
	                        {
	                            text : '$$$/ESToolkit/Dialogs/Breakpoint/Line=Line:'
	                        },

	                        editLine : EditText
	                        {
	                            preferredSize : [60, 20]
	                        },

	                        checkActive : Checkbox
	                        {
	                            text : '$$$/ESToolkit/Dialogs/Breakpoint/Checkbox=Active',
	                            preferredSize : [230, 20]
	                        }
                        },

                        groupCond : Group
                        {
                            orientation : 'row',

	                        staticCond : StaticText
	                        {
	                            text : '$$$/ESToolkit/Dialogs/Breakpoint/Condition=Condition:'
	                        },

	                        editCond : EditText
	                        {
	                            preferredSize : [300, 40],
	                            multiline: true
	                        }
                        },

                        groupHit : Group
                        {
                            orientation : 'row',

	                        staticCond : StaticText
	                        {
	                            text : '$$$/ESToolkit/Dialogs/Breakpoint/HitCount=Hit count:'
	                        },

	                        editHit : EditText
	                        {
	                            text : '1',
	                            preferredSize : [50, 20]
	                        }
                        },

                        groupButtons : Group
                        {
                            orientation : 'row',

	                        buttonRemove : Button
	                        {
	                            text : '$$$/ESToolkit/Dialogs/Breakpoint/buttonRemove=Remove',
	                            visible : """ + ( bp.line > -1 ? """true""" : """false""" ) + """
	                        },
							okBtn			: Button
							{
								text			: '$$$/CT/ExtendScript/UI/OK=&OK',
								properties		: 
								{
									name			:'ok'
								}
							},
							cancelBtn		: Button
							{
								text			 : '$$$/CT/ExtendScript/UI/Cancel=&Cancel',
								properties		: 
								{
									name			: 'cancel'
								}
							}
                        }
                    }
	            }""" );
	     
		dlg.buttonOK		= dlg.groupAll.groupButtons.okBtn;
		dlg.buttonRemove	= dlg.groupAll.groupButtons.buttonRemove;
		dlg.editCond		= dlg.groupAll.groupCond.editCond;
		dlg.editLine		= dlg.groupAll.groupLine.editLine;
		dlg.checkActive		= dlg.groupAll.groupLine.checkActive;
		dlg.editHit			= dlg.groupAll.groupHit.editHit;

		// save the document (Mac loses the document during a modal dialog)
		dlg.document = document.duplicate ? document.master : document;
		dlg.focusDoc = document;
		
        //
        // handle buttons
        //	            
        dlg.buttonOK.onClick = function()
        {
// TODO: cdi support to check syntax        
			var result = app.checkSyntax( dlg.editCond.text );

			if( result.error )
			{
				errorBox (result.error);
				dlg.editCond.active = true;
				return;
			}

			result = Number( dlg.editLine.text );
			
			var maxLines = -1;
			
			if( dlg.document.isSourceDocument )
			    maxLines = dlg.document.getLines().length;
			
			if( isNaN( result ) || result < 1 || result > maxLines )
			{
				app.beep();
				dlg.editLine.active = true;
				return;
			}
			
            dlg.close(1);
        }

		dlg.buttonRemove.onClick = function()
        {
			var line = isFinite( dlg.editLine.text ) ? Number( dlg.editLine.text ) : NaN;
			
			if( isNaN( line ) || line < 1 || line > dlg.document.getLines().length )
			{
				app.beep();
				dlg.editLine.active = true;
				return;
			}
				
			dlg.document.removeBreakpoint( line-1 );
			
            for( var i=0; i<dlg.document.duplicates.length; i++ )
                dlg.document.duplicates[i].removeBreakpoint( line-1 );

			targetMgr.sendBreakpoints();
			breakpoints.updatePane();

            dlg.close(0);
        }

        //
        // fill controls with existing values
        //	            
        var line    = bp.line + 1;
        var hits    = bp.hits;
        var enabled = bp.enabled;
        
        dlg.editLine.text       = line;
        dlg.editCond.text       = bp.condition;
        dlg.checkActive.value   = enabled;
        dlg.editHit.text        = hits;
        
        //
        // display dialog
        //
	    dlg.center();
	    
	    var ret = ( dlg.show() == 1 && dlg.editLine.text.length > 0 );

		//
		// switch focus back to the document
		//
		dlg.focusDoc.activate();
		
        //
        // get values from dialog if closed with ok
        //
        if( ret )
        {
			bp.line         = isFinite( dlg.editLine.text ) ? parseInt( dlg.editLine.text, 10 ) - 1 : NaN;
            bp.condition    = dlg.editCond.text;
            bp.enabled      = dlg.checkActive.value;
			bp.hits         = isFinite( dlg.editHit.text ) ? parseInt( dlg.editHit.text, 10 ) : NaN;

			var newLine    = bp.line;
			var newHits    = bp.hits;
			var newEnabled = bp.enabled;
            
			if( isNaN( newLine ) || newLine < 0 )   newLine = 0, bp.line = 0;
			if( isNaN( newHits ) )                  newHits = 0, bp.hits = 0;

            if( !add && line-1 != newLine )
            {
                dlg.document.removeBreakpoint( line-1 );
                
                for( var i=0; i<dlg.document.duplicates.length; i++ )
                    dlg.document.duplicates[i].removeBreakpoint( line-1 );
            }
               
			dlg.document.setBreakpoint( newLine, newEnabled, newHits, bp.condition, 0 );
			
            for( var i=0; i<dlg.document.duplicates.length; i++ )
                dlg.document.duplicates[i].setBreakpoint( newLine, newEnabled, newHits, bp.condition, 0 );

			targetMgr.sendBreakpoints();
			breakpoints.updatePane();
		}

		workspace.restoreFocus();

        return ret;
    }

    //-----------------------------------------------------------------------------
    //
    // breakpoints.updatePane(...)
    //
    // Purpose: Update breakpoints list in palette
    //
    //-----------------------------------------------------------------------------

    this.updatePane = function()
    {
        if( document )
            this.updateFromDoc( document );
        else
            this.pane.list.removeAll();
    }
    
    this.updateFromDoc = function( doc )
    {
		if( doc )
			this.doUpdate( doc.getAllBreakpoints() );
    }
            
    breakpoints.doUpdate = function( breakpoints )
    {            
        this.pane.list.removeAll();
        
        if( breakpoints )
        {
            var bp          = null;
            var i           = 0;
            
            do
            {
                bp = breakpoints[i];
                i++;
                
                if( bp )
                {
                    var cond        = bp.condition;
                    var hitcount    = bp.hits;

                    var text        = localize( '$$$/ESToolkit/Panes/Breakpoints/Line=Line' ) + ' ' 
							        + ( bp.line + 1 );
    							    
				    if( cond.length > 0 )
				        text += ' ' + localize( '$$$/ESToolkit/Panes/Breakpoints/Cond=when' ) + ' ' + cond;
    				    
				    if( !isNaN( hitcount ) && hitcount > 1 )
				    {
				        if( cond.length > 0 )
				            text += ' ,';
    				        
				        text += ' ';
				        text += localize( '$$$/ESToolkit/Panes/Breakpoints/hitcount=Hitcount' ) + ' == ' + hitcount;
				        text += ' (' + localize( '$$$/ESToolkit/Panes/Breakpoints/cHitcount=Current' ) + ' == ' + bp.hitCount + ' )';
				    }
    								
                    var item        = this.pane.list.add( 'item', text );
                    item.breakpoint = bp;
                    
                    var enabled     = item.breakpoint.enabled;

                    if( cond.length )
                        item.icon = ( enabled ? '#BreakpointEnabledCond' : '#BreakpointDisabledCond' );
                    else
	                    item.icon = ( enabled ? '#BreakpointEnabled' : '#BreakpointDisabled' );
                }
            
            } while( bp )
        }
    }

    ///////////////////////////////////////////////////////////////////////////////
    //
    // UI handler
    //
    
	// Double click handler

	this.pane.list.onDoubleClick = function()
	{
		if( this.selection )
			breakpoints.breakpointDialog( this.selection.breakpoint, false );
	}

    ///////////////////////////////////////////////////////////////////////////////
    //
    // flyout menu
    //

	//
	// add flyout menu
	//
	this.pane.menu = new MenuElement( "popupmenu", "Flyout", undefined, "breakpoints/flyout" );
    var itemAdd = new MenuElement( 'command', '$$$/ESToolkit/Panes/Breakpoints/Flyout/Add=Add', "at the end of breakpoints/flyout", "breakpoints/flyout/add" );
    var itemMod = new MenuElement( 'command', '$$$/ESToolkit/Panes/Breakpoints/Flyout/Modify=Modify', "at the end of breakpoints/flyout", "breakpoints/flyout/modify" );
    var itemRem = new MenuElement( 'command', '$$$/ESToolkit/Panes/Breakpoints/Flyout/Remove=Remove', "at the end of breakpoints/flyout", "breakpoints/flyout/remove" );
	
    ///////////////////////////////////////////////////////////////////////////////
    //
    // methods
    //
    
    //-----------------------------------------------------------------------------
    // 
    // itemMod.onDisplay(...)
    // itemRem.onDisplay(...)
    // 
    // Purpose: Enabled state of flyout menu items
    // 
    //-----------------------------------------------------------------------------
    
    itemMod.onDisplay = itemRem.onDisplay = function()
    {
        this.enabled = ( breakpoints.pane.list.selection != null && breakpoints.enabled );
        
	    if( document )
	    {
            var currTarget  = document.getCurrentTarget();
            var currSession = document.getCurrentSession();
            
            if( currTarget )
                this.enabled = currTarget.getFeature( Feature.SET_BREAKPOINTS, currSession ) &&
                               currTarget.getFeature( Feature.REMOVE_BREAKPOINTS, currSession );
	    }
    }
    
    itemAdd.onDisplay = function()
    {
        this.enabled = breakpoints.enabled;
        
	    if( document && document.isSourceDocument )
	    {
            var currTarget  = document.getCurrentTarget();
            var currSession = document.getCurrentSession();
            
            if( currTarget )
                this.enabled = currTarget.getFeature( Feature.SET_BREAKPOINTS, currSession ) &&
                               currTarget.getFeature( Feature.REMOVE_BREAKPOINTS, currSession );
	    }
    }
    
    //-----------------------------------------------------------------------------
    // 
    // itemAdd.onSelect(...)
    // itemMod.onSelect(...)
    // 
    // Purpose: Flyout menu item add/modify clicked
    // 
    //-----------------------------------------------------------------------------
    
    itemAdd.onSelect = itemMod.onSelect = function()
    {
        if( document )
        {
            var bp = null;
			var add = false;

            if( this == itemMod && breakpoints.pane.list.selection != null )
                bp = breakpoints.pane.list.selection.breakpoint;
            else
            {
                bp = new Breakpoint(1);
                add = true;
            }
            
			breakpoints.breakpointDialog( bp, add );
        }
    }

    //-----------------------------------------------------------------------------
    // 
    // itemRem.onSelect(...)
    // 
    // Purpose: Flyout menu item remove clicked.
    // 
    //-----------------------------------------------------------------------------

    itemRem.onSelect = function()
    {
        if( breakpoints.pane.list.selection != null && document )
        {
            var selIndex = breakpoints.pane.list.selection.index;

            document.removeBreakpoint( breakpoints.pane.list.selection.breakpoint.line );
            
            for( var i=0; i<document.duplicates.length; i++ )
                document.duplicates[i].removeBreakpoint( breakpoints.pane.list.selection.breakpoint.line );

            targetMgr.sendBreakpoints();
            breakpoints.updatePane();
            
            if( breakpoints.pane.list.items.length > selIndex )
                breakpoints.pane.list.selection = selIndex;
            else
                breakpoints.pane.list.selection = null;
        }
    }
}
