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 = 20;

    // 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);
        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);
        }
    }

    // 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);
            shapes[numShapes] = null;
        }
    }

    // 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];
        }

        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];
            lastPoint = point;

            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;
        }
    }
}
