// DBRef.java

package ed.db;

import java.util.*;

import ed.*;
import ed.js.*;
import ed.appserver.*;

public class DBRef extends JSObjectBase {

    static final boolean D = Boolean.getBoolean( "DEBUG.DB" );

    DBRef( JSObject parent , String fieldName , DBBase db , String ns , ObjectId id ){
        _parent = parent;
        _fieldName = fieldName;
        
        _ns = ns;
        _id = id;
        _db = db;
        
        super.set( "_ns" , ns );
        super.set( "_id" , id );
        _inited = true;
        markClean();
    }

    public boolean isNull(){
	if ( _db == null )
	    return false;
	return _getPointedTo() == null;
    }

    public JSObject getRealObject(){
        JSObject o = _getPointedTo();
        if ( ! o.getClass().equals( JSObjectBase.class ) )
            return o;
        return this;
    }
    
    public Object prefunc(){
        return doLoad();
    }

    public Object doLoad(){
        if ( ! _inited )
            return _actual;
        
        if ( _loaded )
            return _actual;

	if ( D ) System.out.println( "following dbref" );
        
	JSObject o = _getPointedTo();

        if ( o == null ){
            System.out.println( "can't find ref.  ns:" + _ns + " id:" + _id );
            _parent.set( _fieldName , null );
            return null;
        }

        MyAsserts.assertEquals( _id , o.get( "_id" ) );
        MyAsserts.assertEquals( _ns.toString() , o.get( "_ns" ).toString() );

        _loaded = true; // this technically makes a race condition...
        
        Object ret = this;

        if ( ! o.getClass().equals( JSObjectBase.class ) ){
            _parent.set( _fieldName , o );
            ret = o;
        }
        
        if ( o instanceof JSObjectBase )
            setConstructor( ((JSObjectBase)o).getConstructor() );
        
        addAll( o );
        
        _doneLoading = true;
        markClean();

        _actual = ret;
        return ret;
    }
    
    public boolean isDirty(){
        return _doneLoading && super.isDirty();
    }
    
    private JSObject _getPointedTo(){
	if ( _loadedPointedTo )
	    return _pointedTo;

        if ( _db == null )
            throw new RuntimeException( "db is null" );

        final RefCache rc = getRefCache();
        final DBCollection coll = _db.getCollectionFromString( _ns );
        
        JSObject o = rc == null ? null : rc.get( _id );
        
        if ( o == null ){
            o = coll.find( _id );
            if ( o != null && rc != null )
                rc.put( _id , o );
        }
	else {
	    coll.apply( o );
	}

	_pointedTo = o;
	_loadedPointedTo = true;
	return _pointedTo;
    }

    final JSObject _parent;
    final String _fieldName;

    final ObjectId _id;
    final String _ns;
    final DBBase _db;
    
    boolean _inited = false;
    boolean _loaded = false;
    boolean _doneLoading = false;
    
    private Object _actual;

    private boolean _loadedPointedTo = false;
    private JSObject _pointedTo;
    

    private static RefCache getRefCache(){
        AppRequest r = AppRequest.getThreadLocal();
        if ( r == null )
            return null;
        
        RefCache c = _refCache.get( r );
        if ( c != null )
            return c;
        
        c = new RefCache();
        _refCache.put( r , c );
        return c;
    }
    
    private static class RefCache extends HashMap<ObjectId,JSObject>{};

    private static Map<AppRequest,RefCache> _refCache = Collections.synchronizedMap( new WeakHashMap<AppRequest,RefCache>() );
}

@@ -70,24 +70,41 @@
 rt ed.js.*;%0A
+import ed.log.*;%0A
 import ed.ap
@@ -114,16 +114,16 @@
 rver.*;%0A
-
 %0Apublic 
@@ -1178,87 +1178,8 @@
  )%7B%0A
-            System.out.println( %22can't find ref.  ns:%22 + _ns + %22 id:%22 + _id );%0A
     
@@ -1386,25 +1386,33 @@
 String() );%0A
+        
 %0A
-
         _loa
@@ -2530,12 +2530,129 @@
  );%0A
-
 %09%7D%0A%0A
+        if ( o == null )%0A            Logger.getRoot().getChild( %22missingref%22 ).info( %22ns:%22 + _ns + %22 id:%22 + _id );%0A%0A%0A
 %09_po

fix broken ref debugging