import java.awt.*;
import java.applet.*;
//import java.awt.event.*;
import java.awt.image.*;
import java.net.*;
import java.io.*;
import java.util.*;

/**
 * JVtxPage implements the teletext decoding and most of the user
 * interactions.
 * JVtxPage was first implemented using the new Java 1.1 event model.
 * Later I discovered that my Netscape 4.05 was unable to handle this
 * properly. So I decided to go back to the old event handling methods.
 * Many pieces of code have been borrowed from Martin Bucks videotext
 * package (<martin-2.buck@student.uni-ulm.de>).
 * @author Martin Denn <mdenn@unix-ag.uni-kl.de>
 * @version 0.02
 */
//public class VtPage extends Canvas 
//    implements MouseListener, MouseMotionListener, KeyListener  {
public class JVtxPage extends Canvas {

    private byte letter[] = new byte[1000];
    private byte attrib[] = new byte[1000];
    private byte color[] = new byte[1000];
    private int link_to[] = new int[1000];
    private char typed[] = new char[2];
    private int no_typed = 0;
    private int page_number;
    private int subpage_number;
    private int max_subpage_number;
    private int hour;
    private int minute;
    private int charset;
    private int dummy;
    private int current_link;
    private JVtxFont vtx_font;
    private URL code_base;
    private Applet applet;
    private JVtxHistory history = new JVtxHistory();
    private boolean reveal = false;
    private boolean vis_flash = false;
    private JVtxFlash flash_thread;
    //private Cursor link_cursor = new Cursor(Cursor.HAND_CURSOR);
    //private Cursor normal_cursor = new Cursor(Cursor.DEFAULT_CURSOR);

    private final boolean right_parity[] = {
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false, 
        false, true,  true,  false, true,  false, false, true,  
        false, true,  true,  false, true,  false, false, true,  
        true,  false, false, true,  false, true,  true,  false
    };

    private final String vtx_separators = " .-/<>+";

    private final byte unhamtab[] = {
          (byte)0x01, (byte)0xff, (byte)0x81, (byte)0x01,
          (byte)0xff, (byte)0x00, (byte)0x01, (byte)0xff, 
          (byte)0xff, (byte)0x02, (byte)0x01, (byte)0xff,
          (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0x07, 
          (byte)0xff, (byte)0x00, (byte)0x01, (byte)0xff,
          (byte)0x00, (byte)0x80, (byte)0xff, (byte)0x00, 
          (byte)0x06, (byte)0xff, (byte)0xff, (byte)0x0b,
          (byte)0xff, (byte)0x00, (byte)0x03, (byte)0xff, 
          (byte)0xff, (byte)0x0c, (byte)0x01, (byte)0xff,
          (byte)0x04, (byte)0xff, (byte)0xff, (byte)0x07, 
          (byte)0x06, (byte)0xff, (byte)0xff, (byte)0x07,
          (byte)0xff, (byte)0x07, (byte)0x07, (byte)0x87, 
          (byte)0x06, (byte)0xff, (byte)0xff, (byte)0x05,
          (byte)0xff, (byte)0x00, (byte)0x0d, (byte)0xff, 
          (byte)0x86, (byte)0x06, (byte)0x06, (byte)0xff,
          (byte)0x06, (byte)0xff, (byte)0xff, (byte)0x07, 
          (byte)0xff, (byte)0x02, (byte)0x01, (byte)0xff,
          (byte)0x04, (byte)0xff, (byte)0xff, (byte)0x09, 
          (byte)0x02, (byte)0x82, (byte)0xff, (byte)0x02,
          (byte)0xff, (byte)0x02, (byte)0x03, (byte)0xff, 
          (byte)0x08, (byte)0xff, (byte)0xff, (byte)0x05,
          (byte)0xff, (byte)0x00, (byte)0x03, (byte)0xff, 
          (byte)0xff, (byte)0x02, (byte)0x03, (byte)0xff, 
          (byte)0x03, (byte)0xff, (byte)0x83, (byte)0x03, 
          (byte)0x04, (byte)0xff, (byte)0xff, (byte)0x05,
          (byte)0x84, (byte)0x04, (byte)0x04, (byte)0xff, 
          (byte)0xff, (byte)0x02, (byte)0x0f, (byte)0xff, 
          (byte)0x04, (byte)0xff, (byte)0xff, (byte)0x07, 
          (byte)0xff, (byte)0x05, (byte)0x05, (byte)0x85, 
          (byte)0x04, (byte)0xff, (byte)0xff, (byte)0x05, 
          (byte)0x06, (byte)0xff, (byte)0xff, (byte)0x05, 
          (byte)0xff, (byte)0x0e, (byte)0x03, (byte)0xff, 
          (byte)0xff, (byte)0x0c, (byte)0x01, (byte)0xff, 
          (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0x09, 
          (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0x0b,
          (byte)0x8a, (byte)0x0a, (byte)0x0a, (byte)0xff, 
          (byte)0x08, (byte)0xff, (byte)0xff, (byte)0x0b,
          (byte)0xff, (byte)0x00, (byte)0x0d, (byte)0xff, 
          (byte)0xff, (byte)0x0b, (byte)0x0b, (byte)0x8b, 
          (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0x0b, 
          (byte)0x0c, (byte)0x8c, (byte)0xff, (byte)0x0c, 
          (byte)0xff, (byte)0x0c, (byte)0x0d, (byte)0xff, 
          (byte)0xff, (byte)0x0c, (byte)0x0f, (byte)0xff, 
          (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0x07, 
          (byte)0xff, (byte)0x0c, (byte)0x0d, (byte)0xff, 
          (byte)0x0d, (byte)0xff, (byte)0x8d, (byte)0x0d, 
          (byte)0x06, (byte)0xff, (byte)0xff, (byte)0x0b, 
          (byte)0xff, (byte)0x0e, (byte)0x0d, (byte)0xff, 
          (byte)0x08, (byte)0xff, (byte)0xff, (byte)0x09, 
          (byte)0xff, (byte)0x09, (byte)0x09, (byte)0x89, 
          (byte)0xff, (byte)0x02, (byte)0x0f, (byte)0xff, 
          (byte)0x0a, (byte)0xff, (byte)0xff, (byte)0x09, 
          (byte)0x88, (byte)0x08, (byte)0x08, (byte)0xff, 
          (byte)0x08, (byte)0xff, (byte)0xff, (byte)0x09, 
          (byte)0x08, (byte)0xff, (byte)0xff, (byte)0x0b, 
          (byte)0xff, (byte)0x0e, (byte)0x03, (byte)0xff, 
          (byte)0xff, (byte)0x0c, (byte)0x0f, (byte)0xff, 
          (byte)0x04, (byte)0xff, (byte)0xff, (byte)0x09, 
          (byte)0x0f, (byte)0xff, (byte)0x8f, (byte)0x0f, 
          (byte)0xff, (byte)0x0e, (byte)0x0f, (byte)0xff, 
          (byte)0x08, (byte)0xff, (byte)0xff, (byte)0x05, 
          (byte)0xff, (byte)0x0e, (byte)0x0d, (byte)0xff, 
          (byte)0xff, (byte)0x0e, (byte)0x0f, (byte)0xff, 
          (byte)0x0e, (byte)0x8e, (byte)0xff, (byte)0x0e
    };
          

    private final byte cct2vtx_table[][] = {
        /* English */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0x23,
          (byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0x40,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0x5b,
          (byte)0x5c,(byte)0x5d,(byte)0x5e,(byte)0x5f,
          (byte)0x60,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0x7b,
          (byte)0x7c,(byte)0x7d,(byte)0x7e,(byte)0x7f },
        /* French */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0xc0,
          (byte)0xc1,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0xc2,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0xc3,
          (byte)0xc4,(byte)0xc5,(byte)0xc6,(byte)0x5f,
          (byte)0xc7,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0xc8,
          (byte)0xc9,(byte)0xca,(byte)0xcb,(byte)0x7f },
        /* Swedish */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0x5f,
          (byte)0xcc,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0xcd,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0xce,
          (byte)0xcf,(byte)0xd0,(byte)0xd1,(byte)0xd2,
          (byte)0xc0,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0xd3,
          (byte)0xd4,(byte)0xd5,(byte)0xd6,(byte)0x7f },
        /* Unknown */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0x23,
          (byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0x40,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0x5b,
          (byte)0x5c,(byte)0x5d,(byte)0x5e,(byte)0x5f,
          (byte)0x60,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0x7b,
          (byte)0x7c,(byte)0x7d,(byte)0x7e,(byte)0x7f },
        /* German */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0x5f,
          (byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0xd7,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0xce,
          (byte)0xcf,(byte)0xd1,(byte)0xd8,(byte)0xd2,
          (byte)0xd9,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0xd3,
          (byte)0xd4,(byte)0xd6,(byte)0xda,(byte)0x7f },
        /* Spanish */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0xcb,
          (byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0xcb,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0xde,
          (byte)0xc0,(byte)0xdf,(byte)0xe2,(byte)0xe3,
          (byte)0xdc,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0xd6,
          (byte)0xdd,(byte)0xc7,(byte)0xc2,(byte)0x7f },
        /* Italian */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0x23,
          (byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0xc0,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0xd9,
          (byte)0xcb,(byte)0x5d,(byte)0x5e,(byte)0x5f,
          (byte)0xc5,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0xc2,
          (byte)0xe0,(byte)0xc7,(byte)0xe1,(byte)0x7f },
        /* Unknown */
        { (byte)0x20,(byte)0x21,(byte)0x22,(byte)0x23,
          (byte)0x24,(byte)0x25,(byte)0x26,(byte)0x27,
          (byte)0x28,(byte)0x29,(byte)0x2a,(byte)0x2b,
          (byte)0x2c,(byte)0x2d,(byte)0x2e,(byte)0x2f,
          (byte)0x30,(byte)0x31,(byte)0x32,(byte)0x33,
          (byte)0x34,(byte)0x35,(byte)0x36,(byte)0x37,
          (byte)0x38,(byte)0x39,(byte)0x3a,(byte)0x3b,
          (byte)0x3c,(byte)0x3d,(byte)0x3e,(byte)0x3f,
          (byte)0x40,(byte)0x41,(byte)0x42,(byte)0x43,
          (byte)0x44,(byte)0x45,(byte)0x46,(byte)0x47,
          (byte)0x48,(byte)0x49,(byte)0x4a,(byte)0x4b,
          (byte)0x4c,(byte)0x4d,(byte)0x4e,(byte)0x4f,
          (byte)0x50,(byte)0x51,(byte)0x52,(byte)0x53,
          (byte)0x54,(byte)0x55,(byte)0x56,(byte)0x57,
          (byte)0x58,(byte)0x59,(byte)0x5a,(byte)0x5b,
          (byte)0x5c,(byte)0x5d,(byte)0x5e,(byte)0x5f,
          (byte)0x60,(byte)0x61,(byte)0x62,(byte)0x63,
          (byte)0x64,(byte)0x65,(byte)0x66,(byte)0x67,
          (byte)0x68,(byte)0x69,(byte)0x6a,(byte)0x6b,
          (byte)0x6c,(byte)0x6d,(byte)0x6e,(byte)0x6f,
          (byte)0x70,(byte)0x71,(byte)0x72,(byte)0x73,
          (byte)0x74,(byte)0x75,(byte)0x76,(byte)0x77,
          (byte)0x78,(byte)0x79,(byte)0x7a,(byte)0x7b,
          (byte)0x7c,(byte)0x7d,(byte)0x7e,(byte)0x7f }
    };

    /**
     * Constructor. Displays a new JVtxPage and shows the first page.
     * @param applet the applet which started this panel
     * @param font the JVtxFont to be used to display the page
     */
    public JVtxPage(Applet applet, JVtxFont font) {
        URL page;

        this.vtx_font=font;
        //this.addMouseMotionListener(this);
        //this.addMouseListener(this);
        //this.addKeyListener(this);
        this.code_base=applet.getCodeBase();
        this.applet=applet;
        flash_thread = new JVtxFlash(this);
        loadFirst(100);
    }

    /**
     * represents an int in the range 0 - 15 as hexadecimal value
     * @param i the integer input
     * @return a single letter representing the integer
     */
    private static byte hex(int i) {
        if ((i>=0) && (i<10)) 
            return (byte) ('0' + i);
        else if ((i>=10) && (i<16)) 
            return (byte) ('a' + i);
        else return (byte) '-';
    }

    /**
     * special conversion.
     * Interpretes a decimal value as hex and convert this value back to
     * decimal. Example: the value 100 is converted to 256.
     * @param i the integer input
     * @return the converted value
     */
    private static int hextodec(int i) {
        return ((((i >> 8) & 0x0f) * 100) +
                (((i >> 4) & 0x0f) * 10) +
                (i & 0x0f));
    }


    /**
     * Builds the file name for the requested page
     * @param pg the page number
     * @param sub_pg the subpage number
     * @return the URL to the requested page
     */
    public URL buildPageURL(int pg, int sub_pg) {
        byte b1, b2;
        try {
            b1=(byte) (sub_pg / 10);
            b2=(byte) (sub_pg % 10);
            return new URL(code_base, ((JVtxView) applet).currentChannel()+
                           "/"+pg+"_"+b1+""+b2+".vtx");
        }
        catch (MalformedURLException e) {
            System.out.println("malformed url exception");  
            return (URL) null;
        }
    }
        
    /**
     * loads the specified page and decodes it
     * This method got a little bit too complex...
     * @param page the page's URL
     * @exception when encountering an error while loading the page
     */
    public void load(URL page) throws IOException {
        InputStream i_stream;
        int c, i, j;
        byte last_letter = (byte) ' ';
        byte last_color = (byte) 7;
        byte new_color = (byte) 7;
        boolean parity = false;
        boolean graphics = false;
        boolean grhold = false;
        boolean copy_line = false;
        boolean double_height = false;
        boolean sep_graphics = false;
        boolean conceal = false;
        boolean flash = false;
        byte[] header = new byte[5];
        String last_line = new 
            String("  - Hist +  - Chan +   Reveal     Home  ");
        int pg_no;
        int mag_no;
        int pg_no1, minute1, hour1, charset1;

        // first stop flash-thread
        if (flash_thread.isAlive()) {
            flash_thread.suspend();
        }
        // read vtx header information
        i_stream = page.openStream();
        i_stream.read(header);
        pg_no = i_stream.read();
        mag_no = i_stream.read();
        // The mag_no value is the only number that must be correct in
        // the VTX header - all other values can be extracted from the
        // first 8 characters in the videotext data (well, actually that
        // number is checked later against the page number that appears
        // on most pages in the first line and corrected if needed).
        // The mag_no - magazine number - is usually interpreted as the
        // "hundreds" in the page number, and should be stored as number
        // in the range 1-8. Some programs seem to store the raw value,
        // so if mag_no is 0, we have to push it to 8.
        if (mag_no == 0) {
            System.err.println(mag_no);
            mag_no = 8;
        }
        pg_no += (mag_no << 8);
        page_number=hextodec(pg_no);
        hour = i_stream.read();
        minute = i_stream.read();
        charset = i_stream.read();
        dummy = i_stream.read();
        dummy = i_stream.read();
        // End of VTX file header; now forget all these values (except
        // mag_no) and recalculate them from the first 8 videotext 
        // characters. There are some programs around that just mess
        // them up.
        // BTW, some additional information like the subtitle flag is
        // silently ignored
        pg_no = (unhamtab[i_stream.read()] & 0x0f) | 
            ((unhamtab[i_stream.read()] & 0x0f) << 4);
        pg_no += (mag_no << 8);
        page_number=hextodec(pg_no);
        minute = (unhamtab[i_stream.read()] & 0x0f) | 
            ((unhamtab[i_stream.read()] & 0x07) << 4);
        hour = (unhamtab[i_stream.read()] & 0x0f) | 
            ((unhamtab[i_stream.read()] & 0x03) << 4);
        dummy = i_stream.read();
        charset = ((unhamtab[i_stream.read()] & 0x0e) >> 1);
        i = 0;
        while (i < 8) {
            if ((i>3) && (i<7)) {
                letter[i]=(byte) '-';
                color[i]=(byte) 2;
            }
            else {
                letter[i]=(byte) ' ';
                color[i]=(byte) 7;
            }
            i++;
        }
        // read the remaining teletext data
        while ((c=i_stream.read())>=0) {
            if ((i % 40) == 0){
                // begin new line -> reset attributes
                graphics = false;
                grhold = false;
                sep_graphics = false;
                conceal = false;
                flash = false;
                double_height = false;
                last_letter = (byte) ' ';
                last_color = (byte) 7;
                new_color = (byte) 7;
            }
            if (((i % 40) == 0) && (copy_line)) {
                // double height -> forget next line
                i_stream.skip((long)39);
                for (j=0; j<40; j++) {
                    color[i]=color[i-40];
                    if ((attrib[i-40] & 0x03) > 0) {
                        letter[i]=letter[i-40];
                        attrib[i]=(byte) ((attrib[i-40] & 0xfc) | 0x02);
                    }
                    else {
                        letter[i]=(byte) ' ';
                    }
                    i++;
                }
                copy_line=false;
            }
            else {
                // check parity
                parity=right_parity[c];
                // strip parity bit
                c = (c & 0x7f);
                // set actual attributes
                color[i]=last_color;
                attrib[i]=0;
                if (double_height) {
                    attrib[i] = (byte) (attrib[i] | 0x01);
                }
                if (sep_graphics) {
                    attrib[i] = (byte) (attrib[i] | 0x04);
                }
                if (conceal) {
                    attrib[i] = (byte) (attrib[i] | 0x08);
                }
                if (flash) {
                    attrib[i] = (byte) (attrib[i] | 0x10);
                }
                // decode read byte
                if (!parity) {
                    letter[i] = (byte) 254;
                } 
                else if ((c >= 32) && (c <= 127)) {
                    if (!graphics || ((c >= 64) && (c <= 95))) {
                        letter[i] = cct2vtx_table[charset][c - 32];
                    } else {
                        letter[i] = (byte) 
                            (c + ((c >= 96) ? 64 : 96));
                    }
                }
                else {
                    letter[i] = ((grhold && graphics ) ? 
                                 last_letter : (byte) ' ');
                    if (c <= 7) {
                        // Set alphanumerics-color
                        graphics = false;
                        new_color  = (byte) ((last_color & 0xf0) | c) ;
                        conceal = false;
                    }
                    
                    else if (c == 8) {
                        // Flashing text on
                        flash = true;
                    }
                    else if (c == 9) {
                        // Flashing text off
                        flash = false;
                    }
                    else if (c == 12) {
                        // Set normal height
                        double_height = false;
                    }
                    else if (c == 13) {
                        // Set double height
                        double_height = true;
                        copy_line = true;
                    }
                    else if ((c >= 16) && (c <= 23)) {
                        // Set graphics-color
                        graphics = true;
                        new_color  = (byte) ((last_color & 0xf0) | (c - 16)) ;
                        conceal = false;
                    }
                    else if (c == 24) {
                        // Conceal display
                        conceal = true;
                    }
                    else if (c == 25) {
                        // Contiguous graphics
                        sep_graphics = false;
                    }
                    else if (c == 26) {
                        // Separated graphics 
                        sep_graphics = true;
                        attrib[i] = (byte) (attrib[i] | 0x04);
                    }
                    else if (c == 28) {
                        // Black background
                        new_color = (byte) (last_color & 0x0f);
                        color[i] = new_color;
                    }
                    else if (c == 29) {
                        // Set background
                        new_color = (byte) ((last_color &  0x0f) |
                                            ((last_color & 0x0f) << 4));
                        color[i] = new_color;
                    }
                    else if (c == 30) {
                        // Hold graphics
                        grhold = true;
                        if (graphics)
                            letter[i]=last_letter;
                    }
                    else if (c == 31) {
                        // Release graphics
                        grhold = false;
                    }
                
                }
                last_letter = letter[i];
                last_color = new_color;

                i++;
            }
        }
        // build hyperlinks
        detectLinks();
        correctPageNumber();
        detectSubpage();
        // reset reveal flag
        reveal = false;
        // build command line
        for (i=960; i<1000; i++) {
            // letter
            letter[i]=(byte) last_line.charAt(i-960);
            // attributes
            attrib[i]=0;
            // color
            if (i==960) { //black
                color[i]=(byte) 0x00;
            }
            else if (i<971) { // green
                color[i]=(byte) 0x20;
            }
            else if (i<981) { // red
                color[i]=(byte) 0x10;
            }
            else if (i<991) { // yellow
                color[i]=(byte) 0x30;
            }
            else { // cyan
                color[i]=(byte) 0x60;
            }
            // links
            if ((i>=961) && (i<=963)) {
                link_to[i]=10;
            }
            else if ((i>=968) && (i<=970)) {
                link_to[i]=11;
            }
            else if ((i>=971) && (i<=973)) {
                link_to[i]=12;
            }
            else if ((i>=978) && (i<=980)) {
                link_to[i]=13;
            }
            else if ((i>=983) && (i<=989)) {
                link_to[i]=14;
            }
            else if ((i>=994) && (i<=997)) {
                link_to[i]=100;
            }
        }
        // build/resume flash thread
        if (!flash_thread.isAlive()) {
            flash_thread.start();
        }
        else {
            flash_thread.resume();
        }
    }

    /**
     * Load the first available subpage of a specified page.
     * If there is no such subpage, try to load one of the next ten subpages. 
     * @param page the page to be loaded
     * @return false if there is no matching subpage.
     */
    public boolean loadFirst(int page) {
        int i = 0;
        boolean success = false;
        
        while ((!success) && (i<10)) {
            try {
                load(buildPageURL(page, i));
                history.push(page_number*100+i);
                success=true;
            }
            catch (IOException ex) {
                i++;
            }
        }
        if (!success) {
            applet.showStatus("page "+page+" not found");
        }
        return success;
    }

    /**
     * Load the next subpage.
     * If this fails, try to load one of the next ten subpages.
     * @return false if there is no matching subpage.
     */
    public boolean loadNext() {
        int i = 0;
        int sub;
        boolean success = false;
        
        while ((!success) && (i <= 10)) {
            try {
                sub = ((subpage_number + i) % max_subpage_number) + 1;
                load(buildPageURL(page_number, sub));
                history.push(page_number*100+sub);
                success=true;
            }
            catch (IOException ex) {
                i++;
            }
        }
        if (!success) {
            applet.showStatus("next subpage not found");
        }
        return success;
    }
    
    /**
     * Load the next subpage.
     * If this fails, try to load one of the previous ten subpages.
     * @return false if there is no matching subpage.
     */
    public boolean loadPrevious() {
        int i = 0;
        int sub;
        boolean success = false;
        
        while ((!success) && (i <= 10)) {
            try {
                sub = ((subpage_number + max_subpage_number - i - 2) % 
                       max_subpage_number) + 1;
                load(buildPageURL(page_number, sub));
                history.push(page_number*100+sub);
                success=true;
            }
            catch (IOException ex) {
                i++;
            }
        }
        if (!success) {
            applet.showStatus("previous subpage not found");
        }
        return success;
    }
    
    /**
     * Load a page from history.
     * As the history list saves only page and subpage, this method may
     * load a newer version of that page if that page has changed on disk.
     * @return false if the page could not be found or there are no more
     *         entries in the history list.
     */
    public boolean loadFromHistory(int i) {
        int page;
        try {
            if (i == 1) {
                page = history.forward();
            }
            else {
                page = history.back();
            }
            load(buildPageURL(page / 100, page % 100));
            return true;
        }
        catch (IOException ex) {
            applet.showStatus("(sub)page not found");
            return false;
        }
        catch (NoSuchElementException ex) {
            applet.showStatus("no more entries in history");
            return false;
        }
    }

    /**
     * Tries to detect links in the page.
     * This allows surfing through the pages. A Link is a number between
     * 100 and 999 and enclosed in delimiters, that is a space, a slash,
     * a hyphen (and a few more) or the left or right border.
     */
    public void detectLinks() {
        int i;
        int status=0;
        boolean success = false;
        int link;
        char buffer[] = new char[3];
        
        for (i=0; i < 960; i++) {
            link_to[i]=0;
            if ((i % 40) == 0) {
                if (status==4) {
                    success = true;
                }
                status=1;
            }
            if ((vtx_separators.indexOf(letter[i])) >= 0) {
                if (status==4) {
                    success = true;
                }
                status=1;
            }
            else if ((letter[i]>=(byte)'0') && (letter[i]<=(byte)'9')) {
                if ((status==1) && (letter[i]!=(byte)'0')) {
                    buffer[0]=(char)letter[i];
                    status++;
                } 
                else if ((status==2) || (status==3)){
                    buffer[status-1]=(char)letter[i];
                    status++;
                }
                else {
                    status=0;
                }
            }
            else {
                status=0;
            }
            if (success) {
                    link=(buffer[0]-'0')*100
                        +(buffer[1]-'0')*10
                        +(buffer[2]-'0');
                    link_to[i-3]=link;
                    link_to[i-2]=link;
                    link_to[i-1]=link;
                    success=false;
            }
        }
        if (status==4) {
            link=(buffer[0]-'0')*100
                +(buffer[1]-'0')*10
                +(buffer[2]-'0');
            link_to[957]=link;
            link_to[958]=link;
            link_to[959]=link;
        }
    }

    /**
     * Tries to find out the correct page number.
     * As noted several times, the page number from the vtx file header is
     * a bit unreliable. In load(), we could decode the ones and tens from
     * the actual vtx content; with this information and the knowledge that
     * most broadcasters put the actual page number into the first line of
     * the page, we should be able to find out the real magazine number
     * (i.e. the hundreds of the page number) and get the correct page
     * number.
     */
    public void correctPageNumber() {
        int i;
        int new_number;

        i=7; new_number=0;
        while ((i<40) && (new_number==0)) {
            if ((link_to[i]>=100) && (link_to[i]<=899) &&
                ((page_number % 100)==(link_to[i] % 100))) {
                new_number=link_to[i];
            }
            i++;
        }
        if (new_number>0) {
            page_number=new_number;
        }
        // now eliminate the links in the first line        
        for (i=0; i<40; i++) {
            link_to[i]=0;
        }
    }

                    
    /**
     * Finds out if this page has subpages.
     * This method does even more magic. It tries to find something like
     * x/y in the text, where x and y are between 1 and 99 and y &gt; x.
     * It then tries to match x with the subpage number given in the header 
     * of the vtx-file. If all these checks succeed, the x area gets a 
     * link to the previous subpage, the y area gets a link to the next
     * subpage. A &gt;&gt; found in the last line will also point to the
     * next subpage.
     */
    public void detectSubpage() {
        int i;
        int status = 0; 
        boolean success = false;
        byte subpage[] = new byte[2];
        byte maxsubpage[] = new byte[2];

        subpage[0]=hex((minute>>4) & 0xf);
        subpage[1]=hex(minute & 0xf);
        if ((subpage[0]>=(byte) '0') && (subpage[0]<=(byte) '9') &&
            (subpage[1]>=(byte) '0') && (subpage[1]<=(byte) '9')) {
            subpage_number=((char)subpage[0]-'0')*10+((char)subpage[1]-'0');
        }
        else
            return;
        i=0;
        while ((!success) && (i<956)) {
            if ((i % 40 == 0) || (letter[i-1]==(byte) ' ')) {
                if ((subpage[0]==(byte)'0') && 
                    (letter[i]==subpage[1]) &&
                    (letter[i+1]=='/') &&
                    (letter[i+2]>=(byte)'0') &&
                    (letter[i+2]<=(byte)'9')) {
                    if (((i+3) % 40 == 0) || (letter[i+3]<=(byte)' ')) {
                        maxsubpage[0]=(byte)'0';
                        maxsubpage[1]=letter[i+2];
                        link_to[i] = -1;
                        link_to[i+2] = 1;
                        success=true;
                    }
                    else if ((letter[i+3]>=(byte)'0') &&
                             (letter[i+3]<=(byte)'9') &&
                             (((i+4) % 40 == 0) || letter[i+4]<=(byte)' ')) {
                        maxsubpage[0]=letter[i+2];
                        maxsubpage[1]=letter[i+3];
                        link_to[i] = -1;
                        link_to[i+2] = 1;
                        link_to[i+3] = 1;
                        success=true;
                    }
                    else {
                        i = i+3;
                    }
                }
                else if ((letter[i]==subpage[0]) && 
                         (letter[i+1]==subpage[1]) &&
                         (letter[i+2]=='/') &&
                         (letter[i+3]>=(byte)'0') &&
                         (letter[i+3]<=(byte)'9') &&
                         (letter[i+4]>=(byte)'0') &&
                         (letter[i+4]<=(byte)'9') &&
                         (((i+5) % 40 == 0) || letter[i+5]<=(byte)' ')) {
                    maxsubpage[0]=letter[i+3];
                    maxsubpage[1]=letter[i+4];
                    link_to[i] = -1;
                    link_to[i+1] = -1;
                    link_to[i+3] = 1;
                    link_to[i+4] = 1;
                    success=true;
                }
                else {
                    i++;
                }
            }
            else {
                i++;
            }
        }
        if (success) {
            max_subpage_number=
                ((char)maxsubpage[0]-'0')*10+((char)maxsubpage[1]-'0');
            i = 959;
            while ((i>940) && !((letter[i-1]=='>') && (letter[i]=='>'))) {
                i--;
            }
            if (i>940) {
                link_to[i-1]=1;
                link_to[i]=1;
            }
            //System.out.println("sub: "+subpage_number+", max: "
            //                   +max_subpage_number);
        }
        else {
            max_subpage_number = 0;
        }
    }

    /**
     * Switches between reveal and conceal.
     * There may be some words in the vtx-page that are concealed.
     * (This is often used to conceal the answer of a quiz.) This
     * method toggles between a revealed and a concealed state of
     * these words.
     */
    public void revealConceal() {
        String message;
        Graphics g;
        int i;

        reveal = (!reveal);
        if (reveal) {
            message="Conceal";
            applet.showStatus("conceal hidden text");
        }
        else {
            message="Reveal ";
            applet.showStatus("reveal hidden text");
       }
        g = this.getGraphics();
        for (i = 983; i < 990; i++) {
                letter[i]=(byte) message.charAt(i-983);
        }
        if (g==null) {
            return;
        }
        for (i = 0; i < 1000; i++) {
            if (((attrib[i] & 0x08) == 0x08) || 
                ((i >= 983) && (i < 990))) {
                paintchar(g, i);
            }
        }            
    }

    /**
     * Does the flashing.
     * This method toggles the flashing words on and off. This method
     * is called regularly by the JVtxFlash thread.
     */
    public void paintFlashing() {
        Graphics g;
        int i;

        vis_flash = !vis_flash;
        g = this.getGraphics();
        if (g==null) {
            return;
        }
        for (i = 0; i < 1000; i++) {
            if ((attrib[i] & 0x10) == 0x10) {
                paintchar(g, i);
            }
        }            
    }
   
    /**
     * Paints one character on screen.
     * @param g the current graphics context
     * @param i the character's location in the page array
     */
    private void paintchar(Graphics g, int i) {
        boolean hide;

        hide=(
              (((attrib[i] & 0x08) == 0x08) && (!reveal)) ||
              (((attrib[i] & 0x10) == 0x10) && (!vis_flash)));
        vtx_font.paintChar(g, 
                              (byte) (color[i] & 0x0f), 
                              (byte) ((color[i] & 0xf0) >> 4), 
                              i % 40, 
                              i / 40, 
                              letter[i],
                              attrib[i],
                              (!hide));
    }

    /**
     * Paint the entire screen.
     * It does this by calling paintchar for every character on the page.
     * @param g the current graphics context
     */
    public void paint(Graphics g) {
        int i, j;
        int fg, bg;
        
        for (i = 0; i < 1000; i++) { 
            paintchar(g, i);         
        }
    }

    /**
     * The mouseDown callback.
     * This method gets called when pressing a mouse button.
     * It should be replaced by the Java 1.1 method mouseClicked
     * as soon as the browsers support this.
     * @param e the event as delivered by the AWT
     * @param x the x position of the mouseclick
     * @param y the y position of the mouseclick
     * @return true. Always.
     */ 
    //public void mouseClicked(MouseEvent e) {
    public boolean mouseDown(Event e, int x, int y) {
        int i;
        Point p;
        boolean success = false;
        Graphics g;

        //p=vt_font.getPosition(e.getPoint());
        p=vtx_font.getPosition(new Point(x, y));
        if ((p.x>39) || (p.x<0) || (p.y>24) || (p.y<0)) {
            return true;
        }
        if (link_to[p.y*40+p.x]==0) {
            return true;
        }
        
        if (link_to[p.y*40+p.x] == -1) {
            success = loadPrevious();
        }
        else if (link_to[p.y*40+p.x] == 1) {
            success = loadNext();
        }
        else if (link_to[p.y*40+p.x] == 10) {
            success = loadFromHistory(-1);
        }
        else if (link_to[p.y*40+p.x] == 11) {
            success = loadFromHistory(1);
        }
        else if (link_to[p.y*40+p.x] == 12) {
            ((JVtxView) applet).previousChannel();
            history.init();
            success = loadFirst(100);
        }
        else if (link_to[p.y*40+p.x] == 13) {
            ((JVtxView) applet).nextChannel();
            history.init();
            success = loadFirst(100);
        }
        else if (link_to[p.y*40+p.x] == 14) {
            revealConceal();
            success = false; // no repaint
        }
        else if (link_to[p.y*40+p.x] >= 100) {
            success = loadFirst(link_to[p.y*40+p.x]);
        }
        else {
            return true;
        }

        if (success){
            current_link=-1;
            g=this.getGraphics();
            paint(g);
        }
        return true;
    }

    /**
     * The mouseEntered callback.
     * This method requests the keyboard focus. This *may* cause problems
     * with MS Windows (never tested...), as they have another keyboard
     * policy.
     * @param e the event as delivered by the AWT
     * @param x the x position where the mouse has entered.
     * @param y the y position where the mouse has entered.
     * @return true. Always.
     */
    //public void mouseEntered(MouseEvent e) {
    public boolean mouseEnter(Event e, int x, int y) {
        this.requestFocus();
        return true;
    }

    //public void mouseExited(MouseEvent e) {
    //}

    //public void mousePressed(MouseEvent e) {
    //}

    //public void mouseReleased(MouseEvent e) {
    //}

    //public void mouseDragged(MouseEvent e) {
    //}
    
    /**
     * Mouse moved callback.
     * @param e the event as delivered by the AWT
     * @param x the x position of the mouse.
     * @param y the y position of the mouse.
     * @return true. Always.
     */
    //public void mouseMoved(MouseEvent e) {
    public boolean mouseMove(Event e, int x, int y) {
        int new_link;
        Point p;
        
        p=vtx_font.getPosition(new Point(x, y));
        if ((p.x>39) || (p.x<0) || (p.y>24) || (p.y<0)) {
            return true;
        }
        new_link=link_to[p.y*40+p.x];
    //    if (new_link != current_link) {
    //        current_link = new_link;
    //        if (new_link == 0) {
    //            this.setCursor(normal_cursor);
    //        }
    //        else {
    //            this.setCursor(link_cursor);
    //        }
    //    }
        if (new_link == 0) {
            applet.showStatus("");
        }
        else if (new_link == -1) {
            applet.showStatus("go to previous subpage");
        }
        else if (new_link == 1) {
            applet.showStatus("go to next subpage");
        }
        else if (new_link == 10) {
            applet.showStatus("go back in history");
        }
        else if (new_link == 11) {
            applet.showStatus("go forward in history");
        }
        else if (new_link == 12) {
            applet.showStatus("switch to previous channel");
        }
        else if (new_link == 13) {
            applet.showStatus("switch to next channel");
        }
        else if (new_link == 14) {
            if (reveal) {
                applet.showStatus("conceal hidden text");
            }
            else {
                applet.showStatus("reveal hidden text");
            }
        }
        else if (new_link == 99) {
            applet.showStatus("not yet implemented");
        }
        else if ((new_link >= 100) && (new_link <= 999)) {
            applet.showStatus("go to page "+new_link);
        }
        return true;
    }

    /**
     * Key typed callback.
     * @param e the event as delivered by the AWT
     * @param key the typed key
     * @return true. Always.
     */
    //public void keyTyped(KeyEvent e) {
    public boolean keyDown(Event e, int key) {
        int page;
        boolean success = false;
        char c;
        Graphics g;

        //c = e.getKeyChar();
        c = (char) key;
        if ((c>='0') && (c<='9')) {
            if (no_typed==2) {
                page=(((typed[0]-'0')*100)+
                      ((typed[1]-'0')*10)+
                      (c-'0'));
                no_typed=0;
                letter[4]=(byte) '-';
                letter[5]=(byte) '-';
                success = loadFirst(page);
                if (!success) {
                    //System.out.println("page "+page+" not found");
                    applet.showStatus("page "+page+" not found");
                    g = this.getGraphics();
                    if (g != null) {
                        paintchar(g, 4);
                        paintchar(g, 5);
                    }
                }           
                else {
                    this.repaint();
                }
            }
            else {
                typed[no_typed]=c;
                letter[4+no_typed]=(byte) c;
                g = this.getGraphics();
                if (g != null) {
                    paintchar(g, 4+no_typed);
                }           
                no_typed++;
            }
        }
        return true;
    }

    //public void keyPressed(KeyEvent e) {
    //}

    //public void keyReleased(KeyEvent e) {
    //}
}
        


