/**
 * @(#)AnimatedNotifier.java
 *
 * <code>AnimatedNotifier</code> class is a JFrame 
 * which shows a sequence of images to create an 
 * animation. An <code>AnimatedNotifier</code> is 
 * used when program does something and the user 
 * should be able to distinguish whether the program 
 * is non-responsive or not. For instance; while 
 * paginating the book, the program seems to "stall".
 * To show users that the program is still working, 
 * an <code>AnimatedNotifier</code> can be created.
 * 
 * @author Gokhan Capar
 * @version 1.00 21.12.2009
 */

package bin;
 
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import java.awt.Color;
import java.io.*;
import javax.imageio.*;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;

public class AnimatedNotifier extends JFrame{

	/**
	 * <code>serialVersionUID</code><br>
	 * Created by Eclipse.
	 */
	private static final long serialVersionUID = -1544117638651264444L;

	/**
	 * <code>finished</code><br>
	 * Determines whether the loop is finished or not.
	 */
	private boolean finished = true;
		
	/**
	 * <code>animatingArray</code><br>
	 * Array of <code>ImageIcon</code>s. Every frame 
	 * of the animation is stored here.
	 */
	private static BufferedImage[] animatingArray;
	
	/**
	 * <code>info</code><br>
	 * The informing little image. 
	 * Intended to be about 145x82.
	 */
	private BufferedImage info;
	
	static {
		// Create a new BufferedImage array
		animatingArray = new BufferedImage[26];
		// Try these:
		try {
			// For each frame
			for(int n = 0;n<26;n++)
				// Load the image for that frame
				animatingArray[n] = ImageIO.read(new File("images/anims/sequence/"+n+".jpg"));
		// If any exception occurs
		} catch (Exception e) {
			// Leave the program
			System.exit(0);
		}
	}
	
	/**
	 * Creates a new <code>AnimatedNotifier</code> 
	 * object. Determines the name and loads the frames.
	 * Once created, start() method should be invoked to 
	 * make the notifier appear.
	 * @param name Name of the notifier. Name is 
	 * important because, for instance, if animation is 
	 * named <code>'wait'</code>, then the information 
	 * image for 'wait' will be loaded from the path
	 * <code>images/anims/wait.jpg</code>.
	 */
    public AnimatedNotifier(String name) {
    	// Try that:
		try {
			// Load the image for that notifier
			info = ImageIO.read(new File("images/anims/"+name+".jpg"));
		// If an error occurs
		} catch (Exception e) {
			// Don't even create this screen
			dispose();
		}
    	// Make the window undecorated
	    setUndecorated(true);
	    // Resize it to 300 x 200
	    setSize(300,200);
	    // Bring it on top
	    setAlwaysOnTop(true);
	    // Center to the screen
		setLocationRelativeTo(null);
    }
    
	/**
	 * <code>stop</code><br>
	 * Waits for 750 milliseconds (to ensure that the 
	 * animation is clearly seen), sets finished to true,
	 * waits 750 milliseconds again (to ensure that the 
	 * final frame is clearly seen), then disposes the 
	 * screen.
	 */
    public void stop() {
    	// If nowait mode is off
    	if (!Splash.isNoWait())
	    	// Wait for 750 milliseconds
	    	AnimatedNotifier.wait(750);
	    // Make the 'finished' true
   		finished=true;
    	// Dispose the screen
    	dispose();
    }
    
	/**
	 * <code>start</code><br>
	 * Sets the window to visible and starts the animation.
	 */
    public void start() {
		// Set finished to false
		finished = false;
    	// Make visible
    	setVisible(true);
    	// Create two buffers to prevent the flickering
    	createBufferStrategy(2);
    	// Create a new Thread and start it
		new Thread() {
			public void run() {
				// Set n to zero
				int n=0;
				// Loop until finished
				while(!finished || isVisible()) {
					// Draw the current frame
					draw (n);
					// Sleep for 20 milliseconds
					AnimatedNotifier.wait(20);
					// Increase n by 1
					n++;
					// Use remainder to keep n in bounds
					n%=26;
				}
			}
		// Start the thread
		}.start();
    }
        
    /**
     * <code>draw</code>
     * The method which is called by the drawing cycle. 
     * This method draws the current animation frame and
     * the information image.
     * @param n The animation frame.
     */
    private void draw (int n) {
    	// Get the current Graphics object of the frame and cast it
    	Graphics2D g2d = (Graphics2D) getBufferStrategy().getDrawGraphics();
    	// If there is no Graphics object
    	if (g2d == null)
    		// Leave the method
    		return;
    	// Fill the background
    	g2d.fillRect(158,0,142,200);
    	// Draw the animation frame
    	g2d.drawImage(animatingArray[n],null,0,0);
    	// Draw the info image
    	g2d.drawImage(info,null,127,25);
		// Dispose the Graphics object
		g2d.dispose();
		// Show the BufferStrategy object
		getBufferStrategy().show();
    }
    
	/**
	 * <code>wait</code><br>
	 * Invokes <code>Thread.sleep()</code> method
	 * inside a <code>try-catch</code> block to 
	 * make the program sleep for a specified time.
	 * <br> Main purpose of this method is to make the 
	 * code more readable by getting rid of some 
	 * <code>try-catch<code> blocks.
	 * @param milliseconds Time in milliseconds.
	 */
    public static void wait (int milliseconds) {
    	// Try to ...
		try {
			// ... wait for x milliseconds
			Thread.sleep(milliseconds);
		// Ignore the InterruptedException
		} catch (Exception e) {}
    }
}