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 ##########   #####"
**
**  Class History
**  
**  Date        Name         Description
**  ---------|------------|-----------------------------------------------
**  21Jun97     subtle       modified loadFrom so that the order of the
**                           elements in the linked list is preserved.
**  22Jun97     subtle       added a constructor to clone the contents of
**                           another collection.
**
*/

package key.collections;
import key.*;
import key.util.LinkedList;
import key.util.EmptyEnumeration;

import java.util.Enumeration;
import java.io.IOException;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.NoSuchElementException;

/**
  *  The shortcut container was created so that you could 'shortcut'
  *  the contents of a container on the string.  There are limitations
  *  in the implementation - it uses Trie's to provide the shortcut,
  *  so only [a-z] characters may be used.  (No punctuation)
  *
  *  Obviously, everything in the collection must be adequately (and
  *  uniquely named).
 */
public final class ObjectCollection implements Collection
{
	private static final long serialVersionUID = -340343914054921047L;
	private LinkedList theList;
	
	public ObjectCollection()
	{
		theList = null;
	}
	
	public ObjectCollection( Collection c )
	{
		this();
		
		for( Enumeration e = c.elements(); e.hasMoreElements(); )
		{
			try
			{
				link( (Symbol) e.nextElement() );
			}
			catch( BadKeyException ex )
			{
			}
			catch( NonUniqueKeyException ex )
			{
			}
		}
	}
	
	/**
	  * 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 synchronized void link( Symbol a ) throws NonUniqueKeyException,BadKeyException
	{
		ensureList();
		
		/*
		try
		{
			a = (Symbol) a.clone();
		}
		catch( CloneNotSupportedException ex )
		{
		}
		*/
		
		Object key = a.getKey();
		AliasListKey newKey;

		if( key == null )
		{
			throw new UnexpectedResult( "cannot add atom without key to ObjectCollection" );
		}
		
		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 );
			}
		}
		
		theList.prepend( a );
	}
	
	public synchronized void conceal( Symbol a )
	{
		throw new UnexpectedResult( "conceal not supported on this collection" );
	}
	
	public synchronized void reveal( Symbol a )
	{
		throw new UnexpectedResult( "reveal not supported on this collection" );
	}
	
	public void concealable( boolean t )
	{
	}
	
	/**
	  * 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 synchronized void unlink( Symbol a ) throws NoSuchElementException,BadKeyException
	{
		if( theList != null )
		{
			theList.removeEqual( a );
			if( theList.count() == 0 )
				theList = null;
		}
	}
	
	public boolean contains( Symbol o )
	{
		return( (theList != null && theList.containsEqual( o )) );
	}
	
	public void rekey( Symbol o )
	{
		if( theList != null )
			theList.replaceEqual( o );
	}
	
	private final void ensureList()
	{
		if( theList == null )
			theList = new LinkedList();
	}
	
	public synchronized 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 )
	{
		String match;
		int hc;
		
		if( theList == null )
			return( null );
		
		try
		{
			match = (String) key;
			hc = match.toLowerCase().hashCode();
		}
		catch( ClassCastException e )
		{
			throw new UnexpectedResult( "non string key passed to shortcut collection" );
		}
		
			//  this match, this match strength
		Symbol tm = null;
		int tms = Integer.MAX_VALUE;

		//System.out.println( "Scanning object collection for '" + match + "'" );
		
		for( Enumeration e = theList.elements(); e.hasMoreElements(); )
		{
			Symbol o = (Symbol) e.nextElement();
			Object k = o.getKey();
			
			try
			{
				int s = ((AliasListKey)k).getMatchStrength( hc, match );
				//System.out.println( "  list key '" + k.toString() + "' strength " + s );
				
				switch( s )
				{
					case 0:
						break;
					case 1:
						return( o );
					default:
						if( s < tms )
						{
							tms = s;
							tm = o;
						}
						break;
				}
			}
			catch( ClassCastException ex )
			{
				Log.debug( this, ex.toString() + " in ObjectCollection::get()" );
				
				if( k.equals( key ) )
				{
					//System.out.println( "  key '" + k.toString() + "' matched, returning" );
					return( o );
				}
				//else
					//System.out.println( "  key '" + k.toString() + "' didn't match" );
			}
		}
		
		return( tm );
	}
	
	public Object getTrieFor( String match )
	{
		throw new UnexpectedResult( "getTrieFor not available in this collection" );
	}
	
	public Symbol getExact( String match )
	{
		return( (Symbol) get( match ) );
	}
	
	public Symbol getElementAt( int c )
	{
		if( theList != null )
			return( (Symbol) theList.getElementAt( c ) );
		else
			return( null );
	}
	
	/**
	  *  aha!, but I reserve the right to make this function more efficient
	  *  this way ;p~  (ie, it isn't very, atm)
	 */
	public synchronized void removeElementAt( int c ) throws NonUniqueKeyException,NoSuchElementException,BadKeyException
	{
		if( theList != null )
			unlink( (Symbol) theList.getElementAt( c ) );
	}

	public Enumeration elements()
	{
		if( theList != null )
			return( theList.elements() );
		else
			return( new EmptyEnumeration() );
	}

	public int count()
	{
		if( theList != null )
			return( theList.count() );
		else
			return( 0 );
	}
	
	public void deallocate()
	{
	}
	
	public void partialLink( Symbol added )
	{
		throw new UnexpectedResult( "partialLink not available in this collection" );
	}
}