
package polarDust.calculator;

/*
 * Copyright (c) 1996 Sorin Lazareanu, All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies.
 *
 */

import java.awt.*;

/**
 * CutoutText is a component that shifts a marquee text from left to 
 * right within a given Graphics object.
 *
 * <br><br><a href=../source/polarDust/calculator/CutoutText.java>
 * The source code.</a>
 *
 * @version 0.9, 1996.06.04
 * @author Sorin Lazareanu
 */

public class CutoutText extends Canvas implements Runnable {
	boolean lSuspended;
	int iTick = 0;
	int iLogoTemplateWidth;
	Thread thisThread = new Thread(this, "ShiftingText");
	String logoTemplate;
	StringBuffer logo;
	Dimension bufferDimension;
	Image bufferImage = null;
	Graphics bufferGraphics;

	/**
	* Constructs the component 
	* @param aTemplate the text to be displayed.
	*/
	public CutoutText(String aTemplate) {
		super();
		logoTemplate = aTemplate;
	}

	/**
	* The thread is alive.
	*/
	public boolean isAlive() { return thisThread.isAlive(); }


	/**
	* Starts the thread.
	*/
	public void start() {
		if (!thisThread.isAlive()) {
			thisThread.setDaemon(true);
			thisThread.start();
			iTick = 0;
			lSuspended = false;
		}
	}

	/**
	* Stops the thread.
	*/
	public void stop() {
		if (thisThread.isAlive()) {
			thisThread.stop();
			iTick = 0;
		};
	}

	/**
	* Suspends the thread.
	*/
	public void suspend() {
		thisThread.suspend();
		iTick = 0;
		lSuspended = true;
		bufferLayout();
		repaint();
	}

	/**
	* The thread is suspended.
	*/
	public boolean isSuspended() { return lSuspended; }

	/**
	* Resume the thread.

	*/
	public void resume() {
		thisThread.resume();
		lSuspended = false;
 	}

	/**
	* Runs the thread.
	*/
	public void run() {
		long lLastmS = System.currentTimeMillis();

		while (thisThread != null) {
			try {
				if (bufferGraphics != null) {
					iTick++;
					bufferLayout();
				}
				thisThread.sleep(
					50L -
					Math.max(
						0L,
						Math.min(
							50L,
							System.currentTimeMillis() - lLastmS
						)
					)
				);
				lLastmS = System.currentTimeMillis();
				// Should repaint() be called only when Screen Updater thread is running ?
				// No specs. on Screen Updater.
				// The thread must be stopped before System.exit(...).
				repaint();
			} catch (InterruptedException e) {
				break;
			}

		};
	}

	/**
	* Paints on a Graphics object. Calls update for that. This is a callback method.
	*/
	public void paint(Graphics aGraphics) {
		update(aGraphics);
	}

	/**
	* Paints on a Graphics object.
	*/
	public synchronized void update(Graphics aGraphics) {
		int iWidth = size().width;
		int iHeight = size().height;
		int i, iMax;

		if (bufferDimension == null ||
			bufferDimension.width != iWidth ||
			bufferDimension.height != iHeight) {

			bufferDimension = size();
		 	bufferImage = createImage(iWidth, iHeight);
			bufferGraphics = bufferImage.getGraphics();
			bufferGraphics.setFont(new Font("Helvetica", Font.BOLD, 10));
			logo = new StringBuffer(logoTemplate);
			iLogoTemplateWidth = bufferGraphics.getFontMetrics().stringWidth(logoTemplate);
			iMax = iWidth / iLogoTemplateWidth + 2;
			logo = new StringBuffer(logoTemplate);
			for (i = 1; i < iMax; i++) {
				logo.append(logoTemplate);
			}
			iTick = 0;
			bufferLayout();
		}
		if (bufferImage != null)
			aGraphics.drawImage(bufferImage, 0, 0, this);
	}

	/**
	*
	*/
	private synchronized void bufferLayout() {
		if (bufferGraphics != null) {
			bufferGraphics.setColor(Color.white);
			bufferGraphics.fillRect(0, 0, bufferDimension.width, bufferDimension.height);
			bufferGraphics.setColor(Color.blue);
			iTick = iTick % iLogoTemplateWidth;
			bufferGraphics.drawString(
		   		"" + logo,
		   		-iTick + 3,
				(bufferDimension.height + getFontMetrics(getFont()).getAscent() + 1) / 2
			);
		}
	}

	public Dimension preferredSize() {
		Dimension aDim = new Dimension(155, 16);

		return aDim;
	}

	public Dimension minimumSize() {
		Dimension aDim = preferredSize();

		return aDim;
	}

}


