/*

    FadingText 1.01

    Jim Nelson, 19 May 1996
    jnelson@crl.com
    http://www.crl.com/~jnelson/

    Copyright (c) 1996 Jim Nelson (jnelson@crl.com).  All rights reserved.
    Permission to re-distribute this applet granted by the author.  No
    warranties are made on the fitness of this program or its source code.

    Description:

        FadingText will "fade" various text messages in and out of view.
        It supports up to eight messages, a few palettes of colors, and
        adjustable timing.  Optionally, URLs can be associated with the
        any or all of the messages, which the browser will jump to if the
        user clicks on the message.  The URL will be displayed in the status
        bar if the mouse is held over the message as it's displayed.

    Applet parameters:

        text[1-8]: up to eight messages can be added as parameters.
            (optional, although at least one required to make this useful).
        url[1-8]: each text message can have an associated URL that the
            browser will jump to if the applet is clicked on while that
            message is in view. (optional)
        fadeDelay: time (in milliseconds) to delay between text colorizations
            (fading).  (optional, 100 msec default).
        holdDelay: time (in milliseconds) to delay once the text has completely
            faded into view.  (optional, 750 msec default).
        blankDelay: time (in milliseconds) to delay once the text has completely
            faded out of view, (optional, 750 msec default).
        palette: describes the background and foreground colors.  The choices
            currently are:
                BLACKTOWHITE
                WHITETOBLACK
                BLACKTOYELLOW
            (optional, default is WHITETOBLACK)
        fontSize: the size of the font to use in points.  (optional, 36
            point size is default).

    Example:

        <APPLET CODE="FadingText.class" WIDTH=600 HEIGHT=50>
        <PARAM NAME="text1" VALUE="message #1">
        <PARAM NAME="text2" VALUE="message #2">
        <PARAM NAME="text3" VALUE="message #3">
        <PARAM NAME="url1" VALUE="page1.html">
        <PARAM NAME="url3" VALUE="page3.html">
        <PARAM NAME="fontsize" VALUE="18">
        <PARAM NAME="palette" VALUE="BLACKTOWHITE">
        <PARAM NAME="holdDelay" VALUE="1500">
        </APPLET>

    Notes:

        This class is the first Java applet or application I've written.
        I used the NervousText class as a "shell" to get me started, so
        kudos to the respective authors of that class.

    Bugs:

        Although there's technically nothing wrong with specifying text
        parameters non-sequentially (i.e. "text1", and "text3" with no
        "text2"), the applet currently won't handle it properly.  Note that
        this is *not* true for the URL parameters.

        The URLs must be relative.  Absolute URLs aren't supported right
        now.

        The applet cannot handled being resized once started.  Not an issue
        with the code here, but if subclassed or cannibalized for another
        applet, beware.

    Wishlist:

        border: specifies the size of the border to place around the applet.
            The color of the border is the same as the text when in full
            view.  (optional, default is 0 which is no border)

*/

import java.applet.Applet;
import java.applet.AppletContext;
import java.awt.*;
import java.net.URL;
import java.net.MalformedURLException;

public class FadingText extends Applet implements Runnable
{
    //
    // constants
    //

    static final int fadeMsgMax = 8;
    static final int fadeStepMax = 4;
    static final int fadeDelayDefault = 100;
    static final int holdDelayDefault = 750;
    static final int blankDelayDefault = 750;
    static final int fontSizeDefault = 36;

    //
    // palettes
    //

    static final Color whiteToBlackPalette[] =
    {
        Color.white,
        Color.lightGray,
        Color.gray,
        Color.black
    };

    static final Color blackToWhitePalette[] =
    {
        Color.black,
        Color.gray,
        Color.lightGray,
        Color.white
    };

    static final Color blackToYellowPalette[] =
    {
        Color.black,
        Color.gray,
        Color.orange,
        Color.yellow
    };

    //
    // variables
    //

    Color [] fadeArray = null;
    String msgArray[] =
    {
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null
    };
    URL msgUrl[] =
    {
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null
    };
    int msgX[] =
    {
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
    };
    int msgY[] =
    {
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
    };

    int msgCount = 0;
    int currentMsg = 0;
    int colorCtr = 0;
    boolean fadeInText = true;
    Thread updateThread = null;
    int fadeDelay = fadeDelayDefault;
    int holdDelay = holdDelayDefault;
    int blankDelay = blankDelayDefault;
    int fontHeight;
    int fontSize = fontSizeDefault;
    boolean mouseInApplet = false;
    boolean displayedMessage = false;
    Dimension appletDimensions = null;

    //
    // methods
    //

    public String getAppletInfo()
    {
        return "FadingText 1.00, copyright (c) 1996 Jim Nelson (jnelson@crl.com)";
    }

    public void init()
    {
        String param;            
        int ctr;

        // have at least one param for testing/debugging of applet
        msgArray[0] = getParameter("text1");
        if(msgArray[0] == null)
        {
            msgArray[0] = "Your message here.";
        }
        msgCount++;

        // read in the rest of the text parameters
        for(ctr = 1; ctr < fadeMsgMax; ctr++)
        {
            String paramName = "text" + (ctr + 1);

            msgArray[ctr] = getParameter(paramName);
            if(msgArray[ctr] != null)
            {
                msgCount++;
            }
        }

        // read in the URL parameters
        for(ctr = 0; ctr < fadeMsgMax; ctr++)
        {
            String paramName = "url" + (ctr + 1);

            param = getParameter(paramName);
            if(param != null)
            {
                try
                {
                    msgUrl[ctr] = new URL(getDocumentBase(), param);
                }
                catch(MalformedURLException m)
                {
                }
            }
        }

        param = getParameter("holdDelay");
        if(param != null)
        {
            holdDelay = Integer.parseInt(param);
        }

        param = getParameter("fadeDelay");
        if(param != null)
        {
            fadeDelay = Integer.parseInt(param);
        }

        param = getParameter("blankDelay");
        if(param != null)
        {
            blankDelay = Integer.parseInt(param);
        }

        param = getParameter("fontSize");
        if(param != null)
        {
            fontSize = Integer.parseInt(param);
        }

        // default palette is white background to black foreground
        fadeArray = whiteToBlackPalette;

        // if a palette is specified, go with it
        param = getParameter("palette");
        if(param != null)
        {
            if(param.equalsIgnoreCase("BLACKTOWHITE"))
            {
                fadeArray = blackToWhitePalette;
            }
            else if(param.equalsIgnoreCase("WHITETOBLACK"))
            {
                fadeArray = whiteToBlackPalette;
            }
            else if(param.equalsIgnoreCase("BLACKTOYELLOW"))
            {
                fadeArray = blackToYellowPalette;
            }
        }

        // get the applet's size
        Dimension appletDimensions = size();

        // clear the background
        setBackground(fadeArray[0]);

        // set up the font and get font information
        setFont(new Font("TimesRoman", Font.BOLD, fontSize));
        fontHeight = getGraphics().getFontMetrics(getFont()).getHeight();

        // precalculate the font X and Y position in the applet box
        for(ctr = 0; ctr < fadeMsgMax; ctr++)
        {
            if(msgArray[ctr] == null)
            {
                continue;
            }

            msgX[ctr] = (appletDimensions.width -
                getGraphics().getFontMetrics().stringWidth(msgArray[ctr])) / 2;
            if(msgX[ctr] < 0)
            {
                msgX[ctr] = 0;
            }

            msgY[ctr] = (appletDimensions.height - fontHeight) / 2;

            // add back in the font height because the y-coordinate
            // describes the *base* of the font, not the top
            msgY[ctr] += fontHeight;

            if(msgY[ctr] < 0)
            {
                msgY[ctr] = 0;
            }
        }
    }

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

    public void stop()
    {
        updateThread = null;
    }

    public void run()
    {
        while(updateThread != null)
        {
            // pause the thread the configured amount of time (depends
            // on what stage of displaying the text the thread is at)
            try
            {
                if(colorCtr == 0)
                {
                    Thread.sleep(blankDelay);
                }
                else if(colorCtr == (fadeStepMax - 1))
                {
                    Thread.sleep(holdDelay);
                }
                else
                {
                    Thread.sleep(fadeDelay);
                }
            }
            catch (InterruptedException e)
            {
            }

            // move the color counter up or down, depending on the
            // "direction" the fade is travelling
            if(fadeInText == true)
            {
                if(++colorCtr >= fadeStepMax)
                {
                    // message has faded into view, time to start winding down
                    colorCtr = fadeStepMax - 1;
                    fadeInText = false;
                }
            }
            else
            {
                if(--colorCtr < 0)
                {
                    colorCtr = 0;
                    fadeInText = true;

                    // text has faded out, time to switch messages
                    if(++currentMsg >= msgCount)
                    {
                        // end of messages, roll over to the first one
                        currentMsg = 0;
                    }
                }
            }

            // some changes have been made, repaint the whole she-bang
            repaint();

            // update the status bar
            UpdateStatusBar();
        }
    }

    // overriden to avoid flickering
    public void update(Graphics g)
    {
        if(colorCtr == 0)
        {
            super.update(g);
        }
        else
        {
            paint(g);
        }
    }

    public void paint(Graphics g)
    {
        // anything to display for this round?
        if(msgArray[currentMsg] == null)
        {
            // nope
            return;
        }

        // if the colorCtr is 0, then update() took care of blanking the
        // component
        if(colorCtr != 0)
        {
            // set the current fade color
            g.setColor(fadeArray[colorCtr]);

            // print the string in the right spot
            g.drawString(msgArray[currentMsg], msgX[currentMsg], msgY[currentMsg]);
        }
    }

    // if the user runs the mouse over the message, display its URL (if
    // any) in the status bar
    public boolean mouseEnter(Event event, int x, int y)
    {
        mouseInApplet = true;
        UpdateStatusBar();

        return true;
    }

    // likewise, need to know when the user moves the mouse out of the applet
    // clear the status bar to blank any lingering messages (if any were
    // displayed)
    public boolean mouseExit(Event event, int x, int y)
    {
        mouseInApplet = false;
        if(displayedMessage == true)
        {
            getAppletContext().showStatus("");
            displayedMessage = false;
        }

        return true;
    }

    // if user clicks on applet, will jump to URL (if one was specified
    // in applet parameters)
    public boolean mouseDown(Event event, int x, int y)
    {
        // see if a message is visible and it has an URL
        if((colorCtr != 0) && (msgUrl[currentMsg] != null))
        {
            // jump to that URL
            getAppletContext().showDocument(msgUrl[currentMsg]);
        }

        return true;
    }

    // if (a) the mouse is over the applet, (b) a message is being displayed,
    // and (c) that message has an associated URL, display the URL in the
    // status bar ... otherwise, if a message had been displayed, clear it
    public void UpdateStatusBar()
    {
        if((mouseInApplet == true) && (colorCtr != 0) && (msgUrl[currentMsg] != null))
        {
            getAppletContext().showStatus(msgUrl[currentMsg].toString());
            displayedMessage = true;
        }
        else if(displayedMessage == true)
        {
            getAppletContext().showStatus("");
        }
    }
}


