import java.applet.*;
import java.awt.*;
import java.awt.event.*;
    // Use a non-1.2 class in deference to browsers.
import java.util.Vector;
import java.io.InputStream;

        /* Maintain a thread which cycles through an array of
         * Image objects. The files for the Images are bundled with
         * the associated .jar file.
         *
         * The animation is parameterised via
         *        imagebase - the base name for the image files
         *        frametime - the (long) time (in milliseconds) between images.
         */
public class MultiImageApplet extends Applet {
    public void init() throws RuntimeException {
        // Setup the layout and extract the images.
        setLayout(new BorderLayout());
        setupButtons();
        setupImageAnimator();
        // Start and suspend the thread ready for Applet.start().
        ImageAnimator animator = getAnimator();
        animator.setAnimationRunning(false);
        new Thread(animator).start();
    }

    public void start(){
        getAnimator().setAnimationRunning(true);
    }

    public void stop(){
        getAnimator().setAnimationRunning(false);
    }

        // Supply information on the parameters used.
    public String[][] getParameterInfo(){
        return parameterInfo;
    }
        
        // Provide a Start and Stop button for the animation.
        // In effect these are Suspend and Resume.
    protected void setupButtons(){
        Panel p = new Panel();
        Button start = new Button("Start");
        Button stop = new Button("Stop");
        p.add(start);
        p.add(stop);
        add(p,"South");

        // Attach appropriate listeners to the buttons.
        start.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                MultiImageApplet.this.start();
            }
        });

        stop.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                MultiImageApplet.this.stop();
            }
        });
    }

        // Extract the images from the associate archive file.
        // The base name for the GIF images is specified by the
        // applet parameter "imagebase".
        // Construct an ImageAnimator as a 
    protected void setupImageAnimator() throws RuntimeException {
        // Get the image.
        String baseName = checkParameter(parameterInfo[imagebaseParameter][0]);
        Image[] images = extractImages(baseName);
        ImageAnimator animator = new ImageAnimator(images);
        // See if the animation's frame time has been set.
        String frameTime = getParameter(parameterInfo[frametimeParameter][0]);
        if(frameTime != null){
            try{
                long time = Long.parseLong(frameTime);
                animator.setFrameTime(time);
            }
            catch(Exception e){
            }
        }
        // The animator is based upon a Canvas and so needs a size.
        Dimension size = getSize();
        animator.setSize(size.width,size.height);
        add(animator,"Center");
        setAnimator(animator);
    }

        // Get the images, which are located in the archive
        // loaded with this applet. The image names are of the form
        //        baseName+number+.gif
        // where number starts at 0.
    protected Image[] extractImages(String baseName) throws RuntimeException {
        // Build a vector until we know how many there are, then
        // set the Image[] attribute.
        Vector images = new Vector();
        try{
            // Compose the individual file names, from the base name
            // a number and the image type suffix.
            for(int i = 0; ; i++){
                images.addElement(extractImage(baseName+i+".gif"));
            }
        }
        catch(Exception e){
            if(images.size() == 0){
                throw new RuntimeException(
                                "Failed to load any images "+
                                e.getMessage());
            }
        }
        // Copy them into an array.
        final int numImages = images.size();
        Image[] imageArray = new Image[numImages];
        for(int i = 0; i < numImages; i++){
            imageArray[i] = (Image) images.elementAt(i);
        }
        return imageArray;
    }

        // Retrieve fileName from this applet's archive file.
    protected Image extractImage(String fileName) throws RuntimeException {
        try {
            InputStream imageStream = getClass().getResourceAsStream(fileName);
            Toolkit tk = Toolkit.getDefaultToolkit();
            byte imageBytes[] = new byte[imageStream.available()];
            imageStream.read(imageBytes);
            return tk.createImage(imageBytes);
        }
        catch(Exception e){
            throw new RuntimeException(e.toString());
        }
    }

        // Retrieve the given parameter from the applet's properties.
    protected String checkParameter(String parameter) throws RuntimeException {
        String value = getParameter(parameter);
        if(value == null){
            throw new RuntimeException("Parameter: "+parameter+" is missing.");
        }
        return value;
    }

    protected ImageAnimator getAnimator(){
        return animator;
    }

    protected void setAnimator(ImageAnimator a){
        animator = a;
    }

    // The image animator.
    private ImageAnimator animator;
    // Information on the parameters of this applet.
    private final int imagebaseParameter = 0, frametimeParameter = 1;
    private final String[][] parameterInfo = {
        {"imagebase", "string",
         "Base name of the image files in the JAR file."
        },
        {"frametime", "long", "Time in milliseconds between frames."},
    };
}
