/*
 * TextFader copyright 1997 by Carl Burke (cburke@mitre.org)
 *
 * Initial framework from FunMessage v. 1.1 by Daniel Julià Lundgren
 * (dani@harrison.upf.es), but the fader algorithms have been completely
 * rewritten.
 */

import java.awt.*;
import java.applet.*;
import java.net.*;
import java.util.*;

public class TextFader extends Applet implements Runnable
{
    public String preferredFontName;
    public String selectedFontName;
    public int m_pause;  // pause within message
    public int m_rest;  // pause between messages
    public int fadeInSpeed, fadeOutSpeed;
    public Color m_bk;  // background color
    public Color m_fg;  // foreground color
    public String the_message;
    private Font mFont;  // internal font
    private boolean m_reset,m_fadein,m_fadeout,m_hold, m_resting;
    private Thread engine = null;
    private Color[] fadeInColors;
    private Color[] fadeOutColors;
    private int fadeInFrame, fadeOutFrame;
    private int ample;   // length required to display current message in selected font

    public String getAppletInfo()
    {
	return "TextFader by CDB version 1.0";
    }

    //Parameter Info

    public String[][] getParameterInfo()
    {
	String[][] info = {
		{"fadein", "int", "Time to fade in (* 50 msec)"},
		{"pause", "int", "Pause within messages (* 50 msec)"},
		{"fadeout", "int", "Time to fade out (* 50 msec)"},
		{"rest", "int", "Pause between messages (* 50 msec)"},
		{"bk", "string", "Background color in decimal xxx|xxx|xxx"},
		{"fg", "string", "Foreground color in decimal xxx|xxx|xxx"},
		{"preferredFont", "string", "Name of desired font"},
	};
	return info;
    }

    public void selectFont()
    {
	String fontNames[] = Toolkit.getDefaultToolkit().getFontList();
	int i;
	selectedFontName = fontNames[0];
	for (i=0;i<fontNames.length;i++)
	{
	    if (fontNames[i].equalsIgnoreCase(preferredFontName))
	    {
		selectedFontName = fontNames[i];
	    }
	    else if (fontNames[i].equalsIgnoreCase("Helvetica"))
	    {
		if (!selectedFontName.equalsIgnoreCase(preferredFontName))
		    selectedFontName = fontNames[i];
	    }
	    else if (fontNames[i].equalsIgnoreCase("TimesRoman"))
	    {
		if ((!selectedFontName.equalsIgnoreCase(preferredFontName)) &&
		    (!selectedFontName.equalsIgnoreCase("Helvetica")))
		    selectedFontName = fontNames[i];
	    }
	}
    }

    public String getNextMessage()
    {
	return "TextFader default message";
    }

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

	param= getParameter("preferredFont");
	if (param==null)
	{
	    preferredFontName = "Arial";
	}
	else if (param.length()==0)
	{
	    preferredFontName = "Arial";
	}
	else
	{
	    preferredFontName = param;
	}
	selectFont();

	param= getParameter("pause");
	if (param==null)
	{
	    m_pause=40;
	}
	else if (param.length()==0)
	{
	    m_pause=40;
	}
	else
	{
	    m_pause = Integer.parseInt(param);
	}

	param= getParameter("fadein");
	if (param==null)
	{
	    fadeInSpeed=10;
	}
	else if (param.length()==0)
	{
	    fadeInSpeed=10;
	}
	else
	{
	    fadeInSpeed = Integer.parseInt(param);
	}

	param= getParameter("fadeout");
	if (param==null)
	{
	    fadeOutSpeed=10;
	}
	else if (param.length()==0)
	{
	    fadeOutSpeed=10;
	}
	else
	{
	    fadeOutSpeed = Integer.parseInt(param);
	}

	param= getParameter("rest");
	if (param==null)
	{
	    m_rest=10;
	}
	else if (param.length()==0)
	{
	    m_rest=10;
	}
	else
	{
	    m_rest = Integer.parseInt(param);
	}

	int[] bk2=new int[3]; /*temporary variable*/
	
	param= getParameter("bk");
	if (param==null)
	{
	    bk2[0] = 255;
	    bk2[1] = 255;
	    bk2[2] = 255;
	}
	else if (param.length()==0)
	{
	    bk2[0] = 255;
	    bk2[1] = 255;
	    bk2[2] = 255;
	}
	else
	{
	    int value;
    
	    Vector v=parseStrings(param);
	    
	    bk2[0]=java.lang.Integer.parseInt(((String)v.elementAt(0)));
	    bk2[1]=java.lang.Integer.parseInt(((String)v.elementAt(1)));
	    bk2[2]=java.lang.Integer.parseInt(((String)v.elementAt(2)));
	}
	
	int[] fg2=new int[3]; /*temporary variable*/
	
	param= getParameter("fg");
	if (param==null)
	{
	    fg2[0] = 0;
	    fg2[1] = 0;
	    fg2[2] = 0;
	}
	else if (param.length()==0)
	{
	    fg2[0] = 0;
	    fg2[1] = 0;
	    fg2[2] = 0;
	}
	else
	{
	    int value;
    
	    Vector v=parseStrings(param);
	    
	    fg2[0]=java.lang.Integer.parseInt(((String)v.elementAt(0)));
	    fg2[1]=java.lang.Integer.parseInt(((String)v.elementAt(1)));
	    fg2[2]=java.lang.Integer.parseInt(((String)v.elementAt(2)));
	}
	
	//Create Foreground and background colors
	m_bk=new Color(bk2[0],bk2[1],bk2[2]);
	m_fg=new Color(fg2[0],fg2[1],fg2[2]);

	//Create internal font
	mFont=new Font(selectedFontName,Font.BOLD,(int)(bounds().height*0.7));

	//Create fade in colors
	fadeInColors = new Color[fadeInSpeed+2];
	fadeInColors[0] = m_bk;
	fadeInColors[fadeInSpeed+1] = m_fg;
	for (i=1;i<=fadeInSpeed;i++)
	{
	    fadeInColors[i] = new Color(
		bk2[0]+(i*(fg2[0]-bk2[0]))/fadeInSpeed,
		bk2[0]+(i*(fg2[1]-bk2[1]))/fadeInSpeed,
		bk2[0]+(i*(fg2[2]-bk2[2]))/fadeInSpeed);
	}

	//Create fade out colors
	fadeOutColors = new Color[fadeOutSpeed+2];
	fadeOutColors[0] = m_fg;
	fadeOutColors[fadeOutSpeed+1] = m_bk;
	for (i=1;i<=fadeOutSpeed;i++)
	{
	    fadeOutColors[i] = new Color(
		fg2[0]+(i*(bk2[0]-fg2[0]))/fadeOutSpeed,
		fg2[1]+(i*(bk2[1]-fg2[1]))/fadeOutSpeed,
		fg2[2]+(i*(bk2[2]-fg2[2]))/fadeOutSpeed);
	}

	m_reset=true;
	m_fadein=false;
	m_fadeout=false;
	m_hold=false;
	m_resting=false;
    }

    public void run()
    {
	Thread me = Thread.currentThread();
	me.setPriority(Thread.MAX_PRIORITY);
	while ( engine == me )
	{
	    try
	    {
		//Thread to sleep x ms 	
		if (m_resting)
		{
		    me.sleep(m_rest*50); //pause within messages
		    m_resting = false;
		    m_reset=true;
		}
		else if (m_hold)
		{
		    me.sleep(m_pause*50); //pause within messages
		    m_hold = false;
		    m_fadeout=true;
		    fadeOutFrame = 0;
		}
		else
		{
		    me.sleep(50);
		}
	    }
	    catch ( InterruptedException e )
	    {
		// do nothing
	    }
	    repaint();
	}
    }

    //Paint the current frame.	
    public void paint(Graphics g)
    {
	g.setFont( mFont );
	Color textColor = m_bk;

	if (m_reset)
	{
	    the_message = getNextMessage();
    
	    FontMetrics fm=g.getFontMetrics(mFont);
	    ample = fm.stringWidth(the_message);	
	    g.setColor(m_bk);
	    g.fillRect(0,0,bounds().width,bounds().height);
	    m_reset=false;
	    m_fadein=true;
	    fadeInFrame = 0;
	}
	else if (m_fadein)
	{
	    textColor = fadeInColors[fadeInFrame++];
	    if (fadeInFrame >= fadeInSpeed)
	    {
		m_fadein=false;
		m_hold=true;
	    }    
	}
	else if (m_fadeout)
	{
	    textColor = fadeOutColors[fadeOutFrame++];
	    if (fadeOutFrame >= fadeOutSpeed)
	    {
		m_fadeout=false;
		m_resting=true;
	    }    
	}
	else if (m_hold)
	{
	    textColor = m_fg;
	}
	else if (m_resting)
	{
	    textColor = m_bk;
	}

	g.setColor(textColor);

	//Centered
	g.drawString(
	    the_message,
	    (bounds().width-ample)/2,
	    (bounds().height)/2 +8);
    }

    //Start the applet by forking an animation thread.
    public void start()
    {
	resize(bounds().width, bounds().height);
	if (engine == null)
	{
		engine = new Thread(this);
		engine.start();
	}
    }

    //Override update to avoid flickering

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

    public void stop()
    {
	if (engine != null && engine.isAlive())
	{
	    engine.stop();
	}

	engine = null;
    }

    //to parse a string with |...

    Vector parseStrings(String attr)
    {
	Vector result = new Vector(10);
	for (int i = 0; i < attr.length(); )
	{
	    int next = attr.indexOf('|', i);
	    if (next == -1) next = attr.length();
	    String file = attr.substring(i, next);
	    result.addElement(file);
	    i = next + 1;
	}
	return result;
    }
    public boolean handleEvent(Event evt)
    {
	if (evt.id == Event.WINDOW_DESTROY)  System.exit(0);
	return super.handleEvent(evt);
    }
}
