import java.awt.*;
import java.awt.event.*;
import objectdraw.*;

import javax.swing.*;

/*
 * A version of the Spirals program that records each spiral
 * as a Scribble so that they can be dragged around.
 */

public class SpiralScribbles extends WindowController implements ActionListener {
    
    private static final double THETA_STEP = 0.1;
    private static final double MAX_THETA = 40 * Math.PI;
    
    // pick the number of "bumps" and magnitude
    private RandomDoubleGenerator randomBumps = new RandomDoubleGenerator(0.5, 10);
    private RandomDoubleGenerator randomMagnitude = new RandomDoubleGenerator(0.5, 10);
    
    
    // user modes
    private static final int DRAWING = 1;
    private static final int MOVING = 2;
    
    // the current scribble
    private ScribbleInterface currentScribble;
    
    // stores last point for drawing or dragging
    private Location lastPoint;
    
    // whether the most recent scribble has been selected for moving
    private boolean draggingScribble;
    
    // buttons that allow user to select modes
    private JButton setDraw, setMove;
    
    // the current mode -- drawing by default
    private int chosenAction;
    
    // create and hook up the user interface components
    public void begin() {
        
        setDraw = new JButton("Draw");
        setMove = new JButton("Move");
        
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(setDraw);
        buttonPanel.add(setMove);
        
        Container contentPane = getContentPane();
        contentPane.add(buttonPanel, BorderLayout.SOUTH);
        contentPane.validate();
        
        // add listeners
        setDraw.addActionListener(this);
        setMove.addActionListener(this);
        
        chosenAction = DRAWING;
    }
    
    // if in drawing mode then start with empty scribble
    // if in moving mode then prepare to move
    public void onMousePress(Location point) {
        if (chosenAction == DRAWING) {
            drawSpiral(point);
            
        } else if (chosenAction == MOVING) {
            // check if user clicked on current scribble
            draggingScribble = currentScribble.contains(point);
        }
        
        // remember point of press for drawing or moving
        lastPoint = point;
    }
    
    // if in drawing mode, add a new segment to scribble
    // if in moving mode then move it
    public void onMouseDrag(Location point) {
        if (chosenAction == MOVING && draggingScribble) {
            // drag current scribble
            currentScribble.move(
                                 point.getX() - lastPoint.getX(),
                                 point.getY() - lastPoint.getY());
        }
        // update for next move or draw
        lastPoint = point;
    }
    
    // Set mode according to button pressed.
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == setDraw) {
            chosenAction = DRAWING;
        } else if (e.getSource() == setMove) {
            chosenAction = MOVING;
        }
    }
    
    
    private void drawSpiral(Location center) {
        // start with an empty scribble for drawing
        currentScribble = new EmptyScribble();
        Location lastPoint = center;
        
        // I invert the magnitude random number to get a more 
        // interesting distribution of values. (Most magnitudes
        // will then be < 1, with some between 1-2.)  
        double magnitude = 1 / randomMagnitude.nextValue();
        double bumps = randomBumps.nextValue();
        
        double theta = 0;
        while (theta < MAX_THETA) {
            double radius = theta * (1 + Math.sin(bumps * theta) * magnitude) / 2;
            
            // Convert polar to cartesian
            Location newPoint = 
                new Location(center.getX() + radius * Math.cos(theta),
                             center.getY() + radius * Math.sin(theta));
            
            Line line = new Line(lastPoint, newPoint, canvas);
            
            // Compute the color of the line segment
            // When theta is small, we want very little red
            //   and lots of blue.  As theta grows, the opposite
            //   is true.  the (int)(...) is a type cast to
            //   force Java to treat a double value as an int.
            int red = (int)(255 * theta / MAX_THETA);
            line.setColor(new Color(red,0,255-red));
            
            // add segment to scribble
            currentScribble = new NonEmptyScribble(line, currentScribble);
            
            lastPoint = newPoint;
            theta = theta + THETA_STEP;
        }
    }
    
}
