/*
 * @(#)DrawingJPanel.java
 *
 * Last Modified: 9/15/01
 */
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.beans.*;

/**
 * A specific type of JPanel for the dedicated purpose of drawing some sort of node or tree onto
 * the panel. Everything within the class is implemented except the <code>draw</code> method. This
 * must be implemented by extending class to activate the drawing.
 *
 * <p>
 * @author  Corey Sanders
 * @version 1.3 9/15/01
 */
public class DrawingJPanel extends JPanel implements ComponentListener{

	/**
	 * Image of the Panel for drawing the tree onto. (Used so redrawing is not necessary.
	 */
	private BufferedImage drawTreeImage;

	/**
	 * Graphics associate with the image of the Panel. (Used so redrawing is not necessary.
	 */
	private Graphics2D drawTreeGraphics;

	/**
	 * Boolean flag whether the tree needs to be redrawn.
	 */
    private boolean drawTree = true;

	/**
	 * Rectangle which represents the drawing area of the panel.
	 */
    private Rectangle drawingArea;

	/**
	 * Flag whether the tree is shown or not.
	 */
	private boolean componentShown = false;


	/**
	 * Sole Constructor for the JPanel that draws. The super constructor is called. Additionally, the
	 * default background is set as white and the comoponent adds it to listen to itself.
	 */
	public DrawingJPanel() {
		super();
		setBackground(Color.white);
		this.addComponentListener(this);

    }


	/**
 	 ********************
	 * Accesssor methods*
	 ********************
	 */

	/**
	 * Gets the draw Tree Image for this panel.
	 *
	 * @return BufferedImage set as the drawing image.
	 */
	 public BufferedImage getDrawTreeImage() {
		 return drawTreeImage;
	 }

	/**
	 * Gets the draw Tree Graphics for this panel.
	 *
	 * @return Graphics2D set as the drawing graphics.
	 */
	 public Graphics2D getDrawTreeGraphics() {
		 return drawTreeGraphics;
	 }


	/**
	 * Gets whether the tree needs to be redrawn.
	 *
	 * @param true if the tree needs drawing.
	 */
	public boolean isDrawTree() {
		return drawTree;
	}


	/**
	 * Sets whether the tree is shown or not.
	 *
	 * @return boolean flag as to whether the tree is shown.
	 */
	public boolean isComponentShown() {
		return componentShown;
	}

	/**
	 * Gets the drawing area for this panel.
	 *
	 * @return Rectangle2D rectangle set as the drawing area.
	 */
	 public Rectangle2D getDrawingArea() {
		 return drawingArea;
	 }


	/**
 	 *******************
	 * Mutator methods *
	 *******************
	 */


	/**
	 * Sets the draw Tree Image for this panel.
	 *
	 * @param drawTreeImage BufferedImage set as the drawing image.
	 */
	 protected void setDrawTreeImage(BufferedImage drawTreeImage) {
		 this.drawTreeImage = drawTreeImage;
	 }

	/**
	 * Sets the draw Tree graphics for this panel.
	 *
	 * @param drawTreeImage Graphics2D set as the drawing graphics.
	 */
	 protected void setDrawTreeGraphics(Graphics2D drawTreeGraphics) {
		 this.drawTreeGraphics = drawTreeGraphics;
	 }

	/**
	 * Sets whether the tree needs drawing.
	 *
	 * @param animating boolean flag as to whether the tree needs drawing.
	 */
	public void setDrawTree(boolean drawTree) {
		this.drawTree = drawTree;
	}

	/**
	 * Sets whether the tree is shown or not.
	 *
	 * @param componentShown boolean flag as to whether the tree is shown.
	 */
	public void setComponentShown(boolean componentShown) {
		this.componentShown = componentShown;

	}

   	/**
	 * Sets the drawing area for this panel. Keeps the Rectangle for usage in drawing.
	 *
	 * @param drawingArea Rectangle2D rectangle set as the drawing area.
	 */
	 protected void setDrawingArea(Rectangle drawingArea) {
		 this.drawingArea = drawingArea;
	 }


	/**
 	 *******************
	 * Drawing methods *
	 *******************
	 */


	/**
	 * Method actually called to complete the drawing of the panel. WIthin this class, the method is
	 * empty. It must be overiden for anything to be drawn in the call.
	 */
	protected void draw() {

	}


	/**
	 * Makes the drawing image. An image is used because the tree might not always
	 * need to be redrawn, saving time.
	 */
    protected void makeDrawTreeImage() {
		Dimension dim = getSize();
		int w = dim.width;
		int h = dim.height;

		if (w <= 0 || h <= 0) {
			return;
		}

		setDrawingArea(new Rectangle(dim));

		setDrawTreeImage((BufferedImage)createImage(w,h));

		setDrawTreeGraphics((Graphics2D)getDrawTreeImage().createGraphics());

		makeDrawTreeGraphics();

	}

	/**
	 * Makes the drawing graphics. Uses the image made from makeDrawTreeImage.
	 */
	 protected void makeDrawTreeGraphics() {

		if (getDrawTreeGraphics() == null) {
			return;
		}

		Dimension dim = getSize();
		int w = dim.width;
		int h = dim.height;



		getDrawTreeGraphics().setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

		getDrawTreeGraphics().setClip(0, 0, w, h);

		setDrawTree(true);

		repaint();
	}

	/**
	 * Draws onto the defined draw tree graphic.
	 * This method is the only call to the <code>draw</code> method.
	 */
	protected void drawTree() {

		if (getDrawTreeGraphics() == null) {
			return;
		}

		getDrawTreeGraphics().setBackground(getBackground());
		getDrawTreeGraphics().clearRect(0,0,(int)drawingArea.getWidth(), (int)drawingArea.getHeight());

		draw();

		setDrawTree(false);

	}


	/**
	 * Draws the JPanel. This overides the paintComponent of JPanel,
	 * to draw the appropriate image and redraw the graphic if necessary. The drawing is double buffered automatically, but
	 * the image is only modified on resizing and a change of node. Therefore, dragging, hiding
	 * and so forth, do not change the image.
	 *
	 * @param g Graphics used to draw to the component.
	 */
	public void paintComponent(Graphics g) {
		// Cast to 2D
		Graphics2D g2 = (Graphics2D)g;

		Dimension dim = getSize();
		int w = dim.width;
		int h = dim.height;


		if (isDrawTree()) {
			drawTree();
		}

		// Set Graphics clip
		g2.setClip(0,0,w,h);
		// Draws the image
		g2.drawImage(getDrawTreeImage(), 0, 0, this);

	}

	/****************************************/
	/* Component Listener Interface Methods */
	/****************************************/

	/**
	 * Called when the component is hidden. Sets the componentShown as false.
	 *
	 * @param e ComponentEvent not used for this particular listening.
	 *
	 */
	public void componentHidden(ComponentEvent e) {
		setComponentShown(false);
	}

	/**
	 * Called when the component is Moved. No action occurs here.
	 *
	 * @param e ComponentEvent not used for this particular listening.
	 *
	 */
	public void componentMoved(ComponentEvent e) {
	}

	/**
	 * Called when the component is Shown. Sets the componentShown as true.
	 *
	 * @param e ComponentEvent not used for this particular listening.
	 *
	 */
	public void componentShown(ComponentEvent e) {
		setComponentShown(true);
	}

	/**
	 * Called when the component is Resized. The image is modified according
	 * to the resizing of the Component.
	 *
	 * @param e ComponentEvent not used for this particular listening.
	 */
	public void componentResized(ComponentEvent e) {
		// make the image if it is null
		if(getDrawTreeImage() == null) {
			makeDrawTreeImage();
			return;
		}

		Dimension dim = getSize();

		int w = dim.width;
		int h = dim.height;

		// If the image is too small.
		if ((w > getDrawTreeImage().getWidth()) || (h > getDrawTreeImage().getHeight())) {
			// Remove old image
			getDrawTreeImage().flush();

			// Make a new image
			makeDrawTreeImage();
		}
		else {
			// Reset drawing area
			setDrawingArea(new Rectangle(dim));

			// Reset Graphics
			makeDrawTreeGraphics();
		}

		// Reset drawing of tree
		setDrawTree(true);


		repaint();
	}

}

