/**
 * This applet will demonstrate projectile motion
 * by displaying a cannon firing.
 * by Drew Dolgert for Dr. Michael Fowler of UVa, mf1i@virginia.edu
 * Copyright (C) Michael Fowler 1998 under Gnu Public License
 * http://www.gnu.org/copyleft/gpl.html
 **/

import java.applet.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;

// The applet is the nerve center for the panels it displays.  It creates an object to
// calculate projectile locations, then connects inputs to it and an output.
// When the applet says it implements a Listener, it promises to include routines
// other objects can call when an event happens.
//
// The applet itself doesn't care about redrawing or sizes.  Each contained component will
// redraw itself.
public class ProjectileApplet extends Applet implements
				ActionListener, BuddyBar.BuddyListener, ItemListener {
	Projectile bullet; // This calculates the current position.
	PositionGraph arcs; // This is a Panel that displays the current position.
	BuddyBar velocityBuddy; // A buddy bar is a home grown component with label, textField, and Scrollbar.
	BuddyBar angleBuddy;
	BuddyBar massBuddy;
	Checkbox airCheckBox;
	Checkbox trailCheckBox;

	// init is called by the browser to initialize the applet.
	public void init() {
		ResourceBundle rb;
        String sResString, sUnitString;
        
		String sUseRB = this.getParameter("international");
		rb = null;
		if ((sUseRB == null) || !sUseRB.equalsIgnoreCase("no")) {
			String sLang = this.getParameter("language");
			String sCountry = this.getParameter("country");
			try {
				try {
					if (sLang == null) {
						rb = ResourceBundle.getBundle("ProjectileStrings",Locale.getDefault());
					} else {
						Locale thisloc;
						if (sCountry == null)
							thisloc = new Locale(sLang,"");
						else
							thisloc = new Locale(sLang,sCountry);
						rb = ResourceBundle.getBundle("ProjectileStrings",thisloc);
					}
				} catch (java.lang.ClassFormatError e) {
					System.out.println("Cannot load the ResourceBundle class.  Must be Netscape.");
					System.out.println("Turning off Internationalization.  Sorry.");
					rb = null;
				}
			} catch (MissingResourceException e) {
				System.out.println(e.getMessage());
				rb = null;
			}
		}
		// A border layout allows you to add panels to the north, south, center, etc.
		this.setLayout(new BorderLayout(5,5));
		this.setBackground(Color.white);

		// Create the position calculator.
		bullet = new Projectile();
		// Create a display panel that reads info from
		// the bullet.  Because a PositionGraph is a Panel,
		// it can be added to the Applet.
		arcs = new PositionGraph(bullet, rb);
		// add()ing a Panel places it visually in the applet window.
		// Center is just that, the center of the window.
		this.add("Center",arcs);

		// The p1 panel will contain the button and checkboxes.
		// It gets its own layout.  Then the whole panel will be added
		// to the applet.
		Panel p1 = new Panel(new FlowLayout(FlowLayout.RIGHT));
        if (rb != null) sResString = rb.getString("fire");
        else sResString = "Fire";
		Button b = new Button(sResString);
		b.setActionCommand("fire");
		// Here is the first Listener command.  "this" is a pointer to the applet itself.
		// By asking button b to add us as an ActionListener, we ask it to call us when
		// something happens.  It does that by calling the method that we, as ActionListeners,
		// promise to have, the actionPerformed method you will see below.  All the listener
		// interfaces work this way.
		b.addActionListener(this);

        if (rb != null) sResString = rb.getString("air");
        else sResString = "air resistance";
		airCheckBox = new Checkbox(sResString,false);
        if (rb != null) sResString = rb.getString("trails");
        else sResString = "show trails";
		trailCheckBox = new Checkbox(sResString,true);
		airCheckBox.addItemListener(this);
		trailCheckBox.addItemListener(this);
		p1.add(airCheckBox);
		p1.add(trailCheckBox);

		// This will hold four objects pushed to the bottom of the applet window.
		// Here is who contains whom.
		// applet - PositionGraph
		//        - panel3 (gridBag)  - panel1 (flowlayout) - checkbox
		//                                                  - checkbox
		//                            - button
		//                            - 3 velocityBuddy pieces
		//                            - 3 angleBuddy pieces
		//                            - 3 massBuddy pieces

		// Arguments are the min and max double values on the scrollbar,
		// the min and max double values you are allowed to enter by hand
		// in the textBox, and lastly the initial setting for both.
        if (rb != null) sResString = rb.getString("velocity");
        else sResString = "Velocity [m/s]";
		velocityBuddy = new BuddyBar(sResString,1,100,0,1000,50);

		// This listener isn't the same as the others.  I rolled my own b/c I
		// made a new buddyBar object, and it doesn't need to be fancy.  It works
		// pretty much the same way as the other listeners, though.
		velocityBuddy.addBuddyListener(this);
		
        if (rb != null) sResString = rb.getString("angle");
        else sResString = "Angle [degrees]";
		angleBuddy = new BuddyBar(sResString,0,90,0,90,70);
		angleBuddy.addBuddyListener(this);

        if (rb != null) sResString = rb.getString("mass");
        else sResString = "Mass [kg]";
		massBuddy = new BuddyBar(sResString,1,20,1,1000,10);
		massBuddy.addBuddyListener(this);

		Panel p3 = new Panel(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.insets = new Insets(4,4,4,4);
		c.gridx = 0; c.gridy = 0; c.gridwidth = 3; c.gridheight = 1;
		c.weighty = 0; c.weightx = 0;
		c.anchor = GridBagConstraints.CENTER;
		c.fill = GridBagConstraints.HORIZONTAL;
		p3.add(p1,c);
		c.gridwidth = 1; c.gridx = 3;
		c.fill = GridBagConstraints.HORIZONTAL;
		p3.add(b,c);
		c.fill = GridBagConstraints.NONE;
		c.anchor = GridBagConstraints.EAST;
		c.gridx = 0; c.gridy = 1;
		p3.add(velocityBuddy.getLabel(),c);
		c.anchor = GridBagConstraints.CENTER;
		c.gridx = 1;
		p3.add(velocityBuddy.getTextField(),c);
		c.anchor = GridBagConstraints.EAST;
		c.gridx=0; c.gridy = 2;
		p3.add(angleBuddy.getLabel(),c);
		c.anchor = GridBagConstraints.CENTER;
		c.gridx = 1;
		p3.add(angleBuddy.getTextField(),c);
		c.anchor = GridBagConstraints.EAST;
		c.gridx=0; c.gridy = 3;
		p3.add(massBuddy.getLabel(),c);
		c.anchor = GridBagConstraints.CENTER;
		c.gridx = 1;
		p3.add(massBuddy.getTextField(),c);
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridwidth=2;
		c.gridx = 2; c.gridy = 1; c.weightx = 1;
		p3.add(velocityBuddy.getScrollbar(),c);
		c.gridy = 2;
		p3.add(angleBuddy.getScrollbar(),c);
		c.gridy = 3;
		p3.add(massBuddy.getScrollbar(),c);

		this.add("South",p3);

        String sParam = this.getParameter("threadsleep");
        if (sParam != null) {
            try {
                int iSleep = Integer.parseInt(sParam);
                bullet.setSleepTime(iSleep);
			} catch (NumberFormatException e) {
			    System.out.println("threadsleep should be an integer number of milliseconds.");
			}
        }
        sParam = this.getParameter("numsteps");
        if (sParam != null) {
            try {
                int nSteps = Integer.parseInt(sParam);
                bullet.setNumSteps(nSteps);
			} catch (NumberFormatException e) {
			    System.out.println("numsteps should be an integer number of timesteps.");
			}
        }

        sParam = this.getParameter("markfrequency");
        if (sParam != null) {
            try {
                int nSteps = Integer.parseInt(sParam);
                bullet.setMarkFrequency(nSteps);
			} catch (NumberFormatException e) {
			    System.out.println("markfrequency should be an integer like 5 or 10.");
			}
        }
	}

	public String getAppletInfo() {
		return "ProjectileApplet v. 1.0.  Written by Drew Dolgert for Dr. Michael Fowler.\n"+
		"Copyright (C) Michael Fowler mf1i@virginia.edu 1998\n"+
		"Under Gnu Public License http://www.gnu.org/copyleft/gpl.html";
	}
	static final String[][] parameterInfo = {
			{"international","yes or no [yes]", "Setting this to \"no\" turns off internationalization "+
					"in case your browser cannot handle it."},
			{"language","two letter language code", "EN for English, FR for French, etc."},
			{"country","two letter country code", "CN for China, IT for Italy.  Not required."},
			{"threadsleep","integer [20]","Number of milliseconds the gas thread should sleep."},
			{"markfrequency","integer [8]","How many timesteps per trail mark."},
			{"numsteps","integer [125]","Number of timesteps for the ball to travel the "+
			        "a full arc."}
		};
		
	public String[][] getParameterInfo() {
		return parameterInfo;
	}

	// This is called when someone clicks on a button.  We listen to the only button
	// we have, which is the fire button.  All info gets passed on to the projectile.
	public void actionPerformed(ActionEvent e) {
		bullet.setVelocity(velocityBuddy.getValue());
		bullet.setAngle(angleBuddy.getValue()*Math.PI/180);
		bullet.setMass(massBuddy.getValue());
		bullet.fire();
	}

	// This is my imitation of a listener method.  When the buddy bar changed, this
	// gets called with the current value of that bar.  Note we need to search through
	// our buddy bars to see which one it is.  When we get the info, we pass it on to
	// the Projectile calculator.
	public void buddyValueChanged(BuddyBar changer, double dVal)
	{
		if (changer==velocityBuddy) {
			bullet.setVelocity(dVal);
		} else if (changer == angleBuddy) {
			bullet.setAngle(dVal*Math.PI/180);
		} else if (changer == massBuddy) {
			bullet.setMass(dVal);
		}
	}

	// This is a standard listener for checkboxes.  Info here is passed on to the projectile.
	// Note I could make a slider for the projectile resistance if I wanted.
	public void itemStateChanged(ItemEvent evt) {
		if (airCheckBox == evt.getSource()) {
			if (airCheckBox.getState())
				bullet.setResistance(0.5);
			else
				bullet.setResistance(0.0);
		} else {
			if (trailCheckBox.getState())
				arcs.setTrails(true);
			else
				arcs.setTrails(false);
		}
	}

}

