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
**  ---------|------------|-----------------------------------------------
**  30Sep98     subtle       created
**
*/

package key;

import key.collections.*;

import java.util.Enumeration;
import java.io.*;
import java.util.StringTokenizer;

import key.util.Trie;

/**
  *  LightWeight Player Group - a collection of players
 */
public class LWPlayerGroup implements PlayerGroup
{
	transient Collection players;
	
	public LWPlayerGroup()
	{
	}
	
	public void setCollection( Collection c )
	{
		players = c;
	}
	
	/**
	  * Add this player to the list of players
	  *
	  * @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 linkPlayer( Player p ) throws NonUniqueKeyException,BadKeyException
	{
		if( !players.contains( p ) )
		{
			players.link( p );
		}
		else
			throw new UnexpectedResult( "adding player " + p.getName() + " to scape when he's already in it" );
	}
	
	/**
	  * 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 unlinkPlayer( Player p ) throws NonUniqueKeyException,java.util.NoSuchElementException,BadKeyException
	{
		players.unlink( p );
	}
	
	/**
	  * Returns the player matched, or, possibly, an instance of
	  * a Trie object that contains all the matching players.
	  * <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.
	  * <p>
	  * If you specify a comma seperated list of players, a scape
	  * containing the players will be returned.  Such a scape can
	  * also contain errors when individual multiple matches are
	  * caught
	  *
	  * @param match the start or whole string to match from
	  * @return A player object, referring to the sole match, or a Trie
	 */
	public final Object getPlayer( Player p, String match )
	{
		//System.out.println( "players is " + players.getClass().getName() + " on " + getClass().getName() );
		StringTokenizer st = new StringTokenizer( match, ",", false );
		return( getPlayer( p, st ) );
	}
	
	public final Object getPlayer( String match )
	{
		return( players.get( match ) );
	}
	
	protected final Object getPlayer( Player p, StringTokenizer st )
	{
		Object single;
		
		if( st.hasMoreTokens() )
		{
			single = players.get( st.nextToken() );
			
			if( st.hasMoreTokens() )
			{	//  more than one player
				try
				{
					LWPlayerGroup group = new LWPlayerGroup();
					
						//  the use of this makes the reference persistant -
						//  it can survive the deletion and login/logout
						//  of players fairly easily.
					group.players = new ReferencingProxyCollection( new NoKeyCollection() );
					
					do
					{
						if( single instanceof Player )
						{
							group.linkPlayer( (Player)single );
						}
						else if( single instanceof Trie )
						{
								//  look for a prefer
							for( Enumeration e = ((Trie)single).elements(); e.hasMoreElements(); )
							{
								Player o = (Player) e.nextElement();
								
								if( p.getPrefer().containsPlayer( o ) )
									group.linkPlayer( o );
							}
						}
						
						single = players.get( st.nextToken() );
					} while( st.hasMoreTokens() );
					
					if( single instanceof Player )
					{
						group.linkPlayer( (Player)single );
					}
					else
						;  // in the future, link to a seperate linked
						   // linked list explicitly for multiple matches
					
					return( group );
				}
				catch( BadKeyException e )
				{
					throw new UnexpectedResult( e.toString() + " occurred when creating temporary sub-group" );
				}
				catch( NonUniqueKeyException e )
				{
					throw new UnexpectedResult( e.toString() + " occurred when creating temporary sub-group" );
				}
			}
			else
			{
				return( single );
			}
		}
		else
			return( null );
	}
	
	public final Enumeration players()
	{
		return( players.elements() );
	}
	
	public final boolean containsPlayer( Player p )
	{
		return( players.contains( p ) );
	}
	
	public final String allNames()
	{
		String all[] = new String[numberPlayers()];
		
		int upto=0;
		for( Enumeration e = players(); e.hasMoreElements(); )
			all[upto++] = (String) ((Player)e.nextElement()).getName();

		return( Grammar.enumerate( all ) );
	}
	
	/**
	  *  All the names, except substitute 'you' for player p
	 */
	public final String allNames( Player p )
	{
		String all[] = new String[numberPlayers()];
		
		int upto=0;
		for( Enumeration e = players(); e.hasMoreElements(); )
		{
			Player t = (Player) e.nextElement();
			if( t == p )
				all[upto++] = "you";
			else
				all[upto++] = (String) t.getName();
		}
		
		return( Grammar.enumerate( all ) );
	}
	
	//  META: this one is deprecated
	public final int numberPlayers()
	{
		return( players.count() );
	}
	
	public final int getNumberPlayers()
	{
		return( players.count() );
	}
	
	//  this method replaced by allNames
	public String getAllNames() { return( allNames() ); }
	
	/**
	  *  A general way of saying that the people in
	  *  this scape should be notified of the
	  *  supplied Effect.
	 */
	public void splash( Effect t, SuppressionList s )
	{
		for( Enumeration e = players(); e.hasMoreElements(); )
			splashToPlayer( ((Player)e.nextElement()), t, s );
	}
	
	protected final void splashToPlayer( Player p, Effect t, SuppressionList sl )
	{
		try
		{
			p.splash( t, sl );
		}
		catch( Exception e )
		{
			Log.error( " during splashToPlayer( " + p.getName() + " )" , e );
		}
	}
	
	/**
	  *  Sends the splash to everyone except the listed
	  *  atom
	 */
	public void splashExcept( Effect t, Splashable except, SuppressionList sl )
	{
		for( Enumeration e = players(); e.hasMoreElements(); )
		{
			Player s = (Player)e.nextElement();
			if( except instanceof Scape )
			{
				if( !((Scape)except).containsPlayer( s ) )
					splashToPlayer( s, t, sl );
			}
			else
			{
				if( s != except )
					splashToPlayer( s, t, sl );
			}
		}
	}
	
	/**
	  *  Sends the splash to everyone except the listed
	  *  atoms
	 */
	public void splashExcept( Effect t, Splashable[] except, SuppressionList sl )
	{
		for( Enumeration e = players(); e.hasMoreElements(); )
		{
			Atom s = (Atom)e.nextElement();
			boolean match;
			
			match=true;
			
			for( int i = 0; i < except.length; i++ )
			{
				if( s == except[i] )
				{
					match = false;
					break;
				}
			}
			
			if( match )
				s.splash( t, sl );
		}
	}
}