import java.awt.Graphics;
import java.awt.Color;
import java.awt.Font;
import java.awt.Event;
import java.net.URL;

public class SnurrandeText extends java.applet.Applet implements Runnable
{
 final double varv         = Math.PI * 2;
 Thread       genThread;
 Font         smallFont    = new Font("TimesRoman", Font.PLAIN, 10);
 Font         defFont      = new Font("TimesRoman", Font.BOLD,  18);
 Color        bgColor      = new Color(0xCC, 0xCC, 0xCC);
 String       Message      = "Johan & Daniel";
 String[]     MsgLetter    = new String[50];
 int[]        letterX      = new int[50];
 int[]        letterY      = new int[50];
 int[]        letterRadie  = new int[50];
 int          delay        = 250;
 int          MsgLength    = 50;
 int          MaxWidth     = 200;
 int          MinWidth     = 30;
 int          fgRed        = 255;
 int          fgGreen      = 255;
 int          fgBlue       = 255;
 int          sgRed        = 0;
 int          sgGreen      = 0;
 int          sgBlue       = 0;
 int          mittX;
 int          mittY;
 double[]     Radianer     = new double[50];
 boolean[]    okandeRadie  = new boolean[50];
 boolean      moveClockwise   = true;
 boolean      scrambleALittle = false;
 boolean      bouncheAway     = false;

 int          mouseX          = 0;
 int          mouseY          = 0;
 boolean      mouseOverApplet = false;
 boolean      mouseOverAuthor = false;
 boolean      appletIsLink    = false;
 URL          linkURL;
 String       linkString;

 public void init()
 {
  String param;
  char[]   MsgChar   = new char[50];
  char[][] MsgCharAr = new char[50][1];
  param = getParameter("Message");
  if(param != null)
  {Message = param;}
  param = getParameter("Delay");
  if(param != null)
  {delay = Integer.parseInt(param);}
  param = getParameter("MaxWidth");
  if(param != null)
  {MaxWidth = Integer.parseInt(param);}
  param = getParameter("MinWidth");
  if(param != null && Integer.parseInt(param) > 3)
  {MinWidth = Integer.parseInt(param);}
  param = getParameter("Color1");
  if(param != null)
  {
   fgRed   = Integer.parseInt(param.substring(1, 3), 16);
   fgGreen = Integer.parseInt(param.substring(3, 5), 16);
   fgBlue  = Integer.parseInt(param.substring(5, 7), 16);
  }
  param = getParameter("Color2");
  if(param != null)
  {
   sgRed   = Integer.parseInt(param.substring(1, 3), 16);
   sgGreen = Integer.parseInt(param.substring(3, 5), 16);
   sgBlue  = Integer.parseInt(param.substring(5, 7), 16);
  }
  param = getParameter("BgColor");
  if(param != null)
  {bgColor = new Color(Integer.parseInt(param.substring(1, 7), 16));}
  param = getParameter("URL");
  if(param != null)
  {
   try
   {
    linkString   = toUrlString(param);
    linkURL      = new URL(param);
    appletIsLink = true;
   }
   catch(java.net.MalformedURLException e)
   {
    showStatus("Malformed link URL");
   }
  }
  param = getParameter("Misc");
  if(param != null && param.length() == 3)
  {
   switch(param.charAt(0))
   {
    case 'y':
    case '0': moveClockwise = false; break;
    default:  moveClockwise = true;
   }
   switch(param.charAt(1))
   {
    case 'y':
    case '0': scrambleALittle = false; break;
    default:  scrambleALittle = true;
   }
   switch(param.charAt(2))
   {
    case 'y':
    case '0': bouncheAway = false; break;
    default:  bouncheAway = true;
   }
  }

  mittX  = Math.round(size().width  / 2);
  mittY  = Math.round(size().height / 2);
  mouseX = mittX;
  mouseY = mittY;

  MsgLength = Message.length();
  MsgChar   = ToChars(Message);
  for(byte i = 0; i < 50; i++)
  {
   MsgCharAr[i][0] = MsgChar[i];
   MsgLetter[i]    = new String(MsgCharAr[i]);
   letterRadie[i]  = MaxWidth / 2 - i;
   Radianer[i]     = varv - varv * i / 45;
   okandeRadie[i]  = true;
  }
  MaxWidth = Math.max(MaxWidth, MinWidth);
 }

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

 public void run()
 {
  while(true)
  {
   for(byte i = 0; i < 50; i++)
   {
    if(scrambleALittle)
    {
     letterRadie[i] += (int)(Math.round((Math.random() - 0.5)* 2));
    }
    if((letterRadie[i] > MaxWidth / 2)||(bouncheAway
       &&(letterX[i] + mittX < 1 || letterX[i] + mittX > size().width - 15
        || letterY[i] + mittY < 18 || letterY[i] + mittY > size().height)))
    {okandeRadie[i] = false;}
    if(letterRadie[i] < MinWidth / 2)
    {okandeRadie[i] = true;}
    if(okandeRadie[i])
    {letterRadie[i] += 1;}
    else
    {letterRadie[i] -= 1;}
    Radianer[i] = Radianer[i] % varv + varv / letterRadie[i];
   }

   if(mittX < mouseX)
   {mittX += 1;}
   if(mittX > mouseX)
   {mittX -= 1;}
   if(mittY < mouseY)
   {mittY += 3;}
   if(mittY > mouseY)
   {mittY -= 3;}

   setCoords();
   repaint();

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

 public void paint(Graphics g)
 {
  setBackground(bgColor);
  g.clearRect(0, 0, size().width, size().height);

  if(mouseOverApplet)
  {
   g.setFont(smallFont);
   if(mouseOverAuthor)
   {
    g.setColor(new Color(sgRed, sgGreen, sgBlue));
    g.drawString("Author:", 5, 12);
    g.setColor(new Color(fgRed, fgGreen, fgBlue));
    g.drawString("Daniel",  5, 22);
    g.drawString("Ramsköld",5, 34);
   }
   if(appletIsLink)
   {
    if(mouseOverAuthor)
    {
     g.setColor(new Color(sgRed, sgGreen, sgBlue));
     g.drawString("Click to go to Authors Homepage", 5, size().height - 5);
    }
    else
    {
     g.setColor(new Color(fgRed, fgGreen, fgBlue));
     g.drawString("Click to go to " + linkString, 5, size().height - 5);
    }
   }
  }
  g.setFont(defFont);
  for(int i = MsgLength - 1; i >= 0; i--)
  {
   if(MsgLength > 1)
   {
    g.setColor(new Color
      (Math.round(fgRed  /(MsgLength-1)*(MsgLength-1-i)+sgRed  /(MsgLength-1)*i),
       Math.round(fgGreen/(MsgLength-1)*(MsgLength-1-i)+sgGreen/(MsgLength-1)*i),
       Math.round(fgBlue /(MsgLength-1)*(MsgLength-1-i)+sgBlue /(MsgLength-1)*i)));
   }
   else
   {g.setColor(new Color(fgRed, fgGreen, fgBlue));}
   g.drawString(MsgLetter[i], letterX[i]+mittX, letterY[i]+mittY);
  }
 }

 public char[] ToChars(String MsgString)
 {
  char[] returnArray = new char[50];
  for(byte i = 0; i < 50 && i < MsgString.length(); i++)
  {
   returnArray[i] = MsgString.charAt(i);
  }
  return returnArray;
 }

 public void setCoords()
 {
  for(int i = MsgLength - 1; i >= 0; i--)
  {
   if(moveClockwise)
   {
    letterX[i] = (int)(Math.round(Math.sin(varv/2-Radianer[i])*letterRadie[i]));
    letterY[i] = (int)(Math.round(Math.cos(varv/2-Radianer[i])*letterRadie[i]));
   }
   else
   {
    letterX[i] = (int)(Math.round(Math.sin(Radianer[i])*letterRadie[i]));
    letterY[i] = (int)(Math.round(Math.cos(Radianer[i])*letterRadie[i]));
   }
  }
 }

 public String toUrlString(String urlString)
 {
  String docBase = getDocumentBase().toString();
  if(urlString.indexOf(":", 0) == -1)
  {
   urlString = "http://" + urlString;
  }
  return urlString;
 }

 public boolean mouseMove(Event evt, int x, int y)
 {
  mouseOverAuthor = (x < 50 && y < 34);
  mouseOverApplet = true;
  mouseX          = x;
  mouseY          = y;
  return true;
 }

 public boolean mouseExit(Event evt, int x, int y)
 {
  mouseOverApplet = false;
  mouseX          = Math.round(size().width  / 2);
  mouseY          = Math.round(size().height / 2);
  return true;
 }

 public boolean mouseUp(Event evt, int x, int y)
 {
  if(x < 50 && y < 34)
  {
   try
   {
    getAppletContext().showDocument(new URL("http://www.geocities.com/ramskold/"));
   }
   catch(java.net.MalformedURLException e)
   {
    showStatus("Malformed URL");
   }
  }
  else
  {
   if(appletIsLink)
   {
    getAppletContext().showDocument(linkURL);
   }
  }
  return true;
 }

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

}