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;

import java.net.Socket;
import java.net.InetAddress;
import java.io.*;
import java.util.Enumeration;
import java.util.StringTokenizer;

/**
 */
public class WebConnection
extends SocketIC
{
	public static final String CRLF = "\r\n";
	public static final int INPUT_BUFFER = 640;
	private transient WebConnectPort www;
	
	/**
	  *  The constructor must take a socket as its sole
	  *  argument
	  *
	  * @param s The socket that the connection is on
	 */
	public WebConnection( Socket s, WebConnectPort wcp ) throws IOException
	{
		super( s );
		www = wcp;
		inBuffer = new char[INPUT_BUFFER+2];
		
			//  since we don't have a null constructor, we can't
			//  be created by the factory: this is our concession.
		Factory.postCreateProcess( this );
	}
	
	public void send( Paragraph p )
	{
		try
		{
			if( p instanceof TextParagraph )
			{
				TextParagraph tp = (TextParagraph) p;
				
				switch( tp.getAlignment() )
				{
					case TextParagraph.LEFT:
						output.write( "<DIV ALIGN=LEFT>" + CRLF );
						parseToHTML( tp.getText(), true );
						output.write( "</DIV>" + CRLF );
						break;
					case TextParagraph.CENTERALIGNED:
						output.write( "<DIV ALIGN=CENTER><PRE>" + CRLF );
						parseToHTML( tp.getText(), false );
						output.write( "</PRE></DIV>" + CRLF );
						break;
					default:
						output.write( "<DIV>" + CRLF );
						parseToHTML( tp.getText(), true );
						output.write( "</DIV>" + CRLF );
						break;
				}
			}
			else if( p instanceof HeadingParagraph )
			{
				HeadingParagraph tp = (HeadingParagraph) p;
				
				switch( tp.getAlignment() )
				{
					case HeadingParagraph.LEFT:
						output.write( "<TABLE WIDTH=100% CELLPADDING=0 CELLSPACING=0><TR><TD ALIGN=LEFT><B>" + CRLF );
						
						parseToHTML( tp.getText(), true );
						
						output.write( "</B></TD><TD WIDTH=80%><HR WIDTH=100%></TD></TR></TABLE>" + CRLF );
						break;
					case HeadingParagraph.CENTRE:
						output.write( "<TABLE WIDTH=100% CELLPADDING=0 CELLSPACING=0><TR><TD WIDTH=30%><HR WIDTH=100%></TD><TD ALIGN=CENTER><B>" + CRLF );
						
						parseToHTML( tp.getText(), true );
						
						output.write( "</B></TD><TD WIDTH=30%><HR WIDTH=100%></TD></TR></TABLE>" + CRLF );

						break;
					case HeadingParagraph.RIGHT:
						output.write( "<TABLE WIDTH=100% CELLPADDING=0 CELLSPACING=0><TR><TD WIDTH=80%><HR WIDTH=100%></TD><TD ALIGN=RIGHT><B>" + CRLF );
						
						parseToHTML( tp.getText(), true );
						
						output.write( "</B></TD></TR></TABLE>" + CRLF );
						break;
					default:
						output.write( "<H1>" + CRLF );
						parseToHTML( tp.getText(), true );
						output.write( "</H1>" + CRLF );
						break;
				}
			}
			else if( p instanceof LineParagraph )
			{
				output.write( "<HR>" + CRLF );
			}
			else if( p instanceof BlankLineParagraph )
			{
				output.write( "<BR>" + CRLF );
			}
			else if( p instanceof MultiParagraph )
			{
				for( Enumeration e = ((MultiParagraph)p).getParagraphs(); e.hasMoreElements(); )
				{
					send( (Paragraph) e.nextElement() );
				}
			}
		}
		catch( IOException e )
		{
			close();
			throw new NetworkException( e );
		}
	}
	
	public void parseToHTML( String message, boolean replaceCR )
	{
		try
		{
			StringBuffer gen = new StringBuffer();
			StringTokenizer lines = new StringTokenizer( message, "\n", true );
			
			while( lines.hasMoreTokens() )
			{
				String str = lines.nextToken();
				
				if( str.equals( "\n" ) )
				{
					if( replaceCR )
						output.write( "<BR>" + CRLF );
				}
				else
				{
						//  this is the colour matching scope
						
						//  here we insert our check for colour codes -
						//  if the word has a ^ in it, there is something
						//  we have to filter out :)
					int colourIndex = str.indexOf( '^' );
					int start = 0;
					
					while( colourIndex != -1 && (colourIndex+1) < str.length() )
					{
						output.write( str.substring( start, colourIndex ) );
						
						char c = str.charAt( colourIndex + 1 );
						
						if( c == '^' )
						{		//  its been doubled to display it - thats cool
							output.write( '^' );
							start = colourIndex+2;
						}
						else
						{		//  lets just skip one character
							start = colourIndex+2;
							//outputStream.print( terminal.stringForCode( c ) );
							if( c == '-' || c == 'N' )
								output.write( "</B>" );
							else
								output.write( "<B>" );
						}
						
						colourIndex = str.indexOf( '^', start );
					}
					
					output.write( str.substring( start ) );
				}
			}
		}
		catch( IOException e )
		{
			close();
			throw new NetworkException( e );
		}
	}
	
	private int lastCharWas = -1;
	char[] inBuffer;
	
	/**
	  * This function blocks until a line of input is
	  * recieved.  Think of it as being much like the
	  * input statement in BASIC of old. *shudder*
	 */
	public String input()
	{
		try
		{
			int where=0;
			char b=' ';
			
			output.flush();
			
			do
			{
				int i;
				
					//  continuously skip until a CR or LF
					//  when the buffer runs out
				if( where >= INPUT_BUFFER )
				{
					output.write( "414 Request-URI too long" + CRLF );
					close();
					throw new IOException( "too long" );
				}
				else
					i = inputStream.read();
				
				if( i != -1 )
					b = (char) i;
				else
					throw new IOException( "connection closed" );
				
				if( b >= 32 && b <= 126 )    //  valid ascii characters only
				{
					inBuffer[where++] = (char) b;
				}
				else if( b == 8 || b == 127 )
				{
					if( where > 0 )
						where--;
				}
			} while( !((b == '\r') && !(lastCharWas == '\n')) && !((b == '\n') && !(lastCharWas == '\r' )) );

			lastCharWas = b;
			
			return( new String( inBuffer, 0, where ) );
		}
		catch( IOException e )
		{
			close();
			throw new NetworkException( e );
		}
	}
	
	public void check()
	{
	}
	
	public void run()
	{
		www.handleConnection( this );
		www = null;
	}
	
	public final void sendLine()
	{
		try
		{
			output.write( "<HR>" + CRLF );
		}
		catch( IOException e )
		{
			close();
			throw new NetworkException( e );
		}
	}
	
	public final String hiddenInput( String prompt )
	{
		return( input() );
	}
	
	public final String input( String prompt )
	{
		return( input() );
	}
	
	public final void blankLine()
	{
		try
		{
			output.write( "<BR>" + CRLF );
		}
		catch( IOException e )
		{
			close();
			throw new NetworkException( e );
		}
	}
	
	public final void sendSubliminal( String message, int duration, int frequency )
	{
	}

	public final void send( String message )
	{
		parseToHTML( message, true );
	}
	
	public final void sendRaw( String message )
	{
		parseToHTML( message, true );
	}

	public final void println( String message )
	{
		try
		{
			output.write( message + CRLF );
		}
		catch( IOException e )
		{
			close();
			throw new NetworkException( e );
		}
	}
	
	public final void send( char qualifier, String message )
	{
		parseToHTML( qualifier + message, true );
	}
	
	public final void send( Paragraph para, boolean okayToPage )
	{
		send( para );
	}
	
	public final boolean isPaging()
	{
		return( false );
	}
}