
import acm.program.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

/**
 * This class represents a graphics program that has a slider and "run" button 
 * at the top of it window. The slider can be use to select integers from a 
 * range of values. This allows simple input into a graphics program. Whenever
 * the "run" button is pressed the run method of the program is invoked. Note 
 * that the run method is also invoked at the start of the program.
 * @author aemertz
 */
public class SliderProgram extends GraphicsProgram
{

  /**
   * Called before the first time this program runs. This method assumes that 
   * the size of the program has been previously set as this size is used to set
   * the size of the slider. Subclasses should override this method if it has 
   * initialization to perform (namely setting the size of the program and range
   * of the slider). For example a subclass could contain the following 
   * <code>init()</code> method to set the width to 500, set the height to 600,
   * and have the slider range between the values [0, 20]: 

<pre>
  public void init() {
    setSize(500, 600);
    super.init();
    setRange(0, 20);
  }</pre>
   */
  @Override
  public void init()
  {    
    // Setup the default behavior for the slider
    slider.setPaintTicks(true);
    slider.setSnapToTicks(true);
    slider.setPaintLabels(true);

    // Make the slider take up most (80%) of the width of the screen. Might 
    // want to look at the sizes of the button and label to be sure things fit.
    // Also I am just hard coding in the height for now.
    slider.setPreferredSize(new Dimension((int) (getWidth() * 0.8), 50));

    // Arrange our interactors and place them at the top of the window
    panel.add(run);
    panel.add(labelN);
    panel.add(slider);
    add(panel, NORTH);

    // We want to listen for button presses
    addActionListeners();
  }

  /**
   * Sets the minimum and maximum values for the slider. Also, adds tick marks
   * every few integers (spacing is a power of 10 based on the number of 
   * integers in the range [minimum, maximum]). 
   *
   * @param minimum The new minimum value for the slider
   * @param maximum The new maximum value for the slider
   */
  public void setRange(int minimum, int maximum)
  {
    // Set the min and max as given
    slider.setMinimum(minimum);
    slider.setMaximum(maximum);

    // find a good power of ten to represent the range
    int digits = (int) Math.log10(maximum - minimum - 1);

    /* Want 10 minor marks per major. The conditional is used to guard against 
     * an exception that occurs if the value is not positive.
     */  
    slider.setMajorTickSpacing(digits > 0 ? (int) Math.pow(10, digits) : 1);
    slider.setMinorTickSpacing(digits > 1 ? (int) Math.pow(10, digits - 1) : 1);

    // Each major tick should have a label.
    slider.setLabelTable(
        slider.createStandardLabels(slider.getMajorTickSpacing()));
  }

  /**
   * Returns the current value of the slider.
   * @return value of the slider
   */
  public int getN()
  {
    return slider.getValue();
  }

  /**
   * Checks to see if the run button was pushed. If so then the canvas is 
   * cleared and the <code>run()</code> method is invoked.
   */
  @Override
  public void actionPerformed(ActionEvent e)
  {
    // When the run button is pushed clear the canvas and invoke button pushed
    if (e.getActionCommand().equals("Run"))
    {
      removeAll();
      
      /* Stop the old thread... I know this is deprecated. However, we do not 
       * have any synchronized code blocks to worry about and interrupting the 
       * thread in the preferred way would take cooperation from the overridden 
       * run method (i.e. cooperation from the student and this is a detail I 
       * want to hid from them). 
       */
      if(thread != null) thread.stop();
      
      // Make a new thread that just invokes the run method. 
      thread = new Thread()
      {

        public void run()
        {
          SliderProgram.this.run();
        }
      };
      thread.start();
    }
  }
  private Thread thread = null;
  private JPanel panel = new JPanel();
  private JButton run = new JButton("Run");
  private JSlider slider = new JSlider();
  private JLabel labelN = new JLabel("N:");
}

