import objectdraw.*;

import java.awt.*;

import javax.swing.*;

/**
 * Drawing Program with Array of Shapes.
 */
public class DrawingProgram extends WindowController {
  // max number of objects to be displayed
  private static final int SIZE = 100;
  private static final int MAX_OBJECTS = 40;

  // menus for shape, color, and command
  private JComboBox shapeChoice;
  private JComboBox colorChoice;
  private JComboBox commandChoice;

  // the item that is currently selected
  private DrawableInterface selected;

  // the last location of the mouse
  private Location lastPoint;

  // Array of objects on screen
  private DrawableInterface[] shapes = new DrawableInterface[MAX_OBJECTS];

  // number of objects on screen
  private int numShapes = 0;

  // Set up GUI components for program
  public void begin() {
    // create panel to hold choice buttons
    JPanel menuPanel = new JPanel();

    // menu for selecting or adding
    commandChoice = new JComboBox();
    commandChoice.addItem("Add new item");
    commandChoice.addItem("Recolor item");
    commandChoice.addItem("Move item");
    commandChoice.addItem("Delete item");
    menuPanel.add(commandChoice);

    // Set up menu for shapes
    shapeChoice = new JComboBox();
    shapeChoice.addItem("Circle");
    shapeChoice.addItem("Square");
    menuPanel.add(shapeChoice);

    // Set up menu for colors
    colorChoice = new JComboBox();
    colorChoice.addItem("Red");
    colorChoice.addItem("Green");
    colorChoice.addItem("Blue");
    menuPanel.add(colorChoice);

    // Add the panel to screen
    getContentPane().add(menuPanel, BorderLayout.SOUTH);
    this.validate();
  }

  // When the user clicks in the canvas, check the settings of the command menu to
  // determine what action to take.
  public void onMousePress(Location point) {
    selected = null; // indicate nothing currently selected

    Object buttonLabel = commandChoice.getSelectedItem();

    if (buttonLabel.equals("Add new item")) {
      addNewAt(point);
    } else if (buttonLabel.equals("Recolor item")) {
      recolorShapeAt(point);
    } else if (buttonLabel.equals("Move item")) {
      selectShapeAt(point);
    } else {
      deleteShapeAt(point);
    }

    lastPoint = point;
  }

  // This method implements the "Add new item" command.
  // Add new geometric shape where clicked.  Type and color of object is determined by the
  // settings of the color and shape menus.
  private void addNewAt(Location point) {
    // only add if still room for more objects
    if (numShapes < MAX_OBJECTS) {
      DrawableInterface newShape;

      // computer top-left corner of shape so it is center over mouse
      Location topLeft = new Location(point.getX() - (SIZE / 2),
          point.getY() - (SIZE / 2));

      Object shapeString = shapeChoice.getSelectedItem();

      // create new object to be shape chosen
      if (shapeString.equals("Square")) {
        newShape = new FilledRect(topLeft, SIZE, SIZE, canvas);
      } else {
        newShape = new FilledOval(topLeft, SIZE, SIZE, canvas);
      }

      newShape.setColor(getSelectedColor());
      shapes[numShapes] = newShape;
      numShapes++;
    }
  }

  // Returns the color corresponding to the string selected in the
  // color menu.
  private Color getSelectedColor() {
    // get color showing in the color menu
    Object colorString = colorChoice.getSelectedItem();

    if (colorString.equals("Red")) {
      return Color.RED;
    } else if (colorString.equals("Green")) {
      return Color.GREEN;
    } else {
      return Color.BLUE;
    }
  }

  /*
   * Change the shape and color of the item the user clicks on.
   */
  private void recolorShapeAt(Location point) {
    int selectIndex = getIndexOf(point);

    if (selectIndex != -1) {
      shapes[selectIndex].setColor(getSelectedColor());
    }
  }

  // return the index of the last element of shapes containing point
  // return -1 if no element of shapes contains point
  private int getIndexOf(Location point) {
    // Walk the array until we find the selected shape
    for (int selectIndex = numShapes - 1; selectIndex >= 0; selectIndex--) {
      if (shapes[selectIndex].contains(point)) {
        return selectIndex;
      }
    }

    return -1;
  }

  // Remove top-most geometric item clicked in.  
  // If didn't click in any then don't do anything.
  private void deleteShapeAt(Location point) {
    int selectIndex = getIndexOf(point);

    // if point is in one of the objects, delete it
    if (selectIndex != -1) {
      shapes[selectIndex].removeFromCanvas();
      removeShapeAtIndex(selectIndex);
    }
  }

  // remove shapes[index] by moving later elements back.
  private void removeShapeAtIndex(int index) {
    for (int i = index; i < numShapes - 1; i++) {
      shapes[i] = shapes[i + 1];
    }
    shapes[numShapes - 1] = null;
    numShapes--;
  }

  // Set select to indicate top-most geometric item clicked in, and send it to front of
  // screen.  If didn't click in any then select stays null.  Remember where clicked in
  // lastPoint.
  private void selectShapeAt(Location point) {
    int selectIndex = getIndexOf(point);

    // Remember which shape is selected so onMouseDrag can move it.
    if (selectIndex != -1) {
      selected = shapes[selectIndex];
      selected.sendToFront();
      removeShapeAtIndex(selectIndex);
      shapes[numShapes] = selected;
      numShapes++;
    }
  }

  // If something was selected then drag it and remember where left off
  public void onMouseDrag(Location point) {
    if (selected != null) {
      selected.move(point.getX() - lastPoint.getX(),
        point.getY() - lastPoint.getY());
      lastPoint = point;
    }
  }
}
