import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;  // MouseInputAdapter
import java.net.*;           // URL

/** A window frame that shows an image of UA Lecturer Rick Mercer.
  * The image is draggable by the mouse.
  * Intended as a demonstration of using Java MouseListeners and
  * MouseMotionListeners to monitor a panel.
  *
  * Written for University of Arizona's C SC 335 class, Fall 2000.
  * 
  * @author Martin Stepp
  */
public class ImageDraggerDemo {
	/** Runs ImageDraggerDemo, creating and showing a new frame. */
	public static void main(String[] args) {
		JFrame frame = new JFrame("Extreme programming in action!");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		// make a new RickPanel with scrollbars
		RickPanel rPanel = new RickPanel();
		JScrollPane scrollPane = new JScrollPane(rPanel);
		
		// lay out window
		JPanel contentPane = new JPanel(new BorderLayout());
		contentPane.add(scrollPane, BorderLayout.CENTER);
		frame.setContentPane(contentPane);
		
		// make window resize to be the "right" size
		frame.pack();
		frame.show();
	}
}


/** A panel that paints a draggable image. */
class RickPanel extends JPanel {
	private static final String IMAGE_URL_STRING = "http://www.cs.arizona.edu/people/mercer/rickm.jpg";
	private static final int MARGIN = 10;
	
	private Image rickImage = null;
	private Point topLeftPoint = null;
	private Dimension rickSize = null;
	
	public RickPanel() {
		// create and download the image of Rick
		Toolkit tk = Toolkit.getDefaultToolkit();
		MediaTracker mt = new MediaTracker(this);
		URL u = null;
		
		try {
			u  = new URL(IMAGE_URL_STRING);
		} catch (MalformedURLException e) {
			System.err.println("Can't get image! " + e);
		}
		
		rickImage = tk.getImage(u);
		mt.addImage(rickImage, 0);
		
		// using a MediaTracker, we are assured that the image
		// file has finished downloading before the panel appears
		// on the screen (unpredictable things happen otherwise)
		try {
			mt.waitForAll();
		} catch (InterruptedException e) {
			System.err.println("Can't waitForAll: " + e);
		}
		
		// store Rick image's size for efficiency
		rickSize = new Dimension(
			rickImage.getWidth(RickPanel.this),
			rickImage.getHeight(RickPanel.this)
		);
		
		// set this panel's size
		Dimension size = new Dimension(
			rickSize.width + 2*MARGIN,
			rickSize.height + 2*MARGIN
		);
		setPreferredSize(size);

		topLeftPoint = new Point();
		setRickLocation(MARGIN, MARGIN);
		
		// add a listener for mouse clicks and movement
		RickMouseDragger md = new RickMouseDragger();
		addMouseListener(md);
		addMouseMotionListener(md);
	}
	
	
	/** Paints this RickPanel on the screen. */
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.drawImage(rickImage, topLeftPoint.x, topLeftPoint.y, this);
	}
	
	
	/** Relocates image of Rick so that its upper-left corner is at (x, y) */
	public void setRickLocation(int x, int y) {
		topLeftPoint.x = x;
		topLeftPoint.y = y;
	}
	
	
	/** Listens for mouse input in a RickPanel.
	  * If the user clicks on the image in the panel, he may drag it
	  * around and its new position will be remembered.
	  * The panel will also resize itself to reflect this, possibly
	  * adding scrollbars.
	  */
	private class RickMouseDragger extends MouseInputAdapter {
		private Point dragPoint = null;
		private boolean iAmDraggingRick = false;
		
		
		/** Called when user presses down the mouse button. */
		public void mousePressed(MouseEvent event) {
			int x = event.getX();
			int y = event.getY();
			
			// if user clicked on Rick, start dragging
			if (topLeftPoint.x <= x  &&  x <= (topLeftPoint.x + rickSize.width)
			&&  topLeftPoint.y <= y  &&  y <= (topLeftPoint.y + rickSize.height))
			{
				dragPoint = event.getPoint();
				iAmDraggingRick = true;
			}
		}
		
		
		/** Called when user lifts up the mouse button. */
		public void mouseReleased(MouseEvent event) {
			// since user released the button, he's not dragging Rick any more
			dragPoint = null;
			iAmDraggingRick = false;
		}
		
		
		/** Called when the user moves the mouse while a button is held down. */
		public void mouseDragged(MouseEvent event) {
			// if user is dragging Rick, move his image's location
			if (iAmDraggingRick) {
				int newX = topLeftPoint.x + event.getX() - dragPoint.x;
				int newY = topLeftPoint.y + event.getY() - dragPoint.y;
				
				setRickLocation(newX, newY);
				dragPoint = event.getPoint();
				
				// resize the window based on Rick's new position
				int width = topLeftPoint.x + rickSize.width;
				int height = topLeftPoint.y + rickSize.height;

				setPreferredSize(new Dimension(width, height));
				revalidate();
				repaint();
			}
		}
	}
}