/*	Ticker Ver 1.2 by Toh Lik Khoong
/	Vertical Scroller developed using JDK 1.1
/	Last revised 23/04/2000
/	Please contact me at lktoh@mail.com for any comments or suggestions
*/

/*	sample applet for ticker
<applet code=ticker.class width=120 height=180>
<param name=filename value="news_e.txt">
<param name=font value="Helvetica">
<param name=size value="10">
<param name=target value="_new">
<param name=xmargin value="10">
<param name=ymargin value="25">
<param name=irect value="6688EE">
<param name=orect value="000000">
<param name=ntext value="000000">
<param name=htext value="FF0000">
<param name=speed value="20">
</applet>
*/

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

public class ticker extends Applet implements Runnable{

	// global parameters
	private Thread m_thread;
	private Image m_imgBuffer = null;
	private int y_pos = 0;		// scroller
	private int cur_news = 0;	// current news item
	private int cur_pos = 0;	// mouse cursor position
	private boolean pause = false;	// pause
	private boolean m_over = false;	// mouse over
	private Vector news = new Vector();	// contains the text to display
	private Vector urls = new Vector();	// contains the corresponding URL

	// default parameters
	private int size = 10;
	private Font ft = new Font("TimesRoman",Font.PLAIN,size);
	private String filename = "news.txt";
	private String target = "_new";
	private int height;
	private int xmargin = 10;
	private int ymargin = 0;
	private Color irect = new Color(8388736);
	private Color orect = new Color(0);
	private Color ntext = new Color(0);
	private Color htext = new Color(16711680);
	private int speed = 100;

	public void init(){

		// retrieval of applet parameters
		String param;
		param = getParameter("size");
		if (param != null) size = Integer.parseInt(param);
		param = getParameter("font");
		if (param != null) ft = new Font(param,Font.PLAIN,size);
		param = getParameter("target");
		if (param != null) target = param;
		param = getParameter("xmargin");
		if (param != null) xmargin = Integer.parseInt(param);
		param = getParameter("ymargin");
		if (param != null) ymargin = Integer.parseInt(param);
		param = getParameter("irect");
		if (param != null) irect = new Color(Integer.parseInt(param,16));
		param = getParameter("orect");
		if (param != null) orect = new Color(Integer.parseInt(param,16));
		param = getParameter("ntext");
		if (param != null) ntext = new Color(Integer.parseInt(param,16));
		param = getParameter("htext");
		if (param != null) htext = new Color(Integer.parseInt(param,16));
		param = getParameter("filename");
		if (param != null) filename = param;
		param = getParameter("speed");
		if (param != null) speed = Integer.parseInt(param);

		setFont(ft);
		FontMetrics fm = getFontMetrics(ft);
		height = fm.getAscent() + fm.getDescent();
		if (height > ymargin) ymargin = height;	// ymargin cannot be too small

		// Mouse Listener for the applet
		MouseListener ml = new MouseListener(){
			public void mouseClicked(MouseEvent e){
				if (urls.elementAt(cur_news) instanceof URL){
					URL myURL = (URL) urls.elementAt(cur_news);
					getAppletContext().showDocument(myURL,getParameter("target"));
				}
			}
			public void mouseEntered(MouseEvent e){
				stop();
				m_over = true;
				cur_pos = e.getY();
				repaint();
			}
			public void mouseExited(MouseEvent e){
				start();
				m_over = false;
				repaint();
			}
			public void mousePressed(MouseEvent e){}
			public void mouseReleased(MouseEvent e){}
		};
		addMouseListener(ml);

		MouseMotionListener mml = new MouseMotionListener(){
			public void mouseMoved(MouseEvent e){
				cur_pos = e.getY();
				m_over = true;
				repaint();
			}
			public void mouseDragged(MouseEvent e){
			}

		};
		addMouseMotionListener(mml);

		// read the news file
		readFile();
	}


	// function to read file
	private void readFile()
	{
		String line;
		try{
			URL url = new URL(getDocumentBase(), filename);
			try{	// read file
				BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
				do{
					line = in.readLine();
					if (line != null){
						try{
							StringTokenizer st = new StringTokenizer(line, "|");
							news.addElement(st.nextToken());	// get display text
							if (st.hasMoreTokens()){	// get url
								urls.addElement(new URL(getDocumentBase(), st.nextToken()));
							}
							else{	// no url, adding indicator
								urls.addElement("nourl");
							}
						}catch (NoSuchElementException nsee){}	// exception if carriage return at eof

					}
				}while (line != null);
			}
			catch (IOException e){
				news.addElement("Could not open news feed file.");
				urls.addElement("nourl");
				System.err.println("Could not open news feed file.");
			}
		}catch (MalformedURLException e){}
	}

	public void paint(Graphics g){
		if (m_imgBuffer == null){	// double buffering
			m_imgBuffer = createImage(getSize().width, getSize().height);
			render(g);	// display the ticker
		}
		g.drawImage(m_imgBuffer, 0, 0, null);
	}

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

	// function that displays the ticker
	public void render(Graphics g)
	{
		// drawing of the background
		g = m_imgBuffer.getGraphics();
		g.setColor(orect);
		g.fillRect(0, 0, getSize().width, getSize().height);
		g.setColor(irect);
		g.fillRect(xmargin, ymargin, getSize().width - 2 * xmargin, getSize().height - 2 * ymargin);
		g.setColor(ntext);

		FontMetrics fm = getFontMetrics(ft);	// to calculate string width later
		boolean reset = false;	// reset the value of y_pos
		int y = 0;
		String s = "";

		while (y + y_pos < getSize().height){
			// calculate the position of the news item
			for (int i = 0; i < news.size(); i++){
				if (m_over){	// mouse over the text
					int b1 = y_pos + 14;	// top current news border
					int b2 = y_pos + 14;	// bottom current news border
					// search for the current news to highlight
					while (b2 < getSize().height - height){
						for (int j = 0; j < news.size(); j++){
							b1 = b2;	// set top border
							StringTokenizer st = new StringTokenizer((String) news.elementAt(j)," ",false);
							String t = "";
							while (st.hasMoreTokens()){
								s = "";
								while (fm.stringWidth(s + t) < getSize().width - 2 * xmargin - 5 && st.hasMoreTokens()){
									if (!t.equals("")) s += t + " ";
									t = st.nextToken();
								}

								if (!st.hasMoreTokens() && fm.stringWidth(s + t) > getSize().width - 2 * xmargin - 5){
									b2 += 2 * height;
								}
								else{
									b2 += height;
								}
							}
							if (cur_pos > b1 && cur_pos < b2){	// look for current news
								cur_news = j;
							}
							b2 += 20;	// calculate bottom border
						}
					}
					// highlight item
					if (i == cur_news && (urls.elementAt(i) instanceof URL)) g.setColor(htext);
					else g.setColor(ntext);
				}

				// pause the ticker when new item appears
				if (y_pos + y == 3){
					pause = true;
				}

				// display the text
				String t = "";
				StringTokenizer st = new StringTokenizer((String) news.elementAt(i)," ",false);
				while (st.hasMoreTokens()){
					s = "";
					while (fm.stringWidth(s + t) < getSize().width - 2 * xmargin - 5 && st.hasMoreTokens()){
						if (!t.equals("")) s += t + " ";
						t = st.nextToken();
					}

					y += height;

					if (st.hasMoreTokens()){
						if ( y + y_pos > ymargin - height && y + y_pos < getSize().height - ymargin - 2 * height){
							g.drawString(s, xmargin + 2, y + y_pos + ymargin);
						}
					}
					else{	// special treatment for last line (no more tokens left)
						if (fm.stringWidth(s + t) > getSize().width - 2 * xmargin - 5){
							// not enough space, draw on different lines
							if ( y + y_pos > ymargin - height && y + y_pos < getSize().height - ymargin - 2 * height){
								g.drawString(s, xmargin + 2, y + y_pos + ymargin);
							}
							y += height;
							if ( y + y_pos > ymargin - height && y + y_pos < getSize().height - ymargin - 2 * height){
								g.drawString(t, xmargin + 2, y + y_pos + ymargin);
							}
						}
						else{	// if not, draw on same line
							if ( y + y_pos > ymargin - height && y + y_pos < getSize().height - ymargin - 2 * height){
								g.drawString(s + t, xmargin + 2, y + y_pos + ymargin);
							}
						}
					}
				}
				y += 20;
			}
			if (y + y_pos < 0) reset = true;
		}
		if (reset) y_pos = 0;	// reset the scroller position
	}

	public void start(){
		m_thread = new Thread(this);
		m_thread.start();
	}

	public void stop(){
		m_thread.stop();
	}

	public void run(){
		try{
			while(true){
				if (pause){	// pause when new item appears
					m_thread.sleep(4000);
					pause = false;
				}
				m_thread.sleep(speed);
				if (!m_over) y_pos--;	// scroll the ticker
				repaint();
			}
		}
		catch (InterruptedException e){}
	}
}
