/*
 * Course:       CSCI 215
 * Title:        Lab 1
 * Description:  DrawPad
 * Author:       Yu Chong
 * Copyright (c)2001 Yu Chong.  All Rights Reserved.
 */

import java.util.Vector;
import java.awt.Graphics;
import java.awt.Color;

/**
 * CLASS:    DrawPadDoc<BR>
 * PURPOSE:  This class keep track of all the shapes and provide methods to
 *           manipulate them<BR>
 * IMPORT:   java.awt.Graphics, java.util.Vector, java.awt.Color, DrawableShape,
 *           Point<BR>
 * EXPORT:   New Class|DrawPadDoc<BR>New Method|DrawPadDoc, addShape,
 *           copySelectedShape, deleteSelectedShape, drawAllShapes,
 *           getSelectedShapeColor, moveSelectedPointBox, moveSelectedShapeToBack,
 *           moveSelectedShapeToFront, moveShape, pasteShape, selectNextShape,
 *           selectPointBox, selectedPreviousShape, selectShape,
 *           setSelectedShapeColor, setShapeEndPoint, unSelectShape<BR>
 */
public class DrawPadDoc
{
  //Private Attributes
  /** A vector list containing shapes*/
  private Vector shapeList;
  /** The shape that is being selected*/
  private DrawableShape selectedShape=null;
  /** A copied of a shape */
  private DrawableShape copyShape=null;
  /** A flag to indicate if we have selected a point box in the selected shape*/
  private boolean bSelectedPointBox=false;

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Construct and initialize the DrawPadDoc Object<BR>
   */
  public DrawPadDoc()
  {
    shapeList = new Vector();
    selectedShape=null;
  }

  /** <BR>
   *  PRE:  A valid DrawableShape object<BR>
   *  POST: Add a shape to the list<BR>
   */
  public void addShape(DrawableShape shape)
  {
    shapeList.addElement(shape.copyClone());
  }

  /** <BR>
   *  PRE:  A valid Graphics object<BR>
   *  POST: Draw all the shape in the list. First one put in the list,
   *        first one get drawn first<BR>
   */
  public void drawAllShapes(Graphics g)
  {
    for(int i = 0; i <shapeList.size(); i++)
    {
      ((DrawableShape)shapeList.elementAt(i)).paint(g);
    }
  }

  /** <BR>
   *  PRE:  A valid point<BR>
   *  POST: Go through the shape list from the top(LIFO) and do hit test on the
   *        shape.  If a shape if found to be hit, the shape will be saved and
   *        return true.  If no shape pass the hit test, return false<BR>
   */
  public boolean selectShape(Point p)
  {
    for(int i = shapeList.size() -1; i >=0; i--)
    {
      if(((DrawableShape)shapeList.elementAt(i)).hitTest(p) == true)
      {
        selectedShape = ((DrawableShape)shapeList.elementAt(i));
        selectedShape.setSelected(true);
        return true;
      }
    }
    return false;
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Don't keep track of the selected object<BR>
   */
  public void unSelectShape()
  {
    if(selectedShape!=null)
    {
      selectedShape.setSelected(false);
      bSelectedPointBox=false;
      selectedShape = null;
    }
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Move the selected Shape of the input offsets<BR>
   */
  public void moveShape(int deltaX, int deltaY)
  {
    if(selectedShape!=null)
    {
      selectedShape.move(deltaX, deltaY);
    }
  }

  /** <BR>
   *  PRE:  A valid Point object<BR>
   *  POST: Set the endPoint of the select shape as the input, solely for
   *        Resizing<BR>
   */
  public void setShapeEndPoint(Point p)
  {
    if(selectedShape!=null)
    {
      selectedShape.setEndPoint(p);
    }
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Delete the selected shape from the list if there is one selected<BR>
   */
  public void deleteSelectedShape()
  {
    if(selectedShape!=null)
    {
      shapeList.removeElement(selectedShape);
      unSelectShape();
    }
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Check if the point in the pointbox of the selecetd shape. Will set a
   *        boolean flag accordingly<BR>
   */
  public boolean selectPointBox(Point pt)
  {
    for(int i = shapeList.size() -1; i >=0; i--)
    {
      if(((DrawableShape)shapeList.elementAt(i)).hitTestPointBox(pt) == true)
      {
        bSelectedPointBox = true;
        return true;
      }
    }
    return false;
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Move the point box of the selected shape object<BR>
   */
  public void moveSelectedPointBox(int deltaX, int deltaY)
  {
    if(selectedShape!=null)
    {
      selectedShape.movePointBox(deltaX, deltaY);
    }
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Move the selected shape one object to the front.  Stay in the front
   *        if it is the front most already.<BR>
   */
  public void moveSelectedShapeToFront()
  {
    if(selectedShape!=null)
    {
      int index = shapeList.indexOf(selectedShape);
      if(index<shapeList.size()-1)
      {
        shapeList.removeElement(selectedShape);
        shapeList.insertElementAt(selectedShape, index+1);
      }
    }
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Move the selected shape one object to the back.  Stay in the back
   *        if it is the back most already.<BR>
   */
  public void moveSelectedShapeToBack()
  {
    if(selectedShape!=null)
    {
      int index = shapeList.indexOf(selectedShape);
      if(index>0)
      {
        shapeList.removeElement(selectedShape);
        shapeList.insertElementAt(selectedShape, index-1);
      }
    }
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Select the next shape in the list.  Select the same shape if it is
   *        already the last in the list.  If no selected shape before calling
   *        this method, it will choose the first one in the list
   *        (if a shape exist in the list)<BR>
   */
  public boolean selectNextShape()
  {
    if(shapeList.size()>0)
    {
      if(selectedShape==null)
      {
        selectedShape = (DrawableShape)shapeList.firstElement();
        selectedShape.setSelected(true);
        return true;
      }
      else
      {
        int index = shapeList.indexOf(selectedShape);
        if(index < (shapeList.size()-1))
        {
          unSelectShape();
          selectedShape = (DrawableShape)shapeList.elementAt(index+1);
          selectedShape.setSelected(true);
        }
        return true;
      }
    }
    return false;
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Select the previous shape in the list.  Select the same shape if it is
   *        already the first in the list. If no selected shape before calling
   *        this method, it will choose the last one in the list
   *        (if a shape exist in the list)<BR>
   */
  public boolean selectPreviousShape()
  {
    if(shapeList.size()>0)
    {
      if(selectedShape==null)
      {
        selectedShape = (DrawableShape)shapeList.lastElement();
        selectedShape.setSelected(true);
        return true;
      }
      else
      {
        int index = shapeList.indexOf(selectedShape);
        if(index > 0)
        {
          unSelectShape();
          selectedShape = (DrawableShape)shapeList.elementAt(index-1);
          selectedShape.setSelected(true);
        }
        return true;
      }
    }
    return false;
  }

  /** <BR>
   *  PRE:  None<BR>
   *  POST: Return the color of the selectedShape color, if no shape is selected,
   *        it will return null<BR>
   */
  public Color getSelectedShapeColor()
  {
    if(selectedShape!=null)
    {
      return selectedShape.getColor();
    }
    return null;
  }

  /** <BR>
   *  PRE:  A valid Color object<BR>
   *  POST: Set the selected Shape's color from the input color object only if
   *        there is a selected shape<BR>
   */
  public void setSelectedShapeColor(Color color)
  {
    if(selectedShape!=null)
    {
      selectedShape.setColor(color);
    }
  }

  /** <BR>
   *  PRE:  NoneBR>
   *  POST: If an shape was selected, this class will save a copy of it<BR>
   */
  public void copySelectedShape()
  {
    if(selectedShape!=null)
    {
      copyShape = selectedShape.copyClone();
      copyShape.move(-copyShape.getLeastX(), -copyShape.getLeastY());
    }
  }

  /** <BR>
   *  PRE:  NoneBR>
   *  POST: If there is a copied shape, will add it to the last in the list and
   *        place it to the top left corner and return true.  Return false
   *        otherwise<BR>
   */
  public boolean pasteShape()
  {
    if(copyShape!=null)
    {
      //offset the shape to top left corner
      unSelectShape();
      addShape(copyShape);
      selectedShape=(DrawableShape)shapeList.lastElement();
      selectedShape.setSelected(true);
      return true;
    }
    return false;
  }
}
