/*
** 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" );
}
}