//  AnimationDemo.java -- Simple animation demo.

import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class AnimationDemo extends Frame implements Runnable {
	boolean isAnimating = false;
	boolean isFirstTime = true;
	int animCanvasWidth;
	int animCanvasHeight;
	Thread animationThread = null;   
	Image imageCelPanel;
	Sprite[] spriteArray;
	Screen screen;
	Rectangle r;      
      
	public void init() {
		// INIT_CONTROLS
		setLayout(null);
		setBackground(java.awt.Color.lightGray);
		setSize(790, 550);
		add(animationCanvas);
		animationCanvas.setBackground(java.awt.Color.black);
		animationCanvas.setBounds(9, 6, 775, 500);
		startOrStopBtn.setLabel("Start");
		add(startOrStopBtn);
		startOrStopBtn.setBounds(79, 512, 73, 24);
		numObjectsLabel.setText("# of Sprites :");
		numObjectsLabel.setAlignment(java.awt.Label.RIGHT);
		add(numObjectsLabel);
		numObjectsLabel.setBounds(169, 514, 93, 20);
		add(speedSlider);
		speedSlider.setBounds(504, 514, 264, 20);
		speedLabel.setText("Speed :");
		speedLabel.setAlignment(java.awt.Label.RIGHT);
		add(speedLabel);
		speedLabel.setBounds(416, 514, 70, 21);
		numObjects.setText("20");
		add(numObjects);
		numObjects.setBounds(264, 514, 60, 24);
		add(numObjectsScroller);
		numObjectsScroller.setBounds(324, 508, 24, 35);
	
		// REGISTER_LISTENERS
		SymAction lSymAction = new SymAction();
		SymWindow aSymWindow = new SymWindow();
		this.addWindowListener(aSymWindow);
		exitApp.addActionListener(lSymAction);
		startItem.addActionListener(lSymAction);
		stopItem.addActionListener(lSymAction);
		startOrStopBtn.addActionListener(lSymAction);
		aboutItem.addActionListener(lSymAction);
		SymAdjustment lSymAdjustment = new SymAdjustment();
		numObjectsScroller.addAdjustmentListener(lSymAdjustment);
		//}}
		
		//-------------------------------------------------------
		// Load our 'cels'.
		//-------------------------------------------------------
		r = animationCanvas.getBounds();
		animCanvasWidth = r.width;
		animCanvasHeight = r.height;
		
		// Load images for animation.
		String urlImage = "./images/donutcels.gif";
		imageCelPanel = Toolkit.getDefaultToolkit().getImage(urlImage);
		MediaTracker tracker = new MediaTracker(this);
		tracker.addImage(imageCelPanel, 1);
		try {
			tracker.waitForAll();
		} catch (InterruptedException e) {
		}
		if (imageCelPanel == null || tracker.isErrorAny()) {
			System.out.println("Can't load image from " + urlImage + "!");
			System.out.println("Verify that [install dir]/images/donutcels.gif exists.");
		}         
	}

	// DECLARE_CONTROLS
	java.awt.Canvas animationCanvas = new java.awt.Canvas();
	java.awt.Button startOrStopBtn = new java.awt.Button();
	java.awt.Label numObjectsLabel = new java.awt.Label();
	java.awt.Scrollbar speedSlider = new java.awt.Scrollbar(Scrollbar.HORIZONTAL, 70, 5, 1, 100);
	java.awt.Label speedLabel = new java.awt.Label();
	java.awt.TextField numObjects = new java.awt.TextField();
	java.awt.Scrollbar numObjectsScroller = new java.awt.Scrollbar(Scrollbar.VERTICAL, 181, 1, 1, 201);

	// DECLARE_MENUS
	java.awt.MenuBar menuBar1   = new java.awt.MenuBar();
	java.awt.Menu fileMenu      = new java.awt.Menu();
	java.awt.MenuItem exitApp   = new java.awt.MenuItem();
	java.awt.Menu optionsMenu   = new java.awt.Menu();
	java.awt.MenuItem startItem = new java.awt.MenuItem();
	java.awt.MenuItem stopItem  = new java.awt.MenuItem();
	java.awt.Menu helpMenu      = new java.awt.Menu();
	java.awt.MenuItem aboutItem = new java.awt.MenuItem();
	
	class SymAction implements java.awt.event.ActionListener {
		public void actionPerformed(java.awt.event.ActionEvent event) {
			Object object = event.getSource();
			if (object == startItem)
			   startItem_ActionPerformed(event);
			else if(object == stopItem)
			   stopItem_ActionPerformed(event);
			else if(object == startOrStopBtn)
				startOrStop_ActionPerformed(event);
			else if (object == exitApp)
				exitApp_ActionPerformed(event);
			else if (object == aboutItem)
				aboutItem_ActionPerformed(event);
		}
	}

	class SymAdjustment implements java.awt.event.AdjustmentListener {
		public void adjustmentValueChanged(java.awt.event.AdjustmentEvent event) {
			Object object = event.getSource();
			if (object == numObjectsScroller)
				numObjectsScroller_AdjustmentValueChanged(event);
		}
	}

	public int toInt(String s) {
		int retVal = 0;
		try {
			retVal = Integer.parseInt(s);
		} catch(Exception e) {
		}
		return retVal;
	}      

	public void run() {
		// Run animation.
		if (isFirstTime) {
			// Class for doing actual drawing, along with offscreen.
			screen = new Screen(animationCanvas, r, Color.black, Color.black);
			isFirstTime = false;
		}         
      
		if(screen == null || imageCelPanel == null) {
			System.out.println("Not initialized!");
			return;
		}         
      
		String temp = numObjects.getText();
		int numSprites = toInt(temp); 
		if (numSprites < 1) {
			numSprites = 1;
			numObjects.setText("1");
			numObjectsScroller.setValue(200);
		}   

		// Bigger values = shorter delays.
		int delayMS = 110 - speedSlider.getValue();
      
		//-------------------------------------------------------------
		// Create requested # of sprites.
		//-------------------------------------------------------------
		spriteArray = new Sprite[numSprites];      
		            
		for (int i = 0; i < numSprites; i++) {
		spriteArray[i] = new Sprite(imageCelPanel, 
									60, 64, 64, 10, 
									animCanvasWidth, 
									animCanvasHeight);
		spriteArray[i].makeNewCoordinates();                                                
		}
		//-------------------------------------------------------------
		// Draw offscreen.      
		Graphics g = screen.getGraphics();                                                 
                   
		while (isAnimating) {
			//-------------------------------------
			// Do animation work.
			//-------------------------------------
			//=====================================
			// Display current bitmap:
			   					
			// Display and move every Sprite object.
			
			// Sort array first -- This allows smaller (= more distant) 
			// objects to be drawn first.
			if (spriteArray.length > 1)
				Sprite.sortArrayByZOrder(spriteArray);
			
			// We're working offscreen.
					
			// Erase and redraw objects off-screen.
			screen.erase();
			
			// Draw each object.
			for (int i = 0; i < spriteArray.length; i++) {                   
				spriteArray[i].draw(g);
				spriteArray[i].calcNextCoordinates();
			}                             
	
			// Now 'flip' screen -- copy offscreen content to visible screen.
			screen.flip();
	         
			try {
			   Thread.sleep(delayMS);            
			} catch (InterruptedException e) {
			}
		}
      
		// To here, we're exiting...
		// Change button to 'Start' for next run.
		startOrStopBtn.setLabel("Start");
	}      
   
	void startItem_ActionPerformed(java.awt.event.ActionEvent event) {
		if (isAnimating)
			return;
		startOrStop_ActionPerformed(event);   
	}      
	
	void stopItem_ActionPerformed(java.awt.event.ActionEvent event) {
		if (! isAnimating)
			return;
		startOrStop_ActionPerformed(event);
	}	   
   
	void startOrStop_ActionPerformed(java.awt.event.ActionEvent event) {
		// Start or stop animation.
		if (! isAnimating) {
			isAnimating = true;
			startOrStopBtn.setLabel("Stop");
		
			// Start our thread.
			animationThread = new Thread(this);
			animationThread.start();
		} else {
			isAnimating = false;
			// (This kills animation thread in run() method.)
			// This will also reset Start/Stop button to "Start."
		}		   
	}
	
	void numObjectsScroller_AdjustmentValueChanged(java.awt.event.AdjustmentEvent event) {
		// Change # of objects in text control--simulate spin control functionality.
		int newVal = numObjectsScroller.getValue();
		int actualVal = 201 - newVal;
		numObjects.setText("" + actualVal);
	}

	public AnimationDemo() {
		init();
		// INIT_MENUS
		fileMenu.setLabel("File");
		fileMenu.add(exitApp);
		exitApp.setLabel("Exit");
		menuBar1.add(fileMenu);
		optionsMenu.setLabel("Options");
		optionsMenu.add(startItem);
		startItem.setLabel("Start");
		optionsMenu.add(stopItem);
		stopItem.setLabel("Stop");
		menuBar1.add(optionsMenu);
		helpMenu.setLabel("Help");
		helpMenu.add(aboutItem);
		aboutItem.setLabel("About...");
		menuBar1.add(helpMenu);
		//$$ menuBar1.move(0, 450);
		setMenuBar(menuBar1);		
		setTitle("Animation Demo. -- Java");
	}
	
	/**
     * Shows or hides the component depending on the boolean flag b.
     * @param b  if true, show the component; otherwise, hide the component.
     * @see java.awt.Component#isVisible
     */
   public void setVisible(boolean b) {
		if (b)
			setLocation(50, 50);
		super.setVisible(b);
	}
	
	public void addNotify() {
		// Record the size of the window prior to calling parents addNotify.
		Dimension d = getSize();
		
		super.addNotify();
	
		if (fComponentsAdjusted)
			return;
	
		// Adjust components according to the insets
		setSize(getInsets().left + getInsets().right + d.width, 
				getInsets().top + getInsets().bottom + d.height);
		Component components[] = getComponents();
		for (int i = 0; i < components.length; i++) {
			Point p = components[i].getLocation();
			p.translate(getInsets().left, getInsets().top);
			components[i].setLocation(p);
		}
		fComponentsAdjusted = true;
	}
	
	// Used for addNotify check.
	boolean fComponentsAdjusted = false;

	class SymWindow extends java.awt.event.WindowAdapter {
		public void windowClosing(java.awt.event.WindowEvent event) {
			Object object = event.getSource();
			if (object == AnimationDemo.this)
				MainFrame_WindowClosing(event);
		}
	}
	
	void MainFrame_WindowClosing(java.awt.event.WindowEvent event) {
	   	setVisible(false);	// hide the Frame
		dispose();			// free the system resources
		System.exit(0);		// close the application
	}
	
	static public void main(String args[]) {
		try {
			//Create a new instance of our application's frame, and make it visible.
    		(new AnimationDemo()).setVisible(true);
		} catch (Throwable t) {
			System.err.println(t);
			t.printStackTrace();
			//Ensure the application exits with an error condition.
			System.exit(1);
		}
	}

	// Event handlers.
	void exitApp_ActionPerformed(java.awt.event.ActionEvent event) {
		// Exit this app.
		Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(new java.awt.event.WindowEvent(this, WindowEvent.WINDOW_CLOSING));
	}
	
	void aboutItem_ActionPerformed(java.awt.event.ActionEvent event) {
		// Show 'About' dialog box.
		AboutDlg dlg = new AboutDlg(this, true, "Animation Demo", "Animation Demo");
		// Show it.
		dlg.setVisible(true);
	}

}
