/*
 * File    : RPObject.java
 * Created : 28-Jan-2004
 * By      : parg
 * 
 * Azureus - a Java Bittorrent client
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details ( see the LICENSE file ).
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.gudy.azureus2.pluginsimpl.remote;

import java.io.Serializable;

/**
 * @author parg
 *
 */

import java.util.*;

import org.gudy.azureus2.core3.util.SystemTime;

public class 
RPObject
	implements Serializable
{
		// as long as the key is referenced by the rest of core
		// 		key refers to RPObject
		// 		RPObject refers to object_id
		//		object_id refers to RPObject
		// so neither weak map is cleared down
	
	protected static Map		object_registry			= new WeakHashMap();
	
	protected static Map	object_registry_reverse 	= new WeakHashMap();
	
	protected static long	next_key		= new Random(SystemTime.getCurrentTime()).nextLong();
	
	public Long	_object_id;
	
	protected transient Object				__delegate;
	protected transient	RPRequestDispatcher	_dispatcher;
	
	// **** Don't try using AEMOnitor for synchronisations here as this object is serialised

	protected static RPObject
	_lookupLocal(
		Object		key )
	{
		synchronized( object_registry ){
			
			RPObject	res = (RPObject)object_registry.get(key);
			
			if ( res != null ){
				
				res._setLocal();
			}
			
			return( res );
		}
	}
	
	public static RPObject
	_lookupLocal(
		long		object_id )
	{
		synchronized( object_registry ){
			
			Object	res = object_registry_reverse.get( new Long(object_id ));
			
			if ( res == null ){
				
				throw( new RPException( "Object no longer exists"));
			}
			
			RPObject	obj = (RPObject)object_registry.get( res );
			
			if ( obj == null ){
				
				throw( new RPException( "Object no longer exists"));
			}
			
			return( obj );			
		}
	}
	
		// public constructor for XML deserialiser
	public
	RPObject()
	{	
	}
	
	protected
	RPObject(
		Object		key )
	{
		synchronized( object_registry ){
			
			RPObject	existing = (RPObject)object_registry.get(key);
			
			if ( existing != null ){
				
				_object_id	= existing._object_id;
				
			}else{
			
				_object_id	= new Long(next_key++);
				
				object_registry.put( key, this );
				
				object_registry_reverse.put( _object_id, key );
			}
		}
		
		__delegate	= key;
		
		_setDelegate( __delegate );
	}
	
	public long
	_getOID()
	{
		return( _object_id.longValue());
	}
	
	protected void
	_setDelegate(
		Object		_delegate )
	{
		throw( new RuntimeException( "you've got to implement this - " + _delegate ));
	}
	
	protected Object
	_getDelegate()
	{
		return( __delegate );
	}
	
	protected Object
	_fixupLocal()
	
		throws RPException
	{
		Object	res = object_registry_reverse.get( _object_id );
		
		if ( res == null ){
			
			throw( new RPException( "Object no longer exists"));
		}
		
		_setDelegate( res );
		
		return( res );
	}
	
	public void
	_setRemote(
		RPRequestDispatcher		__dispatcher )
	{
		_dispatcher	= __dispatcher;
	}
	
	protected RPRequestDispatcher
	getDispatcher()
	{
		return( _dispatcher );
	}
	
	public RPReply
	_process(
		RPRequest	request	)
	{
		throw( new RuntimeException( "you've got to implement this - " + request ));
	}
	
	public Object
	_setLocal()
	{
		throw( new RuntimeException( "you've got to implement this"));
	}
	
	public void
	_refresh()
	{
		RPObject	res = (RPObject)_dispatcher.dispatch( new RPRequest( this, "_refresh", null )).getResponse();
		
		_setDelegate( res );
	}
	
	public String
	_getName()
	{
		String	str = this.getClass().getName();
		
		int	dp = str.lastIndexOf('.');
		
		if ( dp != -1 ){
			
			str = str.substring(dp+1);
		}
		
		if ( str.startsWith("RP")){
			
			str = str.substring(2);
		}
		
		return( str );
	}
	
	public void
	notSupported()
	{
		throw( new RuntimeException( "RPObject:: method not supported"));
	}
	
	public void
	notSupported(
		Object	o )
	{
		throw( new RuntimeException( "RPObject:: method not supported - " + o ));
	}
}
