import java.applet.Applet;
import java.awt.*;
import java.io.*;
import java.net.*;

public class SkrivDok extends Applet implements Runnable
{
 volatile Thread genThread;
 InputStream dok;
 FontMetrics metrics;
 Font        defFont      = new Font("Courier", Font.PLAIN, 11);
 URL         linkURL;
 URL         dokURL;
 Color       textColor    = Color.white;
 String      sDokURL      = "SkrivDok.txt";
 String      sContents;
 char[]      cContents;
 int         lettersWrote = 0;
 int         charWidth;
 int         hiLight;
 boolean     mouseOver    = false;
 boolean     fileFound    = false;

 public void init()
 {
  String param;
  param = getParameter("Fil");
  if(param != null)
  {sDokURL = param;}
  getGraphics().setFont(defFont);
  metrics = getGraphics().getFontMetrics();
  charWidth = metrics.stringWidth("n");
 }

 public void start()
 {
  sContents        = "Fel! :o(";
  int  dokSize;
  char invSign[]   = {'?', '?'};
  boolean inTag    = false;

  try
  {
   dokURL = new URL(getDocumentBase(), sDokURL);
   dok    = dokURL.openStream();
   fileFound = true;
  }
  catch(Exception e)
  {
   sContents = e.toString();
  }

  if(fileFound)
  {
   try
   {
    dokSize = dok.available();
   }
   catch(Exception e)
   {
    return;
   }

   cContents = new char[dokSize];

   for(int i = 0; i < dokSize; i++)
   {
    try
    {
     cContents[i] = (char)(dok.read());
     if(cContents[i] == '\n' || cContents[i] == '\r')
     {
      if(i > 0)
      {
       i -= 1;
       dokSize -= 1;
      }
      else
      {
       cContents[i] = ' ';
      }
     }
     else if(cContents[i] == '\t')
     {cContents[i] = ' ';}
     else if(cContents[i] == '>')
     {inTag = false;}
     else if(!inTag)
     {
      if(cContents[i] == '<')
      {inTag = true;}
      else if(i > 0 && cContents[i - 1] == '/' && cContents[i] == '/')
      {
       i -= 2;
       dokSize -= 2;
       while(invSign[0] != '\n')
       {
        invSign[0] = (char)(dok.read());
        dokSize -= 1;
       }
       invSign[0] = '?';
      }
      else if(i > 0 && cContents[i - 1] == '/' && cContents[i] == '*')
      {
       i -= 2;
       dokSize -= 2;
       while(invSign[1] != '*' || invSign[0] != '/')
       {
        invSign[1] = invSign[0];
        invSign[0] = (char)(dok.read());
        dokSize -= 1;
       }
       invSign[0] = '?';
      }
     }
    }
    catch(Exception e)
    {
     return;
    }
   }
   sContents = new String(cContents);
   try
   {
    dok.close();
   }
   catch(Exception e) {}

   // Söker upp kommandon

   String foundValue;
   int    beginPoint = 0;
   int    endPoint   = 0;

   String red;
   String green;
   String blue;
   int    comma;
   int    lastComma;

   for(int i = 0; i < 10000 && beginPoint != -1 && endPoint != -1; i++)
   { // i ser bara till att förhindra en evig loop, ifall en sådan skulle kunna inträffa

    beginPoint = sContents.indexOf("<", 0);
    if(beginPoint != -1)
    {
     endPoint = sContents.indexOf(">", beginPoint);
     if(endPoint != -1)
     {
      // Leta efter en URL i formatet <URL: http://www... >

      if(beginPoint + 5 < sContents.length() && linkURL == null
       && sContents.substring(beginPoint+1, beginPoint+5).toUpperCase().equals("URL:"))
      {
       try
       {
        foundValue = sContents.substring(beginPoint + 5, endPoint);
        linkURL = new URL(getDocumentBase(), foundValue);
       }
       catch(Exception e)
       {
        linkURL = null;
       }
      }
      // Leta efter en färg i formatet <FÄRG: #rrggbb>

       if(beginPoint + 6 < sContents.length()
       && sContents.substring(beginPoint+1, beginPoint+6).toUpperCase().equals("FÄRG:"))
      {
       foundValue = sContents.substring(beginPoint + 6, endPoint);
       while(true)
       {
        if(foundValue.charAt(0) == ' ')
        {foundValue = foundValue.substring(1, foundValue.length());}
        else
        {
         if(foundValue.charAt(foundValue.length() - 1) == ' ')
         {foundValue = foundValue.substring(0, foundValue.length() - 1);}
         else
         {break;}
        }
       }
       if(foundValue.charAt(0) == '#' && foundValue.length() == 7)
       {
        textColor = new Color(Integer.parseInt(foundValue.substring(1, 7), 16));
       }
       else if(foundValue.length() == 6)
       {
        textColor = new Color(Integer.parseInt(foundValue, 16));
       }
      }
      sContents  = sContents.substring(0, beginPoint) + sContents.substring(endPoint + 1, sContents.length());
     }
    }
   }
  }

  setBackground(Color.black);

  if(genThread == null)
  {
   genThread = new Thread(this);
   genThread.start();
  }
 }

 public void run()
 {
  while(true)
  {
   if(lettersWrote < sContents.length())
   {
    lettersWrote++;
   }
   repaint();

   try
   {
    Thread.sleep(100);
   }
   catch(InterruptedException e)
   {
    return;
   }
  }
 }

 public void update(Graphics g)
 {
  paint(g);
 }

 public void paint(Graphics g)
 {
  Image bgImg = createImage(size().width, size().height);
  Graphics bg = bgImg.getGraphics();

  bg.setFont(defFont);
  for(int i = 0; i < lettersWrote; i++)
  {
   if(!mouseOver || i < hiLight - 20 || i > hiLight + 20)
   {
    bg.setColor(textColor);
   }
   else if(i < hiLight)
   {
    bg.setColor(Colors.mix(textColor, Color.white, (hiLight-i)*5));
   }
   else if(i > hiLight)
   {
    bg.setColor(Colors.mix(textColor, Color.white, (i-hiLight)*5));
   }
   else
   {
    bg.setColor(Color.white);
   }
   bg.drawString(sContents.substring(i, i+1), 5 + i*charWidth, 20);
  }
  g.drawImage(bgImg, 0, 0, this);
 }

 public boolean mouseUp(Event evt, int x, int y)
 {
  if(linkURL != null)
  {
   getAppletContext().showDocument(linkURL);
   return true;
  }
  return false;
 }

 public boolean mouseMove(Event evt, int x, int y)
 {
  mouseOver = true;
  hiLight = (x - 5)/charWidth;
  return false;
 }

 public boolean mouseExit(Event evt, int x, int y)
 {
  mouseOver = false;
  return false;
 }

 public void stop()
 {
  if(genThread != null)
  {
   genThread.interrupt();
  }
 }

 public void destroy()
 {
  if(genThread != null)
  {
   genThread = null;
  }
 }

}