package ps1;

import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.Color;
import java.applet.Applet;
import java.applet.AppletStub;
import java.applet.AppletContext;
import java.applet.AudioClip;

import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;

import java.net.URL;
import java.net.MalformedURLException;
import java.util.Enumeration;
import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.Panel;
import java.awt.Button;
import java.awt.TextArea;
import java.awt.Label;

import Raster;
import Util;

class ps1Applet extends Applet {
	boolean debug;	//true to output debugging information
	
	Background background;
	Sprite currentSelectedSprite;

	//To handle drawing and rendering of BG
	Panel statusBar;
	Panel theField;
	Button debugButton;
	TextArea theLog;
	Label theLocationBar;
	Point offset;
	//

	//To handle drag and click
	boolean clickedAndHeld;

	//----------------------------------- Constructors -----------------------------------
	public ps1Applet () {
		currentSelectedSprite = null;
		background = null;
		clickedAndHeld = false;

		statusBar = new Panel();
		theField = new Panel();
		theLocationBar = new Label();
		debugButton = new Button("Clean");
		theLog = new TextArea(3, 40);

		statusBar.setLayout(new BorderLayout());
		theField.setLayout(new FlowLayout());

		statusBar.add("North", theLocationBar);
		statusBar.add("East", theLog);
		theField.add(debugButton);

		debuggingInit(true);

		add(theField);
		add(statusBar);

		debugButton.addActionListener(new ActionListener () {
			public void actionPerformed (ActionEvent e) {
				if (e.getActionCommand().equalsIgnoreCase("debug")) {
					debuggingInit(true);
					debugButton.setLabel("Clean");
				}
				
				if (e.getActionCommand().equalsIgnoreCase("clean")) {
					debuggingInit(false);
					debugButton.setLabel("Debug");
				}
			}
		});

		addMouseListener(new MouseAdapter () {
			public void mouseClicked (MouseEvent e) {
				
			}

			public void mousePressed (MouseEvent e) {
				try {
					selectSprite(e);
				} catch (NoSpriteLocatableException ee) {
					//setting to null enables drag/drop movement
					currentSelectedSprite = null;
					//enabling allows the point, click & move sprite
					//moveSprite(new Point(e.getX(), e.getY()));
				}

				clickedAndHeld = true;
			}

			public void mouseReleased (MouseEvent e) {
				clickedAndHeld = false;
			}
		});
		
		addMouseMotionListener(new MouseMotionAdapter () {
			public void mouseMoved (MouseEvent e) {
				outputToLocationBar("(" + e.getX() + ", " + e.getY() + ")");
			}

			public void mouseDragged (MouseEvent e) {
				Point currentPosition = new Point(e.getX(), e.getY());
				
				if ((currentSelectedSprite != null) && clickedAndHeld)
					moveSprite(currentPosition);

				outputToLocationBar("(" + e.getX() + ", " + e.getY() + ")");
			}
		});
	}

	//-------------------------------------- Methods -------------------------------------
	public void init () {
		Sprite sprite1;
		Sprite sprite2;
		AnimatedSprite sprite3;
		Sprite sprite4;

		try {
			URL path0 = new URL(getCodeBase(), "DILBERT.GIF");
			URL path1 = new URL(getCodeBase(), "MONKEY1.GIF");
			URL path2 = new URL(getCodeBase(), "MONKEY2.GIF");
			URL path3 = new URL(getCodeBase(), "MONKEY3.GIF");
			URL path4 = new URL(getCodeBase(), "MONKEY4.GIF");
			URL path5 = new URL(getCodeBase(), "MONKEY5.GIF");
			URL path6 = new URL(getCodeBase(), "MONKEY6.GIF");
			URL path7 = new URL(getCodeBase(), "MONKEY7.GIF");
			URL path8 = new URL(getCodeBase(), "WORLD.GIF");
			URL path9 = new URL(getCodeBase(), "ANT.GIF");

			Image image0 = getImage(path0);
			Util.waitForImage(this, image0);

			Image image1 = getImage(path1);
			Util.waitForImage(this, image1);
			
			Image image2 = getImage(path2);
			Util.waitForImage(this, image2);
			
			Image image3 = getImage(path3);
			Util.waitForImage(this, image3);

			Image image4 = getImage(path4);
			Util.waitForImage(this, image4);

			Image image5 = getImage(path5);
			Util.waitForImage(this, image5);
			
			Image image6 = getImage(path6);
			Util.waitForImage(this, image6);
			
			Image image7 = getImage(path7);
			Util.waitForImage(this, image7);

			Image image8 = getImage(path8);
			Util.waitForImage(this, image8);
			
			Image image9 = getImage(path9);
			Util.waitForImage(this, image9);

			setBackground(Color.lightGray);
			background = new Background(image0);
			sprite1 = new Sprite(image8, Color.lightGray.getRGB());
			sprite2 = new Sprite(image1, Color.lightGray.getRGB());
			sprite4 = new Sprite(image9, Color.lightGray.getRGB());

			background.addSprite(sprite1);
			background.addSprite(sprite2);
			background.addSprite(sprite4);

			sprite1.setLocation(new Point(220, 90));
			background.draw();
			sprite2.setLocation(new Point(460, 90));			
			background.draw();
			sprite4.setLocation(new Point(60, 80));			
			background.draw();

			currentSelectedSprite = sprite1;	//always have a default selected
		} catch (MalformedURLException e) {
			System.err.println("Bad URL");
		}
	}

	public void start () {
	}

	public void paint (Graphics g) {
		Image theBackground = background.toImage();
		Util.waitForImage(this, theBackground);
		
		g.drawImage(theBackground, offset.x, offset.y, this);

		outputSavedBG();
		outputToStatus("Painted.");
	}

	public void update(Graphics g) {
		paint(g);
	}

	public void renderSpritesOnBG () {
		background.toTopOfZOrder(currentSelectedSprite);
		background.draw();
		repaint();
	}

	public void selectSprite (MouseEvent e) 
		throws NoSpriteLocatableException {

		currentSelectedSprite = background.getSpriteAtLocation(
			new Point(e.getX() - offset.x, e.getY() - offset.y));
		renderSpritesOnBG();
		//for debugging				
		outputToStatus("Selected sprite of dimension (" + 
			currentSelectedSprite.getWidth() + ", " + 
			currentSelectedSprite.getHeight() + ").");
		outputToLocationBar("(" + e.getX() + ", " + e.getY() + ").");
		outputSavedBG();
	}
	
	public void moveSprite (Point pt) {
		if (currentSelectedSprite != null) {	//making a sprite go somewhere
			currentSelectedSprite.setLocation(
				new Point(pt.x - offset.x - (int)(currentSelectedSprite.getWidth() / 2),
				pt.y - offset.y - (int)(currentSelectedSprite.getHeight() / 2)));
			renderSpritesOnBG();
			//for debugging				
			outputToStatus("Moved sprite of dimension (" + 
				currentSelectedSprite.getWidth() + ", " + 
				currentSelectedSprite.getHeight() + ").");
			outputToLocationBar("(" + pt.x + ", " + pt.y + ").");
			
			return;
		}
		//for debugging				
		outputToStatus("No sprite is selected.");
	}
	//--------------------------------- START DEBUGGING ----------------------------------
	public void outputToStatus (String statusInfo) {
		if (debug) {
			System.out.println(statusInfo);
			theLog.append(statusInfo + "\n");
			theLog.repaint();
		}
	}

	public void outputToLocationBar (String statusInfo) {
		if (debug) {
			System.out.println(statusInfo);
			theLocationBar.setText(statusInfo);
			theLocationBar.repaint();
		}
	}

	public void outputSavedBG () {
		if (debug) {
			Graphics g = getGraphics();
			Image theSavedBackground = 
				((Raster)currentSelectedSprite.getSavedBackground()).toImage();
			Util.waitForImage(this, theSavedBackground);
			g.setColor(getBackground());
			g.fillRect(0, 0, currentSelectedSprite.getWidth() + 2, 
				currentSelectedSprite.getHeight() + 2);
			g.drawRect(0, 0, 
				((Raster)currentSelectedSprite.getSavedBackground()).getWidth() + 2,
				((Raster)currentSelectedSprite.getSavedBackground()).getHeight() + 2);
			g.drawImage(theSavedBackground, 1, 1, this);
		}
	}

	public void debuggingInit (boolean bDebug) {
		debug = bDebug;

		if (bDebug) {
			offset = new Point(0, 220);
			statusBar.setVisible(true);
			resize(600, 480);
		} else {
			offset = new Point(0, 0);
			statusBar.setVisible(false);
			resize(600, 220);
		}

		invalidate();
		repaint();
	}
	//---------------------------------- END DEBUGGING -----------------------------------
	public static void main (String args[]) {
		ps1Application application = new ps1Application("6.837 Problem Set 1");
		application.repaint();
	}
}

class ps1Application extends Frame implements AppletStub, AppletContext {
	public ps1Application (String title) {
		super(title);

		ps1Applet ps1 = new ps1Applet();
		ps1.resize(600, 480);
		setSize(600, 480);
		setLayout(new BorderLayout());
		ps1.setLayout(new BorderLayout());
		add("Center", ps1);
		ps1.setStub(this);
		ps1.init();
		show();
		ps1.start();

		addWindowListener(new WindowAdapter () {
			public void windowClosing (WindowEvent e) {
				dispose();
				System.exit(0);
			}
		});
	}

	public boolean isActive () {return (true);}
	public URL getDocumentBase () {return (null);}
	public URL getCodeBase () {return (null);}
	public String getParameter (String name) {return ("");}
	public AppletContext getAppletContext () {return (this);}
	public void appletResize (int width, int height) {}

	public AudioClip getAudioClip (URL url) {return (null);}
	public Image getImage (URL url) {return (null);}
	public Applet getApplet (String name) {return (null);}
	public Enumeration getApplets() {return (null);}
	public void showDocument(URL url) {}
	public void showDocument (URL url, String target) {}
	public void showStatus (String status) {}
}
