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.collections;

import key.*;

import key.util.LinkedList;
import java.util.Enumeration;
import java.io.*;
import java.util.NoSuchElementException;
import java.util.Hashtable;

/**
  *  A special collection that requires that all its
  *  symbols use AliasListKey's as their key.  WARNING:
  *  this collection should NOT be used by a reference
  *  container, as it has a nasty tendancy to change the
  *  key of everything added to it to AliasListKey's.
  *
  *  This collections very specific purpose at the moment
  *  is for help files. (ie, "help res" and "help resident"
  *  call the same file - the lookup must be equivalent.
 */
public final class AliasCollection implements Collection
{
	private transient Hashtable theHash;
	private LinkedList theList;
	
	public AliasCollection()
	{
		init();
		theList = new LinkedList();
	}
	
	public AliasCollection( Collection c )
	{
		this();
		
		for( Enumeration e = c.elements(); e.hasMoreElements(); )
		{
			try
			{
				link( (Symbol) e.nextElement() );
			}
			catch( BadKeyException ex )
			{
			}
			catch( NonUniqueKeyException ex )
			{
			}
		}
	}
	
	private void init()
	{
		theHash = new Hashtable();
	}
	
	private void readObject( ObjectInputStream ois ) throws IOException
	{
		try
		{
			ois.defaultReadObject();
		}
		catch( ClassNotFoundException e )
		{
			throw new UnexpectedResult( e.toString() );
		}
		
		init();
		
		for( Enumeration e = theList.elements(); e.hasMoreElements(); )
		{
			try
			{
				linkToHash( (Symbol) e.nextElement() );
			}
			catch( NonUniqueKeyException ex )
			{
				Log.debug( this, ex.toString() );
				ex.printStackTrace( System.out );
			}
		}
	}
	
	private void linkToHash( Symbol a ) throws NonUniqueKeyException
	{
		Object key = a.getKey();
		AliasListKey newKey;
		
		if( !(key instanceof AliasListKey) )
		{
			newKey = new AliasListKey();
			newKey.setPrimary( key.toString() );
			
			a.setKey( newKey );
			
				//  this is pretty hacky.
			if( a instanceof Reference )
			{
				((Reference)a).get().setKey( newKey );
			}
			
			//System.out.println( "Added non-ALK: " + key.toString() + " to AliasColl" );
		}
		else
		{
			newKey = (AliasListKey) key;
			//System.out.println( "Added ALK: " + key.toString() + " to AliasColl" );
		}
		
		String pk = newKey.getPrimary();
		
		if( theHash.contains( pk ) )
			throw new NonUniqueKeyException( "'" + newKey.getPrimary() + "' is already in this collection." );
		
		theHash.put( pk, a );
		
		addSecondaries( newKey, a );
	}
	
	/**
	  * Add this object to the list of objects
	  * @param p the player to add to the list
	  * @exception NonUniqueKeyException if there is already a player in with this name
	  * @exception BadKeyException if this players name is malformed somehow
	 */
	public void link( Symbol a ) throws NonUniqueKeyException,BadKeyException
	{
		linkToHash( a );
		theList.append( a );
	}
	
	public void conceal( Symbol a )
	{
	}
	
	public void reveal( Symbol a )
	{
	}
	
	/**
	  * Adds this atom to the database in such a
	  * way that it can be matched, but not seen
	  * by iterating through the elements.
	 */
	public void partialLink( Symbol a ) throws NonUniqueKeyException,BadKeyException
	{
		link( a );
	}

	/**
	  * Take this player out of the list of players
	  * @param p the player to remove from the list
	  * @exception NoSuchElementException if the player is not in the list
	  * @exception BadKeyException if the players name is malformed somehow
	 */
	public void unlink( Symbol a ) throws NoSuchElementException,BadKeyException
	{
		Object key = a.getKey();

			//  its not possible that the element be
			//  in this collection unless it has an
			//  aliaslistkey key.
		if( key instanceof AliasListKey )
		{
			AliasListKey alk = (AliasListKey) key;
			
			if( theHash != null )
			{
				theHash.remove( alk.getPrimary() );
				theList.removeEqual( a );
				
				removeSecondaries( alk );
			}
		}
	}

	public boolean contains( Symbol o )
	{
		return( theList.containsEqual( o ) );
	}
	
	/**
	  *  Sorts the elements in this linked trie
	 */
	public void sort()
	{
	}
	
	/**
	  * Returns the atom matched, or, possibly, an instance of
	  * a Trie object that contains all the matching atoms.
	  * <p>
	  * A null is returned if no matches were found at all.  The
	  * match string is searched until the end of the string or
	  * a non-alphabetical character is found.
	  *
	  * @param match the start or whole string to match from
	  * @return An atom object, referring to the sole match, or a Trie
	 */
	public Object get( Object key )
	{
		if( key instanceof String )
			return( theHash.get( ((String)key).toLowerCase() ) );
		else
			return( theHash.get( key.toString() ) );
	}

	public Symbol getExact( String key )
	{
		return( (Symbol) get( key ) );
	}
	
	public Object getTrieFor( String match )
	{
		return( null );
	}

	public Symbol getElementAt( int c )
	{
		return( (Symbol) theList.getElementAt( c ) );
	}

	/**
	  *  aha!, but I reserve the right to make this function more efficient
	  *  this way ;p~  (ie, it isn't very, atm)
	 */
	public void removeElementAt( int c ) throws NonUniqueKeyException,NoSuchElementException,BadKeyException
	{
		Symbol s = (Symbol) theList.getElementAt( c );
		
		unlink( s );
	}

	public Enumeration elements()
	{
		return( theList.elements() );
	}

	public int count()
	{
		return( theList.count() );
	}
	
	public void deallocate()
	{
	}
	
	public void concealable( boolean t )
	{
	}

	public void removeSecondaries( AliasListKey alk )
	{
		for( Enumeration e = alk.secondaryKeys(); e.hasMoreElements(); )
			theHash.remove( e.nextElement() );
	}
	
	public void addSecondaries( AliasListKey alk, Symbol o )
	{
		for( Enumeration e = alk.secondaryKeys(); e.hasMoreElements(); )
		{
			Object n = e.nextElement();
			//System.out.println( "ALK: aliased " + n.toString() );
			theHash.put( n, o );
		}
	}
}