/** Use JWS to modify MyApplet13.java (previously AnimatorApplet5.java) 
 ** so that the scrolling text displayed is phrased correctly, e.g.  
 ** "0th" is not displayed and "1st", "2nd", "3rd" is displayed instead  
 ** of "1th", "2th", "3th", respectively. Make sure to fix all such  
 ** incorrect occurrences. In addition, change scrollDistance and 
 ** scrollPosition so that the text scrolls onto the page incrementally  
 ** from the left, starting with the last character of the scrolling  
 ** text, instead of the complete text jumping onto the page all at once.   
 ** Also, edit MyApplet13.html in the project directory, both to run the 
 ** MyApplet13.class file you create, and so that everything looks nice 
 ** and works properly.                                               **/

/** USE EXISTING JAVA CLASSES **/

import java.awt.*;
import java.applet.Applet;

/** EXTEND THE JAVA APPLET CLASS AND IMPLEMENT THE RUNNABLE INTERFACE **/

public class MyApplet13 extends Applet implements Runnable
   {int frameNumber = -1;                
    int delay;                          
    Thread animatorThread;
    boolean frozen = false;
    Font font=new Font("TimesRoman",Font.BOLD,24);
    FontMetrics fontm = getFontMetrics(font);
    String framestr = "";
    Dimension preImageDim;               // Define preImage variables needed to
    Image preImage;                      // create the offscreen copy of the image
    Graphics preImageGraphics;           // we want to paint on the screen.

    Image gifImage[];                    // Define an array of gif images and
    MediaTracker tracker;                // a tracker to preload them.
    int HiNumber = 1;

    /** INITIALIZE THE APPLET **/

    public void init()
       {setBackground(Color.blue);
	String str;
        int fps = 20;                       // Define the default fps (frames per second).
        str = getParameter("fps");         // Possibly, get HTML string specifying the
        try                                // fps.
         {if (str != null)
           {fps = Integer.parseInt(str);}  // If possible, convert HTML fps to an
          }                                // integer.
        catch (Exception e) {}             // In case the try caused something strange.
        delay = (fps > 0) ? (1000/fps): 100; // Convert fps to the milisecond delay
                                             // time between frames.			     
	gifImage = new Image[10];
        tracker = new MediaTracker(this);         // Spawn the tracker background thread(s)
        for (int i = 1; i <= 10; i++)             // in order to preload the images.
         {gifImage[i-1] = getImage(getCodeBase(),
                        	   "images/T"+i+".gif");
	  tracker.addImage(gifImage[i-1],0);
          }
	}  

    /** CLICK TO START OR STOP THE APPLET **/

    public boolean mouseDown(Event e, int x, int y)
       {if (frozen)
         {frozen = false;
          start();}
        else
         {frozen = true;
          animatorThread = null;           // Instead of calling stop() here, since
	  }                                // stop() now nullifies our preImage context,
        return true;                       // nullify only the animation thread in case
        }                                  // we want to build on our current preImage.

    /** GENERATE AND/OR START THE ANIMATION THREAD **/

    public void start()
       {if (frozen) { }                    // The animation is supposed to stay frozen.
        else                               // Otherwise, generate and/or start the
         {if (animatorThread == null)      // animation thread. Apparently, if run
           {animatorThread = new Thread(this);}  // breaks after catching an exception,
          animatorThread.start();                // the animatorThread though not null
          }                                      // will still need to be restarted.
        }

    /** CREATE AND DISPLAY FRAMES OF THE ANIMATION THREAD **/

    public void run()
       {try                                              // Start loading the images and
	 {tracker.waitForAll();}                         // wait until done before starting   
        catch (InterruptedException e) {}                // the animation.
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY); // Set the priority low.
        long startTime = System.currentTimeMillis();             // Remember start time.
        while (Thread.currentThread() == animatorThread)         // The animation loop.
           {frameNumber++;                               // Advance the frame number.
            repaint();                                   // Display the frame.
            try                                          // Sleep for the delay period.
             {startTime += delay;
              Thread.sleep(Math.max(0,
                                    startTime-System.currentTimeMillis()));
              }
            catch (InterruptedException e) {break;}     // In case the try caused
            }                                           // something strange, exit
        }                                               // the while loop.


    /** CREATE THE CURRENT FRAME OF THE ANIMATION THREAD **/
    
    public void paint(Graphics g)         // This technique of painting by calling
     {if (!frozen) update(g);}            // update, prevents the default (and hidden)  
					  // behavior of update, and instead allows
    public void update(Graphics g)        // the creation of an offscreen preImage 
     {Dimension d = size();              // preImage before painting the screen.  
      if (!tracker.checkAll())                       // If the images aren't all
       {g.clearRect(0, 0, d.width, d.height);        // loaded, then clear the 
	g.drawString("Please wait...",               // background and notify 
	             (d.width-20)/2, d.height/2);    // the user to wait.
        }
      else	       	               
       {if ((preImageGraphics == null) ||             // When all images are loaded, 
	    (d.width != preImageDim.width) ||         // compare the current applet
	    (d.height != preImageDim.height))         // viewing size to our preImage,
	     {preImageDim = d;                        // and if different, resize our 
	      preImage = createImage(d.width,d.height); // next preImage.
	      preImageGraphics = preImage.getGraphics();
	      }                                     
	preImageGraphics.setColor(getBackground());      // Clear the previous preImage
	preImageGraphics.fillRect(0,0,d.width,d.height); // by filling with the current
	preImageGraphics.setFont(font);                  // background color (magenta),
	preImageGraphics.setColor(Color.black);          // and then create the next
		 					 // offscreen preImage.
	if ((frameNumber + 5) % 10 == 0) HiNumber++;              // Say "Hi" to user,
	framestr = "Hi StLCOP for the " + HiNumber + "th time !"; // and count times.       
	String frameconstant = framestr;
	
	if (HiNumber == 0) HiNumber++;
	else if ((HiNumber % 10 == 1) && (HiNumber % 100 != 11))
	  {framestr = "Hi StLCOP for the " + HiNumber + "st time !";}
	else if ((HiNumber % 10 == 2) && (HiNumber % 100 != 12))
	  {framestr = "Hi StLCOP for the " + HiNumber + "nd time !";}
	else if ((HiNumber % 10 == 3) && (HiNumber % 100 != 13))
	  {framestr = "Hi StLCOP for the " + HiNumber + "rd time !";}
	else
	  {framestr = "Hi StLCOP for the " + HiNumber + "th time !";}
	
	/*if (HiNumber==1)
	  {framestr = "Hi StLCOP for the " + HiNumber + "st time !";}
	if (HiNumber==2)
	  {framestr = "Hi StLCOP for the " + HiNumber + "nd time !";}
	if (HiNumber==3)
	  {framestr = "Hi StLCOP for the " + HiNumber + "rd time !";}
	if ((HiNumber >= 20) && (HiNumber %10 == 1))
	  {framestr = "Hi StLCOP for the " + HiNumber + "st time !";}
	if ((HiNumber >= 20) && (HiNumber %10 == 2))
	  {framestr = "Hi StLCOP for the " + HiNumber + "nd time !";}
	if ((HiNumber >= 20) && (HiNumber %10 == 3))
	  {framestr = "Hi StLCOP for the " + HiNumber + "rd time !";}*/

	int scrollDistance = d.width + fontm.stringWidth(frameconstant);                         // Compute scroll position 
	int scrollPosition = -fontm.stringWidth(frameconstant) + (frameNumber % scrollDistance);    // of leftmost character      
	preImageGraphics.drawString(                          // of framestr, and draw
	   framestr,scrollPosition,d.height/2);	              // framestr above current
	preImageGraphics.drawImage(                           // image.
	   gifImage[frameNumber % 10],                        // Compute current image,
	   scrollPosition + (fontm.stringWidth(framestr))/3,  // and draw below framestr.
	   d.height/2,this);                                                                                         
							 // Offscreen preImage completed.
	g.drawImage(preImage,0,0,this);	                // Paint preImage on the screen.
	} 
      } 

    /** STOP THE ANIMATION THREAD **/

    public void stop()
      {animatorThread = null;     // The user either clicked to stop or left the page,
       preImageGraphics = null;   // so wipe out the current thread and preImage context.
       preImage = null;
       }	
    }