/*
 * ProScroll 2.3
 * By Slava Pestov
 *
 * You can do whatever you want with this file, as long as this notice
 * is left intact and credit is given to the original author.
 */

import java.applet.Applet;
import java.net.URL;
import java.net.URLConnection;
import java.io.InputStream;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Event;
import java.awt.MediaTracker;
import java.util.Enumeration;
import java.util.Vector;
import java.util.StringTokenizer;

public class ProScroll extends Applet implements Runnable
{
        // Instance variables
        private Thread    thread;
        private Image     image;
        private int       scrollLength,
                          scrolled,
                          speed = 10,
                          imgsWidth;
        private URL       url;
        private String    target;
        private Color     bgColor;

        // Initialize the applet
        public void init()
        {
                Enumeration images;
                String fontName;
                int fontSize = 12, fontStyle = 0;

                String text = getParameter("TEXT");
                String textURL = getParameter("TEXTURL");
                
                if(text == null && textURL == null)
                        text = "No TEXT or TEXTURL parameter specified";
                
                if(textURL != null)
                {
                        StringBuffer buf = new StringBuffer();
                        
                        try
                        {
                                InputStream in = new URL(textURL)
                                        .openConnection().getInputStream();
                                
                                for(;;)
                                {
                                        int i = in.read();
                                        if(i == -1) break;
                                        else if(i == '\n') continue;
                                        else if(i == '\t') buf.append(' ');
                                        else buf.append((char)i);
                                }
                                
                                in.close();
                                
                                text = buf.toString();
                        }
                        catch(Exception ex)
                        {
                                if(text == null)
                                        text = "Error loading text from URL: " + ex;
                        }
                }

                fontName = getParameter("FONT");
                if(fontName == null) fontName = "TimesRoman";

                target = getParameter("TARGET");
                if(target == null) target = "_self";

                try
                {
                        fontSize = Integer.parseInt(getParameter("SIZE"));
                }
                catch(Exception e)
                {
                }

                String fontStyleStr = getParameter("STYLE");
                if("bold".equals(fontStyleStr)) fontStyle = 1;
                else if("italic".equals(fontStyleStr)) fontStyle = 2;
                else if("bolditalic".equals(fontStyleStr)) fontStyle = 3;

                String speedStr = getParameter("SPEED");
                if("slow".equals(speedStr)) speed = 20;
                else if("medium".equals(speedStr)) speed = 15;
                else speed = 10;

                try
                {
                	url = new URL(getDocumentBase(), getParameter("URL"));
                }
                catch(Exception e)
                {
                }

                bgColor = parseColorName(getParameter("BGCOLOR"),Color.black);

                images = parseAndLoadImages(getParameter("IMAGES"));
                
                Font font = new Font(fontName, fontStyle, fontSize);

                FontMetrics fm = getToolkit().getFontMetrics(font);

                image = createImage(fm.stringWidth(text) + imgsWidth + size().width, size().height);

                scrolled = -size().width;

                parseAndDrawText(image.getGraphics(), text, fm, font, images);
        }

        // Draw the text to the offscreen graphics
        private void parseAndDrawText(Graphics g, String text,
                FontMetrics fm, Font font, Enumeration images)
        {
                g.setFont(font);
                g.setColor(bgColor);
                g.fillRect(0,0,image.getWidth(this),image.getHeight(this));
                g.setColor(Color.white);

                StringBuffer buf = new StringBuffer();
                boolean readColor = false, slash = false;

                for(int i = 0; i < text.length(); i++)
                {
                        char c = text.charAt(i);

                        if(c == '#' && !slash)
                        {
       	                        if(readColor)
                                {
                                        g.setColor(parseColorName(buf.toString(),Color.white));
                                        buf.setLength(0);
                                        readColor = false;
                                }
                                else
                                {
                                        readColor = true;
                                }
                        }
                        else if(c == '$' && !readColor && !slash)
                        {
                                try
                                {
                                        Image img = (Image)(images.nextElement());
                                        g.drawImage(img,scrollLength,0,this);
                                        scrollLength += img.getWidth(this);
                                }
                                catch(Exception e)
                                {
                                }
                        }
                        else if(c == '/' && !slash)
                        {
                                slash = true;
                        }
                        else if(readColor)
                        {
                                buf.append(c);
                        }
                        else
                        {
                                if(slash == true) slash = false;
                                g.drawString(String.valueOf(c), scrollLength, fm.getAscent());
                                scrollLength += fm.charWidth(c);
                        }
                }
        }

        // Converts a color name string to a color object
        private Color parseColorName(String name, Color defaultColor) {
                if("red".equals(name)) return Color.red;
                else if("green".equals(name)) return Color.green;
                else if("blue".equals(name)) return Color.blue;
                else if("yellow".equals(name)) return Color.yellow;
                else if("orange".equals(name)) return Color.orange;
                else if("white".equals(name)) return Color.white;
                else if("lightGray".equals(name)) return Color.lightGray;
                else if("gray".equals(name)) return Color.gray;
                else if("darkGray".equals(name)) return Color.darkGray;
                else if("black".equals(name)) return Color.black;
                else if("cyan".equals(name)) return Color.cyan;
                else if("magenta".equals(name)) return Color.magenta;
                else if("pink".equals(name)) return Color.pink;
                else return defaultColor;
        }

        // Load the images
        private Enumeration parseAndLoadImages(String s)
        {
                if(s == null) return null;

                int i = 0;
                Vector images = new Vector();
                StringTokenizer st = new StringTokenizer(s);
                MediaTracker tracker = new MediaTracker(this);

                while(st.hasMoreTokens())
                {
                        try
                        {
                                Image image = getImage(new URL(getDocumentBase(), st.nextToken()));
                                images.addElement(image);
                                tracker.addImage(image,i);
                                tracker.waitForID(i++);
                                imgsWidth += image.getWidth(this);
                        }
                        catch(Exception e)
                        {
                        }
                }

                return images.elements();
        }

        // Start the main thread
        public void start()
        {
                thread = new Thread(this);
                thread.start();
        }

        // Stop the main thread
        public void stop()
        {
                thread = null;
                scrolled = -size().width;
        }

        // Thread run method
        public void run()
        {
                while(Thread.currentThread() == thread)
                {
                        long time = System.currentTimeMillis();

                        if(++scrolled > scrollLength) scrolled = -size().width;

                        repaint();

                        try
                        {
                                thread.sleep(Math.max(speed - (System.currentTimeMillis() - time),0));
                        }
                        catch(InterruptedException e)
                        {
                        }
                }
        }

        // Handle events
        public boolean mouseEnter(Event e, int x, int y)
        {
                if(url != null) getAppletContext().showStatus("Link: " + url.toString());
                return true;
        }

        public boolean mouseExit(Event e, int x, int y)
        {
                if(url != null) getAppletContext().showStatus("");
                return true;
        }

        public boolean mouseUp(Event e, int x, int y)
        {
                if(url != null) getAppletContext().showDocument(url,target);
                return true;
        }

        // Handle drawing
        public void update(Graphics g)
        {
                g.setColor(bgColor);
                if(scrolled < 0)
                {
                        g.setColor(bgColor);
                        g.fillRect(0,0,-scrolled,size().height);
                }
                g.drawImage(image,-scrolled,0,this);
        }

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

        // Return applet info
        public String getAppletInfo()
        {
                return "ProScroll version 2.3 by Slava Pestov";
        }
}
