/** 
 * A simple interface for classes that can manipulate pictures in an
 * ImageBase object.  
 *
 * @author Kuzman Ganchev 
 */

import javax.swing.JOptionPane;

public abstract class Manipulator{
  
  private Double theDouble = null;
  private String theString = null;
  
  /**
   * If you call setDouble, subsequent calls to getNumberFromUser will
   * return that double immediately instead of prompting the user for a number.
   * Useful if you want to write a unit test.
   * @param d The double that will be returned from here on out, until you set another one
   * */
  public void setDouble(double d) {
    theDouble = d;
  }
  /**
   * If you call setString, subsequent calls to getNumberFromUser will
   * return that double immediately instead of prompting the user for a number.
   * Useful if you want to write a unit test.
   * @param d The double that will be returned from here on out, until you set another one
   * */
  public void setString(String s) {
    theString = s;
  }
  
  
  /** Performs the manipulation on the supplied ImageBase object.  Calls the processImage() method to get the job done. */
  public void manipulate(ImageBase ib) {
    Picture picture = ib.getPicture();
    
    // read out all the Pixels into a 2d array
    Pixel[][] pixels = new Pixel[picture.getWidth()][picture.getHeight()];
    for (int x = 0; x < picture.getWidth(); x++) {
      for (int y = 0; y < picture.getHeight(); y++) {
        pixels[x][y] = new Pixel(picture.getPixel(x,y).getComponents());
      }
    }
    
    // get the actual work done
    pixels = processImage(pixels);
    
    // the image might have changed size...
    picture = new Picture(pixels.length, pixels[0].length);
    
    // put all the pixels in
    for (int x = 0; x < picture.getWidth(); x++) {
      for (int y = 0; y < picture.getHeight(); y++) {
        picture.setPixel(x,y, pixels[x][y]);
      }
    }
    
    // finally, refresh the picture
    ib.setPicture(picture);
  }
  /** Returns the text associated with this manipulation */
  public abstract String getManipulationName();
  
  /** Processes the picture in whatever way the specific Manipulator subclass is supposed to.
    * You can modify the 2d Pixel array in place and return it, or make a new array and return that.
    * First dimension is the x-axis (positive goes right), second is y-axis (positive goes down) 
    * ex. picture[100][0] is the top of the image, 100 pixels from the left 
    * @param picture The image to apply the effect to
    * @return The new image resulting from processing
    */
  public abstract Pixel[][] processImage(Pixel[][] picture);
  
  /** Display the prompt to the user, and ask for input (number)
    * Loops until the user enters a number
    * @param prompt The prompt to display to the user
    * @return The number the user entered
    */
  protected double getNumberFromUser(String prompt) {
    // following line for the testers...
    if (theDouble != null) return theDouble;
    
    Double num = null;
    String input;
    while(num == null) { 
      input = JOptionPane.showInputDialog(prompt);
      if (input == null) 
        num = null;  
      try {
        num = Double.parseDouble(input);
      } catch (Exception e) {
        num = null;
      }
    }
    
    return num;
  }
  
   /** Display the prompt to the user, and ask them for input (string)
    * If input was invalid, it returns null value *
    * @param prompt The prompt to display to the user
    * @return The String the user entered, or null if the input was invalid
    * */
  protected String getStringFromUser(String prompt) {
    // following line for the testers...
    if (theString != null) return theString;
   return  JOptionPane.showInputDialog(prompt);
  }
}