/*
** 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.util.LinkedList;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.io.Writer;
import java.io.IOException;
/**
* This class defines the basic abstract implementation of
* a terminal type. It's specific to a TelnetConnection,
* since the other (custom) terminals will need changes at
* a much higher level.
*/
public class Terminal
{
/**
* The maximum expected colours on a line.
* <br>
* If this limit is exceeded, then the ^-
* operator won't work correctly - for
* efficiency reasons we're simply going
* to write over the top part of the stack.
* <br>
* If this becomes a problem in the future,
* (all those F&$#*(&#$ gits who set their
* emails "all pretty colours" for instance,
* just increase this stack size.
*/
public static final int STACK_SIZE = 15;
/**
* The position that was marked. If no-where
* has been marked, this will be -1. If you
* mark, you can't remark something until
* the terminal has been reset (like what
* happens when there's a new paragraph)
* <br>
* Its meant to be used in, for example, the
* 'say' command. You don't want the users
* stuffed up colour codes wrecking your
* colouring for the end quote, so right after
* the open quote you mark, then restore mark
* just before the end quote. This means
* no matter *what* happens, you can always
* get back to where you marked.
* <br>
* Don't mark when you're > the stack size.
* <br>
* Again - if you run out of stack, bad things *will
* happen*. ;)
*/
protected int marked;
/**
* The actual stack variable, holds all the
* previous colour codes.
*/
protected char[] stack;
/**
* This always points at the next place to put
* an increasing colour code. (ie, one past)
*/
protected int stackValue;
/**
* If this boolean is true, then the stream is
* in an uncoloured state (the last code sent
* down reset it completely).
*/
protected boolean normal;
/**
* It is the responsibility of the subclass to
* set this array.
*/
protected String names[] = { "none", "dumb" };
protected Terminal()
{
marked = -1;
stackValue = 1;
stack = new char[ STACK_SIZE ];
normal = true;
// see, here's the thing - the first entry
// on the stack is *always* normal, since
// without it, we've got no way to restore.
stack[0] = 'N';
}
/**
* Should be called at the end of every section
* of input - will reset the stream to its
* proper state
*/
public void reset( Writer outputStream ) throws IOException
{
stackValue = 1;
marked = -1;
if( !normal )
{
outputStream.write( stringForCode( 'N' ) );
//Log.debug( this, "terminal reset" );
normal = true;
}
//else
//Log.debug( this, "terminal NOT reset (already normal)" );
}
public boolean nameMatches( String test )
{
for( int i = 0; i < names.length; i++ )
{
if( test.equalsIgnoreCase( names[i] ) )
return true;
}
return false;
}
public String getName()
{
if( names != null && names.length > 0 )
return( names[0] );
else
throw new UnexpectedResult( "names isn't valid in " + Type.typeOf( this ).getName() );
}
/**
* Does all the necessary coding to support
* the newly returned colour code for input
* into the stream.
*/
public String stringForCode( char code )
{
String result="";
switch( code )
{
case '@': // set mark if its not already
if( marked == -1 )
marked = stackValue;
return( "" );
case '$':
if( marked != -1 )
stackValue = marked - 1;
// restore the previous colour
return( stringForCode( stack[ stackValue ] ) );
case '-':
if( stackValue > 1 )
stackValue-=2;
// technically speaking, the stackValue
// could here be invalid, but.. I mean..
// nothings going to go wrong, right?
// *arrogent smile*
return( stringForCode( stack[ stackValue ] ) );
}
normal = false;
result = codeLookup( code );
// push this value onto the stack
if( stackValue < STACK_SIZE )
stack[ stackValue++ ] = code;
else
stack[ STACK_SIZE-1 ] = code;
return( result );
}
public String codeLookup( char code )
{
switch( code )
{
case 'n':
case 'N':
normal = true;
}
return( "" );
}
public String clearScreen()
{
return( "" );
}
public String beep()
{
return( "" );
}
protected static LinkedList terminalTypes;
public static Terminal createTerminal( String terminalName ) throws IllegalAccessException, InstantiationException
{
for( Enumeration e = terminalTypes.elements(); e.hasMoreElements(); )
{
Terminal t = (Terminal) e.nextElement();
if( t.nameMatches( terminalName ) )
return( (Terminal) t.getClass().newInstance() );
//return( (Terminal) Type.typeOf( t ).newInstance() );
}
return null;
}
static
{
terminalTypes = new LinkedList();
terminalTypes.append( new key.terminals.Dumb() );
terminalTypes.append( new key.terminals.ISO6429() );
}
}