/*----------------------------------------------------------------------*/
/*  Banner -- animates text into a box 
           **based on James Gosling's DancingText.java (in this dir)    */ 
/*----------------------------------------------------------------------*/
/* public variables
           fontName="TimesRoman36bi"
           style=..0f-7 means {none, starburst, stage right shuffle, 
                    stage left shuffle , slide in from right, 
                    reverse order, alternate sides, random}  
           time=4000 ..time it takes to finsih animation 
           sound= the URL of a sound (played after animation)
           delay= time between frames (50 is default)  
           pause= pause before the animation starts
           amplitude=36 ..amplitude of the wave in pixels 
           length=1 .. a multiplier for the wave length
           trans=15 ..translates the wave--use to get the right end 
                    position   
           foreground=java.awt.Color.blue  
           background=java.awt.Color.lightGray  
           box = true ..draw a box around the text 
           centre = true ..centre text           
           y_space = 1 ..vertical spacing more thanfont size().height
           x,y = position in window
           xborder, yborder = blank space around the window (text formating)
                                                                        */
/*----------------------------------------------------------------------*/
/* If you want to do some custom animation for the text I have marked 
     easy spots for customization with "**" in the comments (namely 
     at the initial position, timing function (I like sqrt), and 
     the algorithm (this one is a linear combination of the initial and 
     the final positions with a wave in the y direction)                */
/*----------------------------------------------------------------------*/
/*  I left the original audio code in (commented out) but I can't use it 
    since I don't have a speaker                                        */
/*----------------------------------------------------------------------*/
/*               Jim Morey  -  morey@math.ubc.ca  - Aug 5               */
/*----------------------------------------------------------------------*/
  
import java.io.InputStream;
import java.awt.*;
import java.net.*;
import java.applet.*;

/*----------------------------------------------------------------------*/

class Banner implements Runnable{
  int x,y,time,delay,pause,style,amplitude,trans,xborder,yborder,y_space=1;
  float length;
  Color foreground = null, background = null;
  String audioName;
  String fontName;
  boolean fetchingAudio, playRequested, ready=false, keep_going, box;
  boolean centre;

  private long t0;
  private int x0[],xd[],y0[],yd[],W,H,len,xlen,ylen;
  private Graphics offscreen;
  private Image im;
  private Font thefont, font;
  private java.applet.Applet parent;
  private char text[];
  private AudioClip ad;

  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  Banner(java.applet.Applet parent,int wid, int heig) {
    this.parent = parent;
    time = 1000; 
    foreground = java.awt.Color.black;
    background = java.awt.Color.lightGray;
    delay = 50; 
    amplitude = 0; 
    trans = 0; 
    length = 5.0f;
    pause = 0; 
    style = 1; 
    x = 0; y = 0;
    xborder=0;  yborder=0;
    box = false;
    centre = false;

    W = wid;
    H = heig;

    im = parent.createImage(W,H);
    offscreen = im.getGraphics();
    offscreen.setColor(background);
    offscreen.fillRect(0, 0, W, H);
  }
  
  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public void setup_words(Component comp, String s){
    /* .. format the final postions of the Banner .. */
    if (s == null) s = "nothing to say";
    text = new char[s.length() + 2];
    s.getChars(0, s.length(), text, 0);
    if (fontName == null) fontName = "TimesRoman36i";

    int fstyle = 0;
    int size = 0;
    int c = 0;
    int pos = fontName.length();
    while (pos > 0) {
      c = fontName.charAt(--pos);
      switch (c) {
        case 'b':
	  fstyle |= Font.BOLD;
          continue;
        case 'i':
	  fstyle |= Font.ITALIC;
          continue;
      }
      break;
    }
    int fac = 1;
    while ('0' <= c && c <= '9') {
      size += (c - '0') * fac;
      if (--pos <= 0) break;
      c = fontName.charAt(pos);
      fac = fac * 10;
    }
    if (size <= 0) size = 24;

    fontName = fontName.substring(0, pos + 1);
    thefont = new Font(fontName, fstyle, size);
    FontMetrics fm = comp.getFontMetrics(thefont);
    if (thefont == null) thefont = font;
    else font = thefont;

    len = text.length;
    x0 = new int[len];
    xd = new int[len];
    y0 = new int[len];
    yd = new int[len];

    int x_cur = 0;
    int y_cur = fm.getAscent(); 

    int word=0;
    boolean startword=true;

    if (box) {
      /* .. make room for the box unless other borders were picked .. */
      if (xborder == 0 && yborder ==0){
        xborder=4;  yborder=4;
      }
    }
  
    /* .. figure out where the text should end up .. */
    int xmax = 0;
    xlen = len;
    ylen = 1;
    for (int i = 0; i < len; i++) {
      xd[i] = x_cur;
      if (text[i] == ' ') {
        startword = true;
        if (x_cur>xmax) xmax = x_cur;
      }
      x_cur += fm.getWidths()[text[i]];
      yd[i] = y_cur;
      if (x_cur>W-2*xborder) {
        y_cur += (fm.getAscent() + y_space);
        x_cur = 0;
        xlen = i;
        i = word-1;
        ylen++;
      }
      if (startword && text[i] != ' ') {
        word = i;
        startword = false;
      }
    }

    if (x_cur>xmax) xmax = x_cur;

    if (centre){
      int dy = (H-y_cur)/2-yborder;
      int dx = (W-xmax)/2-xborder;
      for (int i = 0; i < len; i++) {
        xd[i] += dx;
        yd[i] += dy;
      }
    }
  }

  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public void run(){
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

/*
   .. I can't play with this stuff since I don't have a speaker ..

    if (audioName != null && !fetchingAudio) {
      fetchingAudio = true;
      kicker = new Thread(this);
      kicker.start();
      Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
      ad = getAudioData(audioName);
      if (playRequested) play(getCodeBase(), ad);
      return;
    }
    if (ad != null)
      play(getCodeBase(), ad);
    else
      playRequested = true;
*/

    /* .. get a blank window to draw the text .. */
    offscreen.setFont(thefont); 
    offscreen.setColor(background);
    offscreen.fillRect(0, 0, W, H);
    offscreen.setColor(foreground);

    if (box) offscreen.drawRect(1, 1, W-3, H-3);

    /* .. **there is a lot of room to have new start positions .. */
    switch (style) {
      default:
      case 0: /* .. still .. */
	for (int i = 0; i < len; i++) { x0[i] = xd[i];  y0[i]=yd[i];}
	break;
      case 1: /* .. below and away  .. */
        for (int i = 0; i < len; i++) { x0[i] = W/2;  y0[i]=H*2;}
        break;
      case 2: /* .. stretch from the right .. */
	for (int i = 0; i < len; i++) { x0[i] = W;  y0[i]=yd[i]; }
	break;
      case 3: /* .. stretch form the left .. */
	for (int i = 0; i < len; i++){ x0[i] = 0;  y0[i]=yd[i]; }
        break;
      case 4: /* .. slide in from the right .. */
	for (int i = 0; i < len; i++){ x0[i] = xd[i] + W;  y0[i]=yd[i]; }
	break;
      case 5: /* .. in 2 dimension this one is not too predictable .. */ 
	for (int i = 0; i < len; i++){ x0[i] = xd[len - i - 1];  y0[i]=yd[i]; }
	break;
      case 6: /* .. stretch from both sides .. */
	for (int i = 0; i < len; i++){ x0[i] = (i & 1) == 0 ? W : 0;  y0[i]=yd[i]; }
	break;
      case 7: /* .. random .. */
	for (int i = 0; i < len; i++){ x0[i] = (int) (W * Math.random());  y0[i]=(int) (H*Math.random()); }
	break;
    }

    t0 = System.currentTimeMillis();
    float wave;

    keep_going=true;
    while (keep_going) {
      ready = false;
      offscreen.setColor(background);
      offscreen.fillRect(0, 0, W, H);
      offscreen.setColor(foreground);

      if (box) offscreen.drawRect(1, 1, W-3, H-3);

      long t = System.currentTimeMillis() - t0;
      wave = 1.0f;
      if (t > time) keep_going=false;
      /* .. **lots of possibilities for timing functions  .. */
      else wave = (float) Math.sqrt((double)t/(double)time);

      int lim = text.length - 2;
      for (int i = 0; i < lim; i++) {
        /* .. **lots of possibilities for algorthims too .. */
        offscreen.drawChars(text, i, 1  
          , (int) (wave*xd[i] + (1-wave)*x0[i] +xborder)  
          , (int) (wave*yd[i] + (1-wave)*y0[i] +yborder) 
         +(int)(amplitude*Math.sin(3.14f* (xd[i]/length+wave*100+trans)/16)) );
      }
      ready = true;
      parent.repaint();
try {Thread.sleep(delay);} catch (InterruptedException e){}
    }
  }

  /* -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
  public void paint(Graphics g) {
    if (ready) g.drawImage(im, x, y, null);
  }

}
