key0-96/
key0-96/doc/key/
key0-96/doc/key/credits/
key0-96/doc/key/developers/
key0-96/doc/key/developers/resources/
key0-96/setup/caves/
key0-96/setup/help/
key0-96/setup/ruins/
key0-96/src/
key0-96/src/commands/
key0-96/src/events/
key0-96/src/hack/
key0-96/src/sql/
key0-96/src/swing/
key0-96/src/talker/forest/
key0-96/src/talker/objects/
key0-96/src/terminals/
/*
**               j###t  ########## ####   ####
**              j###t   ########## ####   ####
**             j###T               "###L J###"
**          ######P'    ##########  #########
**          ######k,    ##########   T######T
**          ####~###L   ####
**          #### q###L  ##########   .#####
**          ####  \###L ##########   #####"
**
**  $Id$
**
**  Class History
**
**  Date        Name         Description
**  ---------|------------|-----------------------------------------------
**  19Aug98     subtle       start of recorded history
**
*/

package key;

import key.collections.SiteCollection;

import java.util.Enumeration;
import java.io.IOException;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.StringTokenizer;
import java.util.Hashtable;

/**
  *   A container for sites.  The Container is used as a
  *   numeric hashtable for each sites number...
 */
public class Network extends Container implements Subnet
{
	int position;
	int maxLen;
	
	/**
	  * @param num is the low number of this network, for instance
	  *            138 for the start of SoCS
	 */
	protected Network( int place, int classDistance, Integer num )
	{
		this();
		setPosition( place, classDistance, num );
	}

	public void setPosition( int place, int classDistance, Integer num )
	{
		position = place;
		maxLen = classDistance;
		
		if( num != null )
			setKey( num );
	}

	Network()
	{
		contained = new SiteCollection();

		setConstraint( Type.SUBNET );
	}
	
	public void dump()
	{
		dump( 0 );
	}
	
	/**
	  *  This command is overridden in Internet
	 */
	public void unRegisterTrailer( String t )
	{
		((Network)getParent()).unRegisterTrailer( t );
	}
	
	/**
	  *  This command is overridden in Internet
	 */
	public void registerTrailer( Site t )
	{
		((Network)getParent()).registerTrailer( t );
	}
	
	protected void dump( int indent )
	{
		for( Enumeration e = elements(); e.hasMoreElements(); )
		{
			Object o = e.nextElement();

			if( o instanceof Site )
			{
				System.out.println( spaces( indent ) + o.toString() );
			}
			else
			{
				((Network)o).dump( indent + 2 );
			}
		}
	}

	public Site search( int[] address )
	{
		if( position >= address.length )
		{
				//  not enough args to uniquely identify
				//  maybe throw an exception?
			//Log.debug( this, "position shortcutted on pos " + position );
			return( null );
		}
		
		Integer sWrapper = new Integer( (int) address[position] );
		
		//Log.debug( this, "position " + position + ", id of net is " + getId() + ", address at that is " + sWrapper.toString() );
		
		Object matched = contained.get( sWrapper );
		if( matched != null )
		{
			if( matched instanceof Reference )
			{
				try
				{
					matched = ((Reference)matched).get();
				}
				catch( OutOfDateReferenceException e )
				{
					try
					{
						contained.unlink( (Symbol)matched );
					}
					catch( Exception ex )
					{
					}
					
					return( null );
				}
			}
			
			if( matched instanceof Network )
				return( ((Network)matched).search( address ) );  //  pass it down
			else if( matched instanceof Site )
				return( (Site) matched );
			else
				throw new UnexpectedResult( "Network siteLevel contains something other than subnets & sites" );
		}
		else
			return( null );
	}

	public void insert( Site site )
	{
		int[] mask = site.getMask();
		if( position == mask.length )
		{
				//  this network represents the site??
			throw new UnexpectedResult( "invalid site IP address too short" );
		}
		else if( position > mask.length )
			throw new UnexpectedResult( "site insert passed down too many times" );
		
		if( position == maxLen )
		{ 
				//  just insert the site - this is a last level network (eg, 138.25.)
				//  could check there wasn't already anything here
			//siteLevel.put( new Integer( (int) mask[ position ] ), site );
			
			try
			{
				super.add( site );
			}
			catch( BadKeyException e )
			{
				throw new UnexpectedResult( e.toString() + " while adding a *numbered* site to the network" );
			}
			catch( NonUniqueKeyException e )
			{
				throw new UnexpectedResult( e.toString() + " while adding a *numbered* site to the network" );
			}

			//Log.debug( this, "inserted site at position " + position );
		}
		else
		{
			Object o = contained.get( new Integer( (int) mask[ position ] ) );
			if( o instanceof Reference )
				o = ((Reference)o).get();
			
			Network subnet = (Network) o;
			
			if( subnet == null )
			{
					//  need to insert another subnet
				Integer n = new Integer( (int) mask[ position ] );
				subnet = (Network) Factory.makeAtom( Network.class );
				subnet.setPosition( position + 1, maxLen, n );
				//siteLevel.put( n, subnet );
				try
				{
					super.add( subnet );
				}
				catch( BadKeyException e )
				{
					throw new UnexpectedResult( e.toString() + " while adding a *numbered* site to the network" );
				}
				catch( NonUniqueKeyException e )
				{
					throw new UnexpectedResult( e.toString() + " while adding a *numbered* site to the network" );
				}
			
				//Log.debug( this, "added subnet at position " + (position+1) );
			}
			
			subnet.insert( site );
		}
	}
	
	private static final String SPACES="                                                                      "; 
	/**
	  * Returns a string of the specified number of spaces
	  * <p>
	  * This routine has been optimised for up to 70 spaces,
	  * requesting more than this will slow it down.
	 */
	private static String spaces( int n )
	{
		if( n > SPACES.length() )
		{
			StringBuffer sb = new StringBuffer();
			while( n > SPACES.length() )
			{
				sb.append( SPACES );
				n -= SPACES.length();
			}
			sb.append( SPACES.substring( SPACES.length() - n ) );
			return( sb.toString() );
		}
		else
			return( SPACES.substring( SPACES.length() - n ) );
	}
}