import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;

import javax.media.j3d.*;
import javax.vecmath.*;

/**
Solution to Lab 8 by Rod Harris
*/

public class Lab8b
{
	private MyVirtualUniverse vu = new MyVirtualUniverse();

	private Matrix4d t3dVals = new Matrix4d();

	private Random rnd = new Random();

	private double ds = 1;

	private double da = 0.1;

	private Transform3D rotateT3D = new Transform3D();

	private Transform3D viewT3D = new Transform3D();


	public static void main(String[] args)
	{
		new Lab8b();
	}


	public Lab8b()
	{
		ApplicationFrame appFrame = new ApplicationFrame("Lab 8 - Flying Saucer Movement Metaphor", 800, 600);
		appFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JPanel mainPanel	= new JPanel(new BorderLayout());
		JPanel southPanel	= new JPanel(new BorderLayout());
		JPanel buttonPanel	= new JPanel(new GridLayout(2,3));

		mainPanel.add(vu.getBoard(), BorderLayout.CENTER);
		mainPanel.add(southPanel, BorderLayout.SOUTH);
		southPanel.add(buttonPanel, (BorderLayout.CENTER));

		JLabel lbl = new JLabel("  Use cursor keys and page up / down keys to move saucer (click the canvas first to give it focus)  ");
		southPanel.add(lbl, BorderLayout.NORTH);

		buttonPanel.add(new JButton(new ButtonAction("Roll Left")));
		buttonPanel.add(new JButton(new ButtonAction("Pitch Up")));
		buttonPanel.add(new JButton(new ButtonAction("Roll Right")));
		buttonPanel.add(new JButton(new ButtonAction("Yaw Left")));
		buttonPanel.add(new JButton(new ButtonAction("Pitch Down")));
		buttonPanel.add(new JButton(new ButtonAction("Yaw Right")));


		appFrame.getContentPane().add(mainPanel);

		addContent();

		addNavigator();

		appFrame.setVisible(true);
	}


	public void addContent()
	{
		for (int x=-100; x<=100; x+=5)
		{
			for (int z=-100; z<=100; z+=5)
			{
				if (rnd.nextInt(100) <= 20)
				{
					addTree(x, z, 4, 1);
				}
			}
		}
	}


	public void addNavigator()
	{
		SaucerNavigator navigator = new SaucerNavigator();
		navigator.setSchedulingBounds(new BoundingSphere(new Point3d(0,0,0), Double.MAX_VALUE));
		BranchGroup bg = new BranchGroup();
		bg.addChild(navigator);
		vu.addBranchGraph(bg);
	}


	public void addTree(double x, double z, double height, double radius)
	{
		BranchGroup bg = new BranchGroup();

		TransformGroup tg = new TransformGroup();

		Transform3D t3d = new Transform3D();

		t3d.set(new Vector3d(x, -5, z));

		tg.setTransform(t3d);

		tg.addChild(new Tree(height, radius));

		bg.addChild(tg);

		vu.addBranchGraph(bg);
	}


	private void buttonPressed(String name)
	{
		if (name.equals("Pitch Up"))
		{
			rotateT3D.rotX(da);
			viewT3D.mul(rotateT3D);
			vu.getViewTG().setTransform(viewT3D);
		}
		else if (name.equals("Roll Left"))
		{
			rotateT3D.rotZ(da);
			viewT3D.mul(rotateT3D);
			vu.getViewTG().setTransform(viewT3D);
		}
		else if (name.equals("Roll Right"))
		{
			rotateT3D.rotZ(-da);
			viewT3D.mul(rotateT3D);
			vu.getViewTG().setTransform(viewT3D);
		}
		else if (name.equals("Yaw Left"))
		{
			rotateT3D.rotY(da);
			viewT3D.mul(rotateT3D);
			vu.getViewTG().setTransform(viewT3D);
		}
		else if (name.equals("Pitch Down"))
		{
			rotateT3D.rotX(-da);
			viewT3D.mul(rotateT3D);
			vu.getViewTG().setTransform(viewT3D);
		}
		else if (name.equals("Yaw Right"))
		{
			rotateT3D.rotY(-da);
			viewT3D.mul(rotateT3D);
			vu.getViewTG().setTransform(viewT3D);
		}
	}


	private void move(double dx, double dy, double dz)
	{
			viewT3D.get(t3dVals);

			double xpos = t3dVals.getElement(0,3);
			double ypos = t3dVals.getElement(1,3);
			double zpos = t3dVals.getElement(2,3);

			double ix = t3dVals.getElement(0,0);
			double iy = t3dVals.getElement(1,0);
			double iz = t3dVals.getElement(2,0);

			double jx = t3dVals.getElement(0,1);
			double jy = t3dVals.getElement(1,1);
			double jz = t3dVals.getElement(2,1);

			double kx = t3dVals.getElement(0,2);
			double ky = t3dVals.getElement(1,2);
			double kz = t3dVals.getElement(2,2);

			xpos += dx*ix + dy*jx + dz*kx;
			ypos += dx*iy + dy*jy + dz*ky;
			zpos += dx*iz + dy*jz + dz*kz;

 			t3dVals.setElement(0,3,xpos);
 			t3dVals.setElement(1,3,ypos);
 			t3dVals.setElement(2,3,zpos);

			viewT3D.set(t3dVals);
			vu.getViewTG().setTransform(viewT3D);
	}

	private class ButtonAction extends AbstractAction
	{
		public ButtonAction(String s)
		{
			super(s);
			name = s;
		}
		public void actionPerformed(ActionEvent e)
		{
			buttonPressed(name);
		}
		private String name;
	}

	private class SaucerNavigator extends Behavior
	{
		private WakeupOnAWTEvent w = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);

		public void initialize()
		{
			wakeupOn(w);
		}
		public void processStimulus(Enumeration criteria)
		{
			WakeupOnAWTEvent awtevent = (WakeupOnAWTEvent) criteria.nextElement();

			AWTEvent[] events = awtevent.getAWTEvent();

			for (int i=0; i<events.length; i++)
			{
				if (events[i] instanceof KeyEvent)
				{
					KeyEvent keyEvent = (KeyEvent) events[i];

					if (keyEvent.getKeyCode() == KeyEvent.VK_UP)
					{
						move(0,0,-ds);
					}
					else if (keyEvent.getKeyCode() == KeyEvent.VK_DOWN)
					{
						move(0,0,ds);
					}
					else if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT)
					{
						move(-ds,0,0);
					}
					else if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT)
					{
						move(ds,0,0);
					}
					else if (keyEvent.getKeyCode() == KeyEvent.VK_PAGE_UP)
					{
						move(0,ds,0);
					}
					else if (keyEvent.getKeyCode() == KeyEvent.VK_PAGE_DOWN)
					{
						move(0,-ds,0);
					}
				}
			}
			wakeupOn(w);
		}
	}
}
