/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */

#include "native.h"
#include "jsdebug.h"

#ifndef XP_MAC
#include "_gen/netscape_jsdebug_DebugController.h"
#include "_gen/netscape_jsdebug_Script.h"
#include "_gen/netscape_jsdebug_JSThreadState.h"
#include "_gen/netscape_jsdebug_JSStackFrameInfo.h"
#include "_gen/netscape_jsdebug_JSPC.h"
#include "_gen/netscape_jsdebug_JSSourceTextProvider.h"
#include "_gen/netscape_jsdebug_JSErrorReporter.h"
#else
#include "n_jsdebug_DebugController.h"
#include "netscape_jsdebug_Script.h"
#include "n_jsdebug_JSThreadState.h"
#include "n_jsdebug_JSStackFrameInfo.h"
#include "netscape_jsdebug_JSPC.h"
#include "n_j_JSSourceTextProvider.h"
#include "n_jsdebug_JSErrorReporter.h"
#endif

static JSDContext* context = 0;
static struct Hnetscape_jsdebug_DebugController* controller = 0;

/***************************************************************************/
/* helpers */

static JHandle*
_constructInteger(ExecEnv *ee, long i)
{
    return (JHandle*) 
        execute_java_constructor(ee, "java/lang/Integer", 0, "(I)", i);
}

static JHandle*
_putHash(ExecEnv *ee, JHandle* tbl, JHandle* key, JHandle* ob)
{
    return (JHandle*) 
        execute_java_dynamic_method( 
            ee, tbl, "put",
            "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 
            key, ob );
}

static JHandle*
_getHash(ExecEnv *ee, JHandle* tbl, JHandle* key)
{
    return (JHandle*) 
        execute_java_dynamic_method( 
            ee, tbl, "get",
            "(Ljava/lang/Object;)Ljava/lang/Object;", 
            key );
}

static JHandle*
_removeHash(ExecEnv *ee, JHandle* tbl, JHandle* key)
{
    return (JHandle*) 
        execute_java_dynamic_method( 
            ee, tbl, "remove",
            "(Ljava/lang/Object;)Ljava/lang/Object;", 
            key );
}

struct Hnetscape_jsdebug_JSStackFrameInfo*
_constructJSStackFrameInfo( ExecEnv* ee, JSDStackFrameInfo* jsdframe, 
                            struct Hnetscape_jsdebug_JSThreadState* threadState )
{
    struct Hnetscape_jsdebug_JSStackFrameInfo* frame;

    frame = (struct Hnetscape_jsdebug_JSStackFrameInfo*)
        execute_java_constructor( ee, "netscape/jsdebug/JSStackFrameInfo", 0, 
                                  "(Lnetscape/jsdebug/JSThreadState;)",
                                  threadState );
    if( ! frame )
        return NULL;

    /* XXX fill in additional fields */
    unhand(frame)->_nativePtr = (long) jsdframe;

    return frame;
}

struct Hnetscape_jsdebug_JSPC*
_constructJSPC( ExecEnv* ee, struct Hnetscape_jsdebug_Script* script, long pc )
{
    struct Hnetscape_jsdebug_JSPC * pcOb;

    pcOb = (struct Hnetscape_jsdebug_JSPC *)
        execute_java_constructor( ee, "netscape/jsdebug/JSPC", 0, 
                                  "(Lnetscape/jsdebug/Script;I)",
                                  script, pc );
    if( ! pcOb )
        return NULL;

    /* XXX fill in additional fields */

    return pcOb;
}

static Hnetscape_jsdebug_Script*
_scriptObFromJSDScriptPtr( ExecEnv* ee, JSDScript* jsdscript )
{
    JHandle* tbl = (JHandle*) unhand(controller)->scriptTable;
    JHandle* key = _constructInteger(ee,(long)jsdscript);
    return (Hnetscape_jsdebug_Script*) _getHash( ee, tbl, key );
}

/***************************************************************************/

void PR_CALLBACK
_scriptHook( JSDContext* jsdc, 
             JSDScript*  jsdscript,
             JSBool      creating,
             void*       callerdata )
{
    Hnetscape_jsdebug_Script* script;
    ExecEnv* ee = EE();

    if( ! context || ! controller || ! ee )
        return;

    if( creating )
    {
        char* url      = (char*)JSD_GetScriptFilename       (jsdc, jsdscript);
        char* function = (char*)JSD_GetScriptFunctionName   (jsdc, jsdscript);
        int base       =        JSD_GetScriptBaseLineNumber (jsdc, jsdscript);
        int extent     =        JSD_GetScriptLineExtent     (jsdc, jsdscript);

        if( ! url )
        {
            return;
            /* url = ""; */
        }

        /* create Java Object for Script */
        script = (Hnetscape_jsdebug_Script*)
                execute_java_constructor(ee, "netscape/jsdebug/Script", 0, "()");

        if( ! script )
            return;

        /* set the members */
        unhand(script)->_url = makeJavaString(url,strlen(url));
        unhand(script)->_function = function ? makeJavaString(function,strlen(function)) : 0;
        unhand(script)->_baseLineNumber = base;
        unhand(script)->_lineExtent = extent;
        unhand(script)->_nativePtr = (long)jsdscript;

        /* add it to the hash table */
        _putHash( ee, (JHandle*) unhand(controller)->scriptTable,
                  _constructInteger(ee, (long)jsdscript), (JHandle*)script );

        /* call the hook */
        if( unhand(controller)->scriptHook )
        {
            execute_java_dynamic_method( ee,(JHandle*)unhand(controller)->scriptHook,
                                         "justLoadedScript",
                                         "(Lnetscape/jsdebug/Script;)V", 
                                         script );
        }
    }
    else
    {
        JHandle* tbl = (JHandle*) unhand(controller)->scriptTable;
        JHandle* key = _constructInteger(ee,(long)jsdscript);

        /* find Java Object for Script    */
        script = (Hnetscape_jsdebug_Script*) _getHash( ee, tbl, key );

        if( ! script )
            return;

        /* remove it from the hash table  */
        _removeHash( ee, tbl, key );

        /* call the hook */
        if( unhand(controller)->scriptHook )
        {
            execute_java_dynamic_method( ee,(JHandle*)unhand(controller)->scriptHook,
                                         "aboutToUnloadScript",
                                         "(Lnetscape/jsdebug/Script;)V", 
                                         script );
        }
        /* set the Script as invalid */
        execute_java_dynamic_method( ee,(JHandle*)script,
                                     "_setInvalid",
                                     "()V" );
    }
}

/***************************************************************************/
PRUintn PR_CALLBACK
_executionHook( JSDContext*     jsdc, 
                JSDThreadState* jsdstate,
                PRUintn         type,
                void*           callerdata )
{
    Hnetscape_jsdebug_JSThreadState* threadState;
    Hnetscape_jsdebug_Script* script;
    JHandle* pcOb;
    JSDStackFrameInfo* jsdframe;
    JSDScript*  jsdscript;
    int pc;
    JHandle* tblScript;
    JHandle* keyScript;
    ExecEnv* ee = EE();

    if( ! context || ! controller || ! ee )
        return JSD_HOOK_RETURN_HOOK_ERROR;

    /* get the JSDStackFrameInfo */
    jsdframe = JSD_GetStackFrame(jsdc, jsdstate);
    if( ! jsdframe )
        return JSD_HOOK_RETURN_HOOK_ERROR;

    /* get the JSDScript */
    jsdscript = JSD_GetScriptForStackFrame(jsdc, jsdstate, jsdframe);
    if( ! jsdscript )
        return JSD_HOOK_RETURN_HOOK_ERROR;

    /* find Java Object for Script    */
    tblScript = (JHandle*) unhand(controller)->scriptTable;
    keyScript = _constructInteger(ee, (long)jsdscript);
    script = (Hnetscape_jsdebug_Script*) _getHash( ee, tblScript, keyScript );
    if( ! script )
        return JSD_HOOK_RETURN_HOOK_ERROR;

    /* generate a JSPC */
    pc = JSD_GetPCForStackFrame(jsdc, jsdstate, jsdframe);

    pcOb = (JHandle*)
        _constructJSPC(ee, script, pc);
    if( ! pcOb )
        return JSD_HOOK_RETURN_HOOK_ERROR;

    /* build a JSThreadState */
    threadState = (struct Hnetscape_jsdebug_JSThreadState*)
            execute_java_constructor( ee, "netscape/jsdebug/JSThreadState",0,"()");
    if( ! threadState )
        return JSD_HOOK_RETURN_HOOK_ERROR;

    /* populate the ThreadState */
    /* XXX FILL IN THE REST... */
    unhand(threadState)->valid           = 1; /* correct value for true? */
    unhand(threadState)->currentFramePtr = (long) jsdframe;
    unhand(threadState)->nativeThreadState = (long) jsdstate;
    unhand(threadState)->continueState = netscape_jsdebug_JSThreadState_DEBUG_STATE_RUN;

    /* XXX FILL IN THE REST... */


    /* find and call the appropriate Hook */
    if( JSD_HOOK_INTERRUPTED == type )
    {
        JHandle* hook;

        /* clear the JSD level hook (must reset on next sendInterrupt0()*/
        JSD_ClearInterruptHook(context); 

        hook = (JHandle*) unhand(controller)->interruptHook;
        if( ! hook )
            return JSD_HOOK_RETURN_HOOK_ERROR;

        /* call the hook */
        execute_java_dynamic_method( 
            ee, hook, "aboutToExecute",
            "(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V",
            threadState, pcOb );
    }
    else if( JSD_HOOK_DEBUG_REQUESTED == type )
    {
        JHandle* hook;

        hook = (JHandle*) unhand(controller)->debugBreakHook;
        if( ! hook )
            return JSD_HOOK_RETURN_HOOK_ERROR;

        /* call the hook */
        execute_java_dynamic_method( 
            ee, hook, "aboutToExecute",
            "(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V",
            threadState, pcOb );
    }
    else if( JSD_HOOK_BREAKPOINT == type )
    {
        JHandle* hook;

        hook = (JHandle*)
                execute_java_dynamic_method( 
                        ee,(JHandle*)controller,
                        "getInstructionHook0",
                        "(Lnetscape/jsdebug/PC;)Lnetscape/jsdebug/InstructionHook;",
                        pcOb );
        if( ! hook )
            return JSD_HOOK_RETURN_HOOK_ERROR;

        /* call the hook */
        execute_java_dynamic_method( 
            ee, hook, "aboutToExecute",
            "(Lnetscape/jsdebug/ThreadStateBase;)V",
            threadState );
    }

    if( netscape_jsdebug_JSThreadState_DEBUG_STATE_THROW == 
        unhand(threadState)->continueState )
        return JSD_HOOK_RETURN_ABORT;

    return JSD_HOOK_RETURN_CONTINUE;
}

PRUintn PR_CALLBACK
_errorReporter( JSDContext*     jsdc, 
                JSContext*      cx,
                const char*     message, 
                JSErrorReport*  report,
                void*           callerdata )
{
    JHandle* reporter;
    JHandle* msg         = NULL;
    JHandle* filename    = NULL;
    int      lineno      = 0;
    JHandle* linebuf     = NULL;
    int      tokenOffset = 0;
    ExecEnv* ee = EE();

    if( ! context || ! controller || ! ee )
        return JSD_ERROR_REPORTER_PASS_ALONG;

    reporter = (JHandle*) unhand(controller)->errorReporter;
    if( ! reporter )
        return JSD_ERROR_REPORTER_PASS_ALONG;

    if( message )
        msg = (JHandle*) makeJavaString((char*)message, strlen(message));
    if( report && report->filename )
        filename = (JHandle*) makeJavaString((char*)report->filename, strlen(report->filename));
    if( report && report->linebuf )
        linebuf = (JHandle*) makeJavaString((char*)report->linebuf, strlen(report->linebuf));
    if( report )
        lineno = report->lineno;
    if( report && report->linebuf && report->tokenptr )
        tokenOffset = report->tokenptr - report->linebuf;

    return (int) 
        execute_java_dynamic_method( 
                ee, reporter, "reportError",
                "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)I", 
                msg,
                filename,
                lineno,
                linebuf,
                tokenOffset );
}

/***************************************************************************/
/* from "_gen\netscape_jsdebug_DebugController.h" */


/* XXX HACK */
JSDContext* _simContext = 0;

void netscape_jsdebug_DebugController__setController(struct Hnetscape_jsdebug_DebugController * self,/*boolean*/ long on)
{
    if(on)
    {
        context = JSD_DebuggerOn();
        if( ! context )
            return;

        _simContext = context; /* XXX HACK */

        unhand(self)->_nativeContext = (long) context;
        controller = self;
        JSD_SetScriptHook(context, _scriptHook, (void*)1 );
        JSD_SetErrorReporter(context, _errorReporter, (void*)1 );
        JSD_SetDebugBreakHook(context, _executionHook, (void*)1 );
    }
    else
    {
        /* XXX stop somehow... */
        /* kill context        */
        JSD_SetDebugBreakHook(context, NULL, NULL );
        JSD_SetErrorReporter(context, NULL, NULL);
        JSD_SetScriptHook(context, NULL, NULL);
        context = 0;
        controller = 0;
    }
}

void netscape_jsdebug_DebugController_setInstructionHook0(struct Hnetscape_jsdebug_DebugController * self,struct Hnetscape_jsdebug_PC * pcOb)
{
    Hnetscape_jsdebug_Script* script;
    JSDScript* jsdscript;
    PRUintn pc;
    ExecEnv* ee = EE();

    if( ! context || ! controller || ! ee )
        return;

    script = (Hnetscape_jsdebug_Script*)
        execute_java_dynamic_method(ee, (JHandle*)pcOb, "getScript","()Lnetscape/jsdebug/Script;");

    if( ! script )
        return;

    jsdscript = (JSDScript*) unhand(script)->_nativePtr;
    if( ! jsdscript )
        return;

    pc = (PRUintn)
        execute_java_dynamic_method(ee, (JHandle*)pcOb, "getPC","()I");

    JSD_SetExecutionHook(context, jsdscript, pc, _executionHook, 0);
}

void netscape_jsdebug_DebugController_sendInterrupt0(struct Hnetscape_jsdebug_DebugController * self)
{
    if( ! context || ! controller )
        return;
    JSD_SetInterruptHook(context, _executionHook, 0);
}

struct Hjava_lang_String *netscape_jsdebug_DebugController_executeScriptInStackFrame0(struct Hnetscape_jsdebug_DebugController *self,struct Hnetscape_jsdebug_JSStackFrameInfo *frame,struct Hjava_lang_String *src,struct Hjava_lang_String *filename,long lineno)
{
    struct Hnetscape_jsdebug_JSThreadState* threadStateOb;
    JSDThreadState* jsdthreadstate;
    JSDStackFrameInfo* jsdframe;
    char* filenameC;
    char* srcC;
    JSString* jsstr;
    jsval rval;
    JSBool success;
    int srclen;

    threadStateOb = (struct Hnetscape_jsdebug_JSThreadState*)unhand(frame)->threadState;
    jsdthreadstate = (JSDThreadState*) unhand(threadStateOb)->nativeThreadState;

    jsdframe = (JSDStackFrameInfo*) unhand(frame)->_nativePtr;

    if( ! context || ! controller || ! jsdframe )
        return NULL;

    filenameC = allocCString(filename);
    if( ! filenameC )
        return NULL;
    srcC = allocCString(src);
    if( ! srcC )
    {
        free(filenameC);
        return NULL;
    }

    srclen = strlen(srcC);

    success = JSD_EvaluateScriptInStackFrame(context, jsdthreadstate, jsdframe, 
                                             srcC, srclen,
                                             filenameC, lineno, &rval);

    /* XXX crashing on Windows under Symantec (though I can't see why!)*/

    free(filenameC);
    free(srcC);


    if( ! success )
        return NULL;

    if( JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval) )
        return NULL;

    jsstr = JSD_ValToStringInStackFrame(context,jsdthreadstate,jsdframe,rval);
    if( ! jsstr )
        return NULL;

    /* XXXbe should use JS_GetStringChars and preserve Unicode. */
    return makeJavaString((char*)JS_GetStringBytes(jsstr), JS_GetStringLength(jsstr));
}    

long netscape_jsdebug_DebugController_getNativeMajorVersion(struct Hnetscape_jsdebug_DebugController* self)
{
    return (long) JSD_GetMajorVersion();
}

long netscape_jsdebug_DebugController_getNativeMinorVersion(struct Hnetscape_jsdebug_DebugController* self)
{
    return (long) JSD_GetMinorVersion();
}

/***************************************************************************/
/* from "_gen\netscape_jsdebug_Script.h" */

struct Hnetscape_jsdebug_JSPC *netscape_jsdebug_Script_getClosestPC(struct Hnetscape_jsdebug_Script * self,long line)
{
    PRUintn pc;
    JSDScript* jsdscript;

    if( ! context || ! controller )
        return 0;

    jsdscript = (JSDScript*) unhand(self)->_nativePtr;
    if( ! jsdscript )
        return 0;

    pc = JSD_GetClosestPC(context, jsdscript, line);

    if( -1 == pc )
        return 0;
    return _constructJSPC( 0, self, pc);
}

/***************************************************************************/
/* from "_gen\netscape_jsdebug_JSThreadState.h" */

long netscape_jsdebug_JSThreadState_countStackFrames(struct Hnetscape_jsdebug_JSThreadState * self)
{
    JSDThreadState* jsdstate;
        
    if( ! context || ! controller )
        return 0;

    jsdstate = (JSDThreadState*) unhand(self)->nativeThreadState;

    if( ! jsdstate )
        return 0;

    return (long) JSD_GetCountOfStackFrames(context, jsdstate);
}

struct Hnetscape_jsdebug_StackFrameInfo *netscape_jsdebug_JSThreadState_getCurrentFrame(struct Hnetscape_jsdebug_JSThreadState * self)
{
    JSDThreadState* jsdstate;
    JSDStackFrameInfo* jsdframe;
        
    if( ! context || ! controller )
        return NULL;

    jsdstate = (JSDThreadState*) unhand(self)->nativeThreadState;

    if( ! jsdstate )
        return NULL;

    jsdframe = JSD_GetStackFrame(context, jsdstate);
    if( ! jsdframe )
        return NULL;

    return (struct Hnetscape_jsdebug_StackFrameInfo*)
                _constructJSStackFrameInfo( 0, jsdframe, self );
}


/***************************************************************************/
/* from "_gen\netscape_jsdebug_JSStackFrameInfo.h" */

struct Hnetscape_jsdebug_StackFrameInfo *netscape_jsdebug_JSStackFrameInfo_getCaller0(struct Hnetscape_jsdebug_JSStackFrameInfo * self)
{
    JSDStackFrameInfo* jsdframeCur;
    JSDStackFrameInfo* jsdframeCaller;
    struct Hnetscape_jsdebug_JSThreadState* threadState;
    JSDThreadState* jsdthreadstate;

    if( ! context || ! controller )
        return NULL;

    jsdframeCur = (JSDStackFrameInfo*) unhand(self)->_nativePtr;
    if( ! jsdframeCur )
        return NULL;

    threadState = (struct Hnetscape_jsdebug_JSThreadState*) unhand(self)->threadState;
    if( ! threadState )
        return NULL;

    jsdthreadstate = (JSDThreadState*) unhand(threadState)->nativeThreadState;
    if( ! jsdthreadstate )
        return NULL;

    jsdframeCaller = JSD_GetCallingStackFrame(context, jsdthreadstate, jsdframeCur);
    if( ! jsdframeCaller )
        return NULL;

    return (struct Hnetscape_jsdebug_StackFrameInfo*)
                _constructJSStackFrameInfo( 0, jsdframeCaller, threadState );
}
struct Hnetscape_jsdebug_PC *netscape_jsdebug_JSStackFrameInfo_getPC(struct Hnetscape_jsdebug_JSStackFrameInfo * self)
{
    JSDScript* jsdscript;
    JSDStackFrameInfo* jsdframe;
    struct Hnetscape_jsdebug_Script* script;
    struct Hnetscape_jsdebug_JSThreadState* threadState;
    JSDThreadState* jsdthreadstate;
    int pc;
    ExecEnv* ee = EE();

    if( ! context || ! controller || ! ee )
        return NULL;

    jsdframe = (JSDStackFrameInfo*) unhand(self)->_nativePtr;
    if( ! jsdframe )
        return NULL;

    threadState = (struct Hnetscape_jsdebug_JSThreadState*) unhand(self)->threadState;
    if( ! threadState )
        return NULL;

    jsdthreadstate = (JSDThreadState*) unhand(threadState)->nativeThreadState;
    if( ! jsdthreadstate )
        return NULL;

    jsdscript = JSD_GetScriptForStackFrame(context, jsdthreadstate, jsdframe );
    if( ! jsdscript )
        return NULL;

    script = _scriptObFromJSDScriptPtr(ee, jsdscript);
    if( ! script )
        return NULL;

    pc = JSD_GetPCForStackFrame(context, jsdthreadstate, jsdframe);
    if( ! pc )
        return NULL;

    return (struct Hnetscape_jsdebug_PC*) _constructJSPC(ee, script, pc);
}

/***************************************************************************/
/* from "_gen\netscape_jsdebug_JSPC.h" */

struct Hnetscape_jsdebug_SourceLocation *netscape_jsdebug_JSPC_getSourceLocation(struct Hnetscape_jsdebug_JSPC * self)
{
    JSDScript* jsdscript;
    struct Hnetscape_jsdebug_Script* script;
    struct Hnetscape_jsdebug_JSPC* newPCOb;
    int line;
    int newpc;
    int pc;
    ExecEnv* ee = EE();

    if( ! context || ! controller || ! ee )
        return NULL;

    script = unhand(self)->script;

    if( ! script )
        return NULL;

    jsdscript = (JSDScript*) unhand(script)->_nativePtr;
    if( ! jsdscript )
        return NULL;
    pc = unhand(self)->pc;

    line = JSD_GetClosestLine(context, jsdscript, pc);
    newpc = JSD_GetClosestPC(context, jsdscript, line);

    newPCOb = _constructJSPC(ee, script, newpc );
    if( ! newPCOb )
        return NULL;

    return (struct Hnetscape_jsdebug_SourceLocation *)
        execute_java_constructor( ee, "netscape/jsdebug/JSSourceLocation", 0, 
                                  "(Lnetscape/jsdebug/JSPC;I)",
                                  newPCOb, line );
}

/***************************************************************************/
/* from "_gen\netscape_jsdebug_JSSourceTextProvider.h" */

struct Hnetscape_jsdebug_SourceTextItem *netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem0(struct Hnetscape_jsdebug_JSSourceTextProvider * self,struct Hjava_lang_String * url)
{
    /* this should attempt to load the source for the indicated URL */
    return NULL;    
}

void netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector(struct Hnetscape_jsdebug_JSSourceTextProvider * self)
{

    JHandle* vec;
    JHandle* itemOb;
    JSDSourceText* iterp = 0;
    JSDSourceText* item;
    const char* url;
    struct Hjava_lang_String* urlOb;
    ExecEnv* ee = EE();

    if( ! context || ! controller || ! ee )
        return;

    /* create new vector */
    vec = (JHandle*) execute_java_constructor(ee, "netscape/util/Vector", 0, "()");
    if( ! vec )
        return;

    /* lock the native subsystem */
    JSD_LockSourceTextSubsystem(context);

    /* iterate through the native items */
    while( 0 != (item = JSD_IterateSources(context, &iterp)) )
    {
        int urlStrLen;
        int status = JSD_GetSourceStatus(context,item);

        /* try to find Java object */
        url = JSD_GetSourceURL(context, item);
        if( ! url || 0 == (urlStrLen = strlen(url)) ) /* ignoring those with no url */
            continue;

        urlOb = makeJavaString((char*)url,urlStrLen);
        if( ! urlOb )
            continue;

        itemOb = (JHandle*)
            execute_java_dynamic_method( ee, (JHandle*)self, "findSourceTextItem0",
                      "(Ljava/lang/String;)Lnetscape/jsdebug/SourceTextItem;",
                      urlOb );
                      
        if( ! itemOb )
        {
            /* if not found then generate new item */
            struct Hjava_lang_String* textOb;
            const char* str;
            int length;

            if( ! JSD_GetSourceText(context, item, &str, &length ) )
            {
                str = "";
                length = 0;
            }
            textOb = makeJavaString((char*)str, length);

            itemOb = (JHandle*)
                execute_java_constructor(ee, "netscape/jsdebug/SourceTextItem",0,  
                     "(Ljava/lang/String;Ljava/lang/String;I)",
                     urlOb, textOb, status );
        }
        else if( JSD_IsSourceDirty(context, item) && 
                 JSD_SOURCE_CLEARED != status )
        {
            /* if found and dirty then update */
            struct Hjava_lang_String* textOb;
            const char* str;
            int length;

            if( ! JSD_GetSourceText(context, item, &str, &length ) )
            {
                str = "";
                length = 0;
            }
            textOb = makeJavaString((char*)str, length);
            execute_java_dynamic_method(ee, itemOb, "setText", 
                                        "(Ljava/lang/String;)V", textOb);
            execute_java_dynamic_method(ee, itemOb, "setStatus", 
                                        "(I)V", status );
            execute_java_dynamic_method(ee, itemOb, "setDirty", "(Z)V", 1 );
        }

        /* we have our copy; clear the native cached text */
        if( JSD_SOURCE_INITED  != status && 
            JSD_SOURCE_PARTIAL != status &&
            JSD_SOURCE_CLEARED != status )
        {
            JSD_ClearSourceText(context, item);
        }

        /* set the item clean */
        JSD_SetSourceDirty(context, item, FALSE );

        /* add the item to the vector */
        if( itemOb )
            execute_java_dynamic_method(ee, vec, "addElement", 
                                        "(Ljava/lang/Object;)V", itemOb );
    }
    /* unlock the native subsystem */
    JSD_UnlockSourceTextSubsystem(context);

    /* set main vector to our new vector */

    unhand(self)->_sourceTextVector = (struct Hnetscape_util_Vector*) vec;
}    



