import java.awt.*;

/**
 * A class that represents a picture.  This class inherits from 
 * SimplePicture and allows the student to add functionality to
 * the Picture class.
 * 
 * @author Barbara Ericson
 */
public class Picture extends SimplePicture
{
  ///////////////////// constructors //////////////////////////////////
  
  /**
   * Constructor that takes no arguments 
   */
  public Picture ()
  {
    // not needed but use it to show students the implicit call to super()
    super();  
  }
  
  /**
   * Constructor that takes a file name and creates the picture 
   * @param fileName the name of the file to create the picture from
   */
  public Picture(String fileName)
  {
    // let the parent class handle this fileName
    super(fileName);
  }
  
  /**
   * Constructor that takes the width and height
   * @param width the width of the desired picture
   * @param height the height of the desired picture
   */
  public Picture(int width, int height)
  {
    // let the parent class handle this width and height
    super(width,height);
  }
  
  ////////////////////// methods ///////////////////////////////////////
 
  /**
   * Method to return a string with information about this picture.
   * @return a string with information about the picture such as fileName,
   * height and width.
   */
  public String toString()
  {
    String output = "Picture, filename " + getFileName() + " height " + getHeight() 
      + " width " + getWidth();
    return output;
  }
  
  
  /**
   * Class method to let the user pick a file name and then create the picture 
   * and show it
   * @return the picture object
   */
  public static Picture pickAndShow()
  {
    String fileName = FileChooser.pickAFile();
    Picture picture = new Picture(fileName);
    picture.show();
    return picture;
  }
  
  /**
   * Class method to create a picture object from the passed file name and 
   * then show it
   * @param fileName the name of the file that has a picture in it
   * @return the picture object
   */
  public static Picture showNamed(String fileName)
  {
    Picture picture = new Picture(fileName);
    picture.show();
    return picture;
  }
  
  
  /**
   * Method to decrease the red by half in the current picture
   */
  public void decreaseRed()
  {
    Pixel pixel = null; // the current pixel
    int redValue;       // the amount of red
    
    // get the array of pixels for this picture object
    Pixel[] pixels = this.getPixels();
    
    // start the index at 0
    int index = 0;

    // loop while the index is less than the length of the pixels array
    while (index < pixels.length)
    {
      // get the current pixel at this index
      pixel = pixels[index];

      // get the red value at the pixel
      redValue = pixel.getRed();

      // set the red value to half what it was
      redValue = (int) (redValue * 0.5);
      
      // set the red for this pixel to the new value
      pixel.setRed(redValue);
      
      // increment the index
      index++;
    }
  }
  
  public void increaseRed()
  {
    Pixel pixel = null; // the current pixel
    int redValue;       // the amount of red
    
    // get the array of pixels for this picture object
    Pixel[] pixels = this.getPixels();
    
    // start the index at 0
    int index = 0;

    // loop while the index is less than the length of the pixels array
    while (index < pixels.length)
    {
      // get the current pixel at this index
      pixel = pixels[index];

      // get the red value at the pixel
      redValue = pixel.getRed();

      // increase the red value to 30% more than the original
      redValue = (int) (redValue * 1.3);
      
      // set the red for this pixel to the new value
      pixel.setRed(redValue);
      
      // increment the index
      index++;
    }
  }

  
  /**
   * Method to decrease the red by an amount
   * @param amount the amount to change the red by
   */
  public void decreaseRed(double amount)
  {
    Pixel[] pixels = this.getPixels();
    Pixel p = null;
    int value = 0;
    
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      p = pixels[i]; 
      
      // get the value
      value = p.getRed();
      
      // set the red value the passed amount time what it was
      p.setRed((int) (value * amount));
    }
  }
  
  /**
   * Method to increase the amount of red by 1.3
   */
//  public void increaseRed()
//  {
//    Pixel[] pixels = this.getPixels();
//    Pixel pixel = null;
//    int value = 0;
//    
//    // loop through all the pixels
//    for (int i = 0; i < pixels.length; i++)
//    {
//      // get the current pixel
//      pixel = pixels[i]; 
//      
//      // get the value
//      value = pixel.getRed();
//      
//      // set the red value to 1.3 times what it was
//      pixel.setRed((int) (value * 1.3));
//    }
//  }
  
  /**
   * Method to increase the amount of red by 1.3
   */
  public void increaseRed2()
  {
    Pixel[] pixels = this.getPixels();
    
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // set the red value to 1.3 times what it was
      pixels[i].setRed((int) (pixels[i].getRed() * 1.3));
    }
  }
  
   /**
   * Method to increase the amount of red by 1.3
   */
  public void increaseRed3()
  {
    Pixel[] pixels = this.getPixels();
    Pixel pixel = null;
    int red = 0;
    int green = 0;
    int blue = 0;
    int newRed = 0;
    
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i]; 
      
      // get the color values
      red = pixel.getRed();
      green = pixel.getGreen();
      blue = pixel.getBlue();
      
      // calculate the new red value
      newRed = (int) (red * 1.3);
      
      // set the pixel color to the new color
      pixel.setColor(new Color(newRed,green,blue));
    }
  }
  
  /**
   * Method to clear the blue from the picture (set
   * the blue to 0 for all pixels)
   */
  public void clearBlue()
  {
    
    // get the array of pixels from the current picture
    Pixel[] pixels = this.getPixels();
    
    //  declare the variable that will refer to the current pixel
    Pixel pixel = null;
    
    // declare the index and initialize it to 0
    int index = 0;
    
    // loop through all the pixels
    while (index < pixels.length)
    {
      // get the current pixel
      pixel = pixels[index];
      
      // set the blue on the pixel to 0
      pixel.setBlue(0);
      
      index++;
    }
  }
  
  /**
   * Method to lighten the colors in the picture
   */
  public void lighten()
  {
    Pixel[] pixels = this.getPixels();
    Color color = null;
    Pixel pixel = null;
    
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];
      
      // get the current color
      color = pixel.getColor();
      
      // get a lighter color 
      color = color.brighter();
      
      // set the pixel color to the lighter color
      pixel.setColor(color);
    }
   }
  
  /**
   * Method to lighten the colors using a nested for loop
   */
  public void lightenNested()
  {
    Pixel pixel = null;
    Color color = null;
    
    // loop through the columns (x direction)
    for (int x = 0; x < getWidth(); x++)
    {
      // loop through the rows (y direction)
      for (int y = 0; y < getHeight(); y++)
      {
        // get the current pixel
        pixel = getPixel(x,y);
      
        // get the current color
        color = pixel.getColor();
      
        // get a lighter color 
        color = color.brighter();
      
        // set the pixel color to the lighter color
        pixel.setColor(color);
      }
    }
   }
  
  /**
   * Method to lighten the colors using a nested for loop
   */
  public void lightenWhileNested()
  {
    Pixel pixel = null;
    Color color = null;
    
    // loop through the columns (x direction)
    int x = 0;
    while (x < getWidth())
    {
      
      // loop through the rows (y direction)
      int y = 0;
      while(y < getHeight())
      {
        // get the current pixel
        pixel = getPixel(x,y);
      
        // get the current color
        color = pixel.getColor();
      
        // get a lighter color 
        color = color.brighter();
      
        // set the pixel color to the lighter color
        pixel.setColor(color);
        
        // increment y
        y++;
      }
      // increment x
      x++;
    }
   }
 
  /**
   * Method to darken the color in the picture
   */
  public void darken()
  {
    Pixel[] pixels = this.getPixels();
    Color color = null;
    Pixel pixel = null;

    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];

      // get the current color
      color = pixel.getColor();

      // get a darker color
      color = color.darker();

      // set the pixel color to the darker color
      pixel.setColor(color);
    }
   }
   
  /**
   * Method to negate the picture 
   */
  public void negate()
  {
    Pixel pixel = null;
    
    // get the array of pixels 
    Pixel[] pixels = this.getPixels();
    
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];
      
      // set the pixel color values to the new values
      pixel.setRed(255 - pixel.getRed());
      pixel.setGreen(255 - pixel.getGreen());
      pixel.setBlue(255 - pixel.getBlue());
    }
  }
  
  /**
   * Method to change the picture to gray scale
   */
  public void grayscale()
  {
    Pixel pixel = null;
    int intensity = 0;
    
    // get the array of pixels
    Pixel[] pixels = this.getPixels();
  
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];
      
      // compute the intensity of the pixel (average value)
      intensity = (int) ((pixel.getRed() + pixel.getGreen() + 
                     pixel.getBlue()) / 3);
      
      // set the pixel color to the new color
      pixel.setColor(new Color(intensity,intensity,intensity));
      
    }
  }
  
  /**
   * Method to change the picture to gray scale with luminance
   */
  public void grayscaleWithLuminance()
  {
    Pixel[] pixels = this.getPixels();
    Pixel pixel = null;
    int luminance = 0;
    double redValue = 0;
    double greenValue = 0;
    double blueValue = 0;
  
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];
      
      // get the corrected red, green, and blue values
      redValue = pixel.getRed() * 0.299;
      greenValue = pixel.getGreen() * 0.587;
      blueValue = pixel.getBlue() * 0.114;
      
      // compute the intensity of the pixel (average value)
      luminance = (int) (redValue + greenValue + blueValue);
      
      // set the pixel color to the new color
      pixel.setColor(new Color(luminance,luminance,luminance));
      
    }
  }
  
  /**
   * Method to reduce the green in the picture by 30% 
   */
  public void reduceGreen()
  {
    Pixel[] pixels = this.getPixels();
    Pixel pixel = null;
    int value = 0;

    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];

      // get the value
      value = pixel.getGreen();

      // set the green value to 70% of what it was
      pixel.setGreen((int) (value * 0.7));
    }
  }

  /**
   * Method to reduce the blue in the picture by 30% 
   */
  public void reduceBlue()
  {
    Pixel[] pixels = this.getPixels();
    Pixel pixel = null;
    int value = 0;

    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];

      // get the value
      value = pixel.getBlue();

      // set the blue value to 70% of what it was
      pixel.setBlue((int) (value * 0.7));
    }
  }
  
  /**
   * Method to create a picture from the passed file name and 
   * reduce the green in it
   * @param fileName the name of the file to create the picture from
   * @return the created picture
   */
  public static Picture reduceGreen(String fileName)
  {
    Picture picture = new Picture(fileName);
    Pixel[] pixels = picture.getPixels();
    Pixel pixel = null;
    int value = 0;
    
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i]; 
      
      // get the value
      value = pixel.getGreen();
      
      // set the green value to 70% of what it was
      pixel.setGreen((int) (value * 0.7));
    }
    
    return picture;
  }
  
  /**
   * Method to create a picture and reduce the blue in it
   * @param fileName the name of the file to use to create the picture 
   * @return the created picture
   */
  public static Picture reduceBlue(String fileName)
  {
    Picture picture = new Picture(fileName);
    Pixel[] pixels = picture.getPixels();
    Pixel pixel = null;
    int value = 0;
    
    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i]; 
      
      // get the value
      value = pixel.getBlue();
      
      // set the blue value to 70% of what it was
      pixel.setBlue((int) (value * 0.7));
    }
    
    return picture;
  }
  
  /**
   * Method to make a picture look like it was taken at sunset
   * by reducing the blue and green to make it look more red
   */
  public void makeSunset()
  {
    reduceGreen();
    reduceBlue();
  }
  
  /**
   * Method to simulate a sunset by reducing the green and blue 
   * @param fileName the name of the file to use
   */
  public static void makeSunset(String fileName)
  {
    reduceGreen(fileName);
    reduceBlue(fileName);
  }
  
  /**
   * Method to fake a sunset by reducing the blue and green in a picture
   * by 30%
   */
  public void fakeSunset()
  {
    Pixel pixel = null; // the current pixel
    
    // get the array of pixels for this picture object
    Pixel[] pixels = this.getPixels();
    
    // start the index at 0
    int index = 0;

    // loop while the index is less than the length of the pixels array
    while (index < pixels.length)
    {
      // get the current pixel at this index
      pixel = pixels[index];
      
      // set the blue value to 0.7 times the original blue value
      pixel.setBlue((int) 0.7 * pixel.getBlue());

      // set the green value to 0.7 times the original green value
      pixel.setGreen((int) 0.7 * pixel.getGreen());
      
      // increment the index
      index++;
    }
  }
   
  /**
   * Method to mirror around a vertical line in the middle of the picture
   * based on the width
   */
  public void mirrorVertical()
  {
    int mirrorPoint = getWidth() / 2;
    Pixel leftPixel = null;
    Pixel rightPixel = null;
    
    // loop through the rows
    for (int y = 0; y < getHeight(); y++)
    {
      // loop from 1 to just before the mirror point
      for (int x = 1; x < mirrorPoint; x++)
      {
        leftPixel = getPixel((mirrorPoint - x), y);
        rightPixel = getPixel((mirrorPoint + x), y);
        rightPixel.setColor(leftPixel.getColor());
      }
    }
  }
 
  /**
   * Method to mirror around a horizontal line in the middle based 
   * on the height.  It copies the top mirrored to the bottom
   */
  public void mirrorHorizontal()
  {
    int mirrorPoint = getHeight() / 2;
    Pixel topPixel = null;
    Pixel bottomPixel = null;
    
    // loop through the columns
    for (int x=0; x < getWidth(); x++)
    {
      // loop from 1 to just before the mirror point
      for (int y=1; y < mirrorPoint; y++)
      {
        topPixel = getPixel(x,(mirrorPoint - y));
        bottomPixel = getPixel(x,(mirrorPoint + y));
        bottomPixel.setColor(topPixel.getColor());
      }
    }
  }
 
  /**
   * Method to mirror around a horiztonal line in the middle
   * based on the height of the picture.  It copies the bottom
   * to the top.
   */
  public void mirrorHorizontalBottomToTop()
  {
    int mirrorPoint = (int) (getHeight() / 2);
    Pixel topPixel = null;
    Pixel bottomPixel = null;
    
    // loop through the columns
    for (int x=0; x < getWidth(); x++)
    {
      // loop from 1 to just before the mirror point
      for (int y=1; y < mirrorPoint; y++)
      {
        topPixel = getPixel(x,(mirrorPoint - y));
        bottomPixel = getPixel(x,(mirrorPoint + y));
        topPixel.setColor(bottomPixel.getColor());
      }
    }
  }
  
  /**
   * Method to mirror the piedmont of the temple
   * @return the corrected picture
   */
  public static Picture mirrorTemple()
  {
    Picture picture = new Picture(getMediaPath("temple.jpg"));
    int mirrorPoint = 276;
    int lengthToCopy = mirrorPoint - 13;
    Pixel leftPixel = null;
    Pixel rightPixel = null;
    int count = 0;
    
    // loop through the columns
    for (int x = 1; x < lengthToCopy; x++)
    {
      // loop through the rows
      for (int y = 27; y < 97; y++)
      {
        count = count + 1;
        leftPixel = picture.getPixel(mirrorPoint - x,y);
        rightPixel = picture.getPixel(mirrorPoint + x, y);
        rightPixel.setColor(leftPixel.getColor());
      }
    }
    
    // tell how many pixels were copied
    System.out.println("We copied " + count + " pixels");
    
    // show the picture 
    picture.show();
    return picture;
  }
 
  /**
   * Method to copy the picture of Katie to 100, 100 in the canvas
   * @return the picture of Katie copied to 100,100
   */
  public static Picture copyKatieMidway()
  {
    String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
    Picture sourcePicture = new Picture(sourceFile);
    String targetFile = Picture.getMediaPath("7inx95in.jpg");
    Picture targetPicture = new Picture(targetFile);
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (int sourceX = 0, targetX=100; 
         sourceX < sourcePicture.getWidth(); 
         sourceX++, targetX++)
    {
      // loop through the rows
      for (int sourceY = 0, targetY =100; 
           sourceY < sourcePicture.getHeight(); 
           sourceY++, targetY++)
      {
        // set the target pixel color to the source pixel color
        sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
        targetPixel = targetPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the source and target pictures
    sourcePicture.show();
    targetPicture.show();
    
    return targetPicture;
  }
 
  /**
   * Method to copy the picture of Katie to the canvas
   * @return the canvas after the picture of Katie has been copied
   */
  public static Picture copyKatie()
  {
    String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
    Picture sourcePicture = new Picture(sourceFile);
    String targetFile = Picture.getMediaPath("7inx95in.jpg");
    Picture targetPicture = new Picture(targetFile);
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (int sourceX = 0, targetX=0; 
         sourceX < sourcePicture.getWidth(); 
         sourceX++, targetX++)
    {
      // loop through the rows
      for (int sourceY = 0, targetY =0; 
           sourceY < sourcePicture.getHeight(); 
           sourceY++, targetY++)
      {
        // set the target pixel color to the source pixel color
        sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
        targetPixel = targetPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the source and target pictures
    sourcePicture.show();
    targetPicture.show();
    
    return targetPicture;
  }
  
  /**
   * Method to copy Katie rotated to the left 90 degrees
   * @return the picture after Katie has been copied and rotated to the left 90
   */
  public static Picture copyKatieRightRotation()
  {
    String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
    Picture sourcePicture = new Picture(sourceFile);
    String targetFile = Picture.getMediaPath("7inx95in.jpg");
    Picture targetPicture = new Picture(targetFile);
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (int sourceX = 0; sourceX < sourcePicture.getWidth(); sourceX++)
    {
      // loop through the rows
      for (int sourceY = 0; sourceY < sourcePicture.getHeight(); sourceY++)
      {
        // set the target pixel color to the source pixel color
        sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
        targetPixel = targetPicture.getPixel(sourcePicture.getHeight() - 1 - sourceY,sourceX);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the source and target pictures
    sourcePicture.show();
    targetPicture.show();
    
    return targetPicture;
  }
  
  /**
   * Method to copy Katie rotated to the left 90 degrees
   * @return the picture after Katie has been copied and rotated to the left 90
   */
  public static Picture copyKatieLeftRotation()
  {
    String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
    Picture sourcePicture = new Picture(sourceFile);
    String targetFile = Picture.getMediaPath("7inx95in.jpg");
    Picture targetPicture = new Picture(targetFile);
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (int sourceX = 0; sourceX < sourcePicture.getWidth(); sourceX++)
    {
      // loop through the rows
      for (int sourceY = 0; sourceY < sourcePicture.getHeight(); sourceY++)
      {
        // set the target pixel color to the source pixel color
        sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
        targetPixel = targetPicture.getPixel(sourceY, sourcePicture.getWidth() - 1 - sourceX);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the source and target pictures
    sourcePicture.show();
    targetPicture.show();
    
    return targetPicture;
  }
  
  /**
   * Method to copy from the passed source picture to current picture object
   * The copying will start at startX, startY, and end at endX and endY
   * The copy will be placed starting at targetStartX, targetStartY
   * @param sourcePicture the source picture to copy from
   * @param startX the starting x value in the source picture
   * @param startY the starting y value in the source picture
   * @param endX the ending x value in the source picture
   * @param endY the ending y value in the source picture
   * @param targetStartX the starting x value in the current picture
   * @param targetStartY the starting y value in the current picture
   */
  public void copy(Picture sourcePicture, int startX, int startY, 
                   int endX, int endY, int targetStartX, int targetStartY)
  {
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the x values
    for (int x = startX; x <= endX; x++)
    {
      // loop through the y values
      for (int y = startY; y <= endY; y++)
      {
        sourcePixel = sourcePicture.getPixel(x,y);
        targetPixel = this.getPixel(targetStartX + x, targetStartY + y);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
  }
 
  /**
   * Method to copy just Katie's face to the canvas 
   * @return the canvas after the copying the face
   */
  public static Picture copyKatiesFace()
  {
    String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
    Picture sourcePicture = new Picture(sourceFile);
    String targetFile = Picture.getMediaPath("7inx95in.jpg");
    Picture targetPicture = new Picture(targetFile);
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (int sourceX = 70, targetX = 100; sourceX <= 136; sourceX++, targetX++)
    {
      // loop through the rows
      for (int sourceY = 3, targetY = 100; sourceY <= 81; sourceY++, targetY++)
      {
        // set the target pixel color to the source pixel color
        sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
        targetPixel = targetPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the source and target pictures
    sourcePicture.show();
    targetPicture.show();
    
    return targetPicture;
    
  }
  
  /**
   * Method to create a flower collage
   */
  public static Picture createFlowerCollage()
  {
    // create the picture objects
    Picture flower1Picture = new Picture(Picture.getMediaPath("flower1.jpg"));
    Picture flower2Picture = new Picture(Picture.getMediaPath("flower2.jpg"));
    Picture targetPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
    
    // get the flower 1 and flower 2 width and height
    int flower1Width = flower1Picture.getWidth();
    int flower2Width = flower2Picture.getWidth();
    int flower1Height = flower1Picture.getHeight();
    int flower2Height = flower2Picture.getHeight();
    
    // get the flower1 end x and end y
    int flower1EndX = flower1Width - 1;
    int flower1EndY = flower1Height - 1;
    
    // get the flower2 width and height
    int flower2EndX = flower2Width - 1;
    int flower2EndY = flower2Height - 1;
    
    // determine the target start x bottom y
    int targetStartX = 0;
    int targetBottomY = targetPicture.getHeight() - 5;
    
    // copy from flower1Picture to targetPicture and update target start x 
    targetPicture.copy(flower1Picture,0,0,flower1EndX, flower1EndY,
                       targetStartX,targetBottomY - flower1Height);
    targetStartX = targetStartX + flower1Width;
    
    // copy from flower2Picture to targetPicture and update target start x 
    targetPicture.copy(flower2Picture,0,0,flower2EndX, flower2EndY,
                       targetStartX,targetBottomY - flower2Height);
    targetStartX = targetStartX + flower2Width;
    
    // negate the flower1Picture and copy to targetPicture and update target start x 
    flower1Picture.negate();
    targetPicture.copy(flower1Picture,0,0,flower1EndX, flower1EndY,
                       targetStartX,targetBottomY - flower1Height);
    targetStartX = targetStartX + flower1Width;
    
    // clear the blue from flower2 picture and copy to targetPicture
    flower2Picture.clearBlue();
    targetPicture.copy(flower2Picture,0,0,flower2EndX, flower2EndY,
                       targetStartX,targetBottomY - flower2Height); 
    targetStartX = targetStartX + flower2Width;
    
    // copy from flower1Picture to targetPicture 
    targetPicture.copy(flower1Picture,0,0,flower1EndX, flower1EndY,
                       targetStartX,targetBottomY - flower1Height);
    
    // show the target picture
    targetPicture.show();
    
    return targetPicture;
  }
                       
  /**
   * Method to create a collage from the flower pictures.  All the flower pictures
   * will be lined up near the bottom of the canvas (5 pixels from the bottom)
   * @return the collage as a picture object
   */
  public static Picture createCollage()
  {
    
    // create the three pictures
    Picture flower1Picture = new Picture(Picture.getMediaPath("flower1.jpg"));
    Picture flower2Picture = new Picture(Picture.getMediaPath("flower2.jpg"));
    Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
    
    // declare the source and target pixel variables
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // print out the picture information
    System.out.println(flower1Picture);
    System.out.println(flower2Picture);
    System.out.println(canvasPicture);
    
    /* copy the first flower picture to 5 pixels from the bottom 
       left corner of the canvas
    */
    for (int sourceX = 0, targetX = 0; 
         sourceX < flower1Picture.getWidth(); 
         sourceX++, targetX++)
    {
      for (int sourceY = 0, 
           targetY = canvasPicture.getHeight() - flower1Picture.getHeight() - 5; 
           sourceY < flower1Picture.getHeight(); 
           sourceY++, targetY++)
      {
        sourcePixel = flower1Picture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // copy the flower2 picture starting with x = 100 in the canvas
    for (int sourceX = 0, targetX = 100; 
         sourceX < flower2Picture.getWidth(); 
         sourceX++, targetX++)
    {
      for (int sourceY = 0, 
           targetY = canvasPicture.getHeight() - flower2Picture.getHeight() - 5; 
           sourceY < flower2Picture.getHeight(); 
           sourceY++, targetY++)
      {
        sourcePixel = flower2Picture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // copy the flower1 negated to x = 200 in the canvas
    flower1Picture.negate();
    for (int sourceX = 0, targetX = 200; 
         sourceX < flower1Picture.getWidth(); 
         sourceX++, targetX++)
    {
      for (int sourceY = 0, 
           targetY = canvasPicture.getHeight() - flower1Picture.getHeight() - 5; 
           sourceY < flower1Picture.getHeight(); 
           sourceY++, targetY++)
      {
        sourcePixel = flower1Picture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // clear the blue in flower 2 picture and add at x=300 in the canvas
    flower2Picture.clearBlue();
    for (int sourceX = 0, targetX = 300; 
         sourceX < flower2Picture.getWidth(); 
         sourceX++, targetX++)
    {
      for (int sourceY = 0, 
           targetY = canvasPicture.getHeight() - flower2Picture.getHeight() - 5; 
           sourceY < flower2Picture.getHeight(); 
           sourceY++, targetY++)
      {
        sourcePixel = flower2Picture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // copy the negated flower 1 to x=400
    for (int sourceX = 0, targetX = 400; 
         sourceX < flower1Picture.getWidth(); 
         sourceX++, targetX++)
    {
      for (int sourceY = 0, 
           targetY = canvasPicture.getHeight() - flower1Picture.getHeight() - 5; 
           sourceY < flower1Picture.getHeight(); 
           sourceY++, targetY++)
      {
        sourcePixel = flower1Picture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the resulting picture
    canvasPicture.show();
    
    return canvasPicture;
  }
 
  /**
   * Method that will copy all of the passed source picture into
   * the current picture object starting with the left corner
   * given by xStart
   * @param sourcePicture  the picture object to copy
   * @param xStart the x position to start the copy into
   */
  public void copyPictureTo(Picture sourcePicture, int xStart)
  {
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (int sourceX = 0, targetX = xStart; 
         sourceX < sourcePicture.getWidth(); 
         sourceX++, targetX++)
    {
      // loop through the rows
      for (int sourceY = 0, 
           targetY = this.getHeight() - sourcePicture.getHeight() - 5; 
           sourceY < sourcePicture.getHeight(); 
           sourceY++, targetY++)
      {
        sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
        targetPixel = this.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
  }
 
  /**
   * Method to create a collage of flowers with a better method
   * @return the flower collage as a picture object
   */
  public static Picture createCollageBetter()
  {
    
    // create the three pictures
    Picture flower1Picture = new Picture(Picture.getMediaPath("flower1.jpg"));
    Picture flower2Picture = new Picture(Picture.getMediaPath("flower2.jpg"));
    Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
    
    // print out the picture information
    System.out.println(flower1Picture);
    System.out.println(flower2Picture);
    System.out.println(canvasPicture);
    
    /* copy the first flower picture to the near the bottom left 
     * corner of the canvas
     */
    canvasPicture.copyPictureTo(flower1Picture,0);
    
    // copy the flower2 picture starting with x = 100 in the canvas
    canvasPicture.copyPictureTo(flower2Picture,100);
    
    // copy the flower1 negated to x = 200 in the canvas
    flower1Picture.negate();
    canvasPicture.copyPictureTo(flower1Picture,200);
    
    // clear the blue in flower 2 picture and add at x=300 in the canvas
    flower2Picture.clearBlue();
    canvasPicture.copyPictureTo(flower2Picture,300);
    
    // copy the negated flower 1 to x=400
    canvasPicture.copyPictureTo(flower1Picture,400);
    
    // show the resulting picture
    canvasPicture.show();
    
    return canvasPicture;
  }
 
  /**
   * Method to blend pictures of Katie and Jenny
   * @return the blended picture
   */
  public static Picture blendPictures()
  {
    
    // create the three pictures
    Picture katiePicture = new Picture(Picture.getMediaPath("KatieFancy.jpg"));
    Picture jennyPicture = new Picture(Picture.getMediaPath("JenParty.jpg"));
    Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
    
    // declare the source and target pixel variables
    Pixel katiePixel = null;
    Pixel jennyPixel = null;
    Pixel targetPixel = null;
    
    // declare the target x and source x since we will need the values after the
    // for loop
    int sourceX = 0;
    int targetX = 0;
    
    // copy the first 150 pixels of katie to the canvas
    for (; sourceX < 150; sourceX++, targetX++)
    {
      for (int sourceY=0, targetY=0; 
           sourceY < katiePicture.getHeight(); 
           sourceY++, targetY++)
      {
        katiePixel = katiePicture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(katiePixel.getColor());
      }
    }
    
    // copy 50% of katie and 50% of jenny till the end of katie's width
    for (; sourceX < katiePicture.getWidth(); sourceX++, targetX++)
    {
      for (int sourceY=0,targetY=0; 
           sourceY < katiePicture.getHeight(); 
           sourceY++, targetY++)
      {
        katiePixel = katiePicture.getPixel(sourceX,sourceY);
        jennyPixel = jennyPicture.getPixel(sourceX - 150,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(new Color((int) (katiePixel.getRed() * 0.5 +
                                              jennyPixel.getRed() * 0.5),
                                       (int) (katiePixel.getGreen() * 0.5 +
                                              jennyPixel.getGreen() * 0.5),
                                       (int) (katiePixel.getBlue() * 0.5 +
                                              jennyPixel.getBlue() * 0.5)));
      }
    }
    
    // copy the rest of Jenny
    sourceX = sourceX - 150;
    for (; sourceX < jennyPicture.getWidth(); sourceX++, targetX++)
    {
      for (int sourceY = 0, targetY = 0; 
           sourceY < jennyPicture.getHeight(); 
           sourceY++, targetY++)
      {
        jennyPixel = jennyPicture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(jennyPixel.getColor());
      }
    }
    
    // show the canvas
    canvasPicture.show();
    
    // return the canvas
    return canvasPicture;
  }
 
  /**
   * Method to copy the flower but smaller (half as big)
   * @return the smaller flower picture
   */
  public static Picture copyFlowerSmaller()
  {
    Picture flowerPicture = new Picture(Picture.getMediaPath("daisyMed.jpg"));
    Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (int sourceX = 0, targetX=0; 
         sourceX < flowerPicture.getWidth(); 
         sourceX+=2, targetX++)
    {
      // loop through the rows
      for (int sourceY=0, targetY=0; 
           sourceY < flowerPicture.getHeight(); 
           sourceY+=2, targetY++)
      {
        sourcePixel = flowerPicture.getPixel(sourceX,sourceY);
        targetPixel = canvasPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the resulting picture
    canvasPicture.show();
    
    return canvasPicture;
    
  } 
  
  /**
   * A method to scale the current picture object 2 x regular size
   * @return the new scaled picture
   */
  public Picture scale2x()
  {
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    Picture targetPicture = new Picture(this.getWidth() * 2, this.getHeight() * 2);
    
    // loop through the columns
    for (double sourceX = 0, targetX=0; sourceX < getWidth(); 
         sourceX = sourceX + 0.5, targetX++)
    {
      // loop through the rows
      for (double sourceY=0, targetY=0; sourceY < getHeight(); 
           sourceY = sourceY + 0.5, targetY++)
      {
        sourcePixel = getPixel((int) sourceX,(int) sourceY);
        targetPixel = targetPicture.getPixel((int) targetX,(int) targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    return targetPicture;
  }
  
  /**
   * A method create a copy of the current picture and return it
   * @return the copied picture
   */
  public Picture copy()
  {
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    Picture targetPicture = new Picture(this.getWidth(), this.getHeight());
    
    // loop through the columns
    for (int sourceX = 0, targetX=0; sourceX < getWidth(); 
         sourceX++, targetX++)
    {
      // loop through the rows
      for (int sourceY=0, targetY=0; sourceY < getHeight(); 
           sourceY++, targetY++)
      {
        sourcePixel = getPixel(sourceX,sourceY);
        targetPixel = targetPicture.getPixel(targetX,targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    return targetPicture;
  }
  
  /**
   * Method to copy a flower but scaled to 2x normal size
   * @return the larger flower
   */
  public static Picture copyFlowerLarger()
  {
    Picture flowerPicture = new Picture(Picture.getMediaPath("daisyMed.jpg"));
    Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
    Pixel sourcePixel = null;
    Pixel targetPixel = null;
    
    // loop through the columns
    for (double sourceX = 0, targetX=0; sourceX < flowerPicture.getWidth(); 
         sourceX = sourceX + 0.5, targetX++)
    {
      // loop through the rows
      for (double sourceY=0, targetY=0; sourceY <  flowerPicture.getHeight(); 
           sourceY = sourceY + 0.5, targetY++)
      {
        sourcePixel = flowerPicture.getPixel((int) sourceX,(int) sourceY);
        targetPixel = canvasPicture.getPixel((int) targetX,(int) targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    
    // show the resulting picture
    canvasPicture.show();
    
    return canvasPicture;
    
  }  
  
  /**
   * Method to turn to turn Katie into a red head
   */
  public static Picture turnKatieRedHead()
  {
    Color brown = new Color(42,25,15);
    Color currentColor = null;
    Picture katiePicture = new Picture(Picture.getMediaPath("KatieFancy.jpg"));
    Pixel[] pixels = katiePicture.getPixels();
    Pixel pixel = null;
    
    // loop through the pixels
    for (int i=0; i<pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];
      
      // check if in distance to brown and if so reduce blue and green
      if (pixel.colorDistance(brown) < 50.0)
        pixel.setColor(new Color((int) (currentColor.getRed() * 2.0),
                                 currentColor.getGreen(),
                                 currentColor.getBlue()));
    }
    
    // show the result
    katiePicture.show();
    
    return katiePicture;
  }
  
  /**
   * Method to turn to turn Katie into a red head using a range
   */
  public static Picture turnKatieRedHeadInRange()
  {
    Color brown = new Color(42,25,15);
    Color currentColor = null;
    Picture katiePicture = new Picture(Picture.getMediaPath("KatieFancy.jpg"));
    Pixel pixel = null;
    
    // loop through the x values
    for (int x=63; x < 125; x++)
    {
      for (int y=6; y < 76; y++)
      {
        
        // get the current pixel
        pixel = katiePicture.getPixel(x,y);
        
        // check if in distance to brown and if so reduce blue and green
        if (pixel.colorDistance(brown) < 50.0)
          pixel.setColor(new Color((int) (currentColor.getRed() * 2.0),
                                     currentColor.getGreen(),
                                     currentColor.getBlue()));
      }
    }
    
    // show the result
    katiePicture.show();
    
    return katiePicture;
  }
  
  /**
   * Method to remove red eye from the current picture object in the rectange
   * define by startX, startY, endX, endY.  The red will be replaced with the
   * passed newColor
   * @param startX  the top left corner x value of a rectangle
   * @param startY  the top left corner y value of a rectangle
   * @param endX    the bottom right corner x value of a rectangle
   * @param endY    the bottom right corner y value of a rectangle
   * @param newColor the new color to use
   */
  public void removeRedEye(int startX, int startY, int endX, 
                           int endY, Color newColor)
  {
    Pixel pixel = null;
    
    // loop through the pixels in the rectangle defined by the startX, startY, and
    // endX and endY
    for (int x = startX; x < endX; x++)
    {
      for (int y = startY; y < endY; y++)
      {
        // get the current pixel
        pixel = getPixel(x,y);
        
        // if the color is near red then change it
        if (pixel.colorDistance(Color.red) < 167)
          pixel.setColor(newColor);
      }
    }
  }
  
  /**
   * Method to change the current picture to a sepia 
   * tint (modify the middle colors to a light brown and
   * the light colors to a light yellow and make the shadows darker
   */
  public void sepiaTint()
  {
    Pixel pixel = null;
    double redValue = 0;
    double greenValue = 0;
    double blueValue = 0;
    
    // first change the current picture to grayscale
    this.grayscale();
    
    // loop through the pixels
    for (int x = 0; x < this.getWidth(); x++)
    {
      for (int y = 0; y < this.getHeight(); y++)
      {
        // get the current pixel and color values
        pixel = this.getPixel(x,y);
        redValue = pixel.getRed();
        greenValue = pixel.getGreen();
        blueValue = pixel.getBlue();
        
        // tint the shadows darker
        if (redValue < 60)
        {
          redValue = redValue * 0.9;
          greenValue = greenValue * 0.9;
          blueValue = blueValue * 0.9; 
        }
        
        // tint the midtones a light brown
        // by reducing the blue
        else if (redValue < 190)
        {
          blueValue = blueValue * 0.8;
        }
        
        // tint the highlights a light yellow
        // by reducing the blue
        else 
        {
          blueValue = blueValue * 0.9;
        }
        
        // set the color
        pixel.setColor (new Color((int) redValue,
                                  (int) greenValue,
                                  (int) blueValue));
      }
    }
  }
  
  /**
   * Method to posterize (reduce the number of colors) in the picture
   * @param numLevels the number of color levels to use
   */
  public void posterize(int numLevels)
  {
    Pixel pixel = null;
    int redValue = 0;
    int greenValue = 0;
    int blueValue = 0;
    int increment = (int) (256.0 / numLevels);
    int bottomValue, topValue, middleValue = 0;
    
    // loop through the pixels
    for (int x = 0; x < this.getWidth(); x++) {
      for (int y = 0; y < this.getHeight(); y++) {
        
        // get the current pixel and colors
        pixel = this.getPixel(x,y);
        redValue = pixel.getRed();
        greenValue = pixel.getGreen();
        blueValue = pixel.getBlue();
        
        // loop through the number of levels
        for (int i = 0; i < numLevels; i++)
        {
          // compute the bottom, top, and middle values
          bottomValue = i * increment;
          topValue = (i + 1) * increment;
          middleValue = (int) ((bottomValue + topValue - 1) / 2.0);
          
          // check if current values are in current range and if so
          // set them to the middle value
          if (bottomValue <= redValue && redValue < topValue)
            pixel.setRed(middleValue);
          if (bottomValue <= greenValue && greenValue < topValue)
            pixel.setGreen(middleValue);
          if (bottomValue <= blueValue && blueValue < topValue)
            pixel.setBlue(middleValue);
        }
      }
    }
  }
  
  /**
   * Method to posterize (reduce the number of colors) in the picture
   * The number of reds, greens, and blues will be 4
   */
  public void posterize()
  {
    Pixel pixel = null;
    int redValue = 0;
    int greenValue = 0;
    int blueValue = 0;
    
    // loop through the pixels
    for (int x = 0; x < this.getWidth(); x++) {
      for (int y = 0; y < this.getHeight(); y++) {
        
        // get the current pixel and colors
        pixel = this.getPixel(x,y);
        redValue = pixel.getRed();
        greenValue = pixel.getGreen();
        blueValue = pixel.getBlue();
        
        // check for red range and change color
        if (redValue < 64)
          redValue = 31;
        else if (redValue < 128)
          redValue = 95;
        else if (redValue < 192)
          redValue = 159;
        else 
          redValue = 223;
        
        // check for green range
        if (greenValue < 64)
          greenValue = 31;
        else if (greenValue < 128)
          greenValue = 95;
        else if (greenValue < 192)
          greenValue = 159;
        else
          greenValue = 223;
        
        // check for blue range
        if (blueValue < 64)
          blueValue = 31;
        else if (blueValue < 128)
          blueValue = 95;
        else if (blueValue < 192)
          blueValue = 159;
        else
          blueValue = 223;
        
        // set the colors
        pixel.setRed(redValue);
        pixel.setGreen(greenValue);
        pixel.setBlue(blueValue);
      }
    }
  }
  
  /**
   * Method to blur the pixels
   * @param numPixels the number of pixels to average in all directions so if the
   * numPixels is 2 then we will average all pixels in the rectange defined by 2 before
   * the current pixel to 2 after the current pixel
   */
  public void blur(int numPixels)
  {
    Pixel pixel = null;
    Pixel samplePixel = null;
    int redValue = 0;
    int greenValue = 0;
    int blueValue = 0;
    int count = 0;
    
    // loop through the pixels
    for (int x=0; x < this.getWidth(); x++) {
      for (int y=0; y < this.getHeight(); y++) {
        
        // get the current pixel
        pixel = this.getPixel(x,y);
        
        // reset the count and red, green, and blue values
        count = 0;
        redValue = greenValue = blueValue = 0;
        
        // loop through pixel numPixels before x to numPixels after x
        for (int xSample = x - numPixels; xSample <= x + numPixels; xSample++) {
          for (int ySample = y - numPixels; ySample <= y + numPixels; ySample++) {
            
            // check that we are in the range of acceptable pixels
            if (xSample >= 0 && xSample < this.getWidth() &&
                ySample >= 0 && ySample < this.getHeight()) {
              samplePixel = this.getPixel(xSample,ySample);
              redValue = redValue + samplePixel.getRed();
              greenValue = greenValue + samplePixel.getGreen();
              blueValue = blueValue + samplePixel.getBlue();
              count = count + 1;
            }
          }
        }
        
        // use average color of surrounding pixels
        Color newColor = new Color(redValue / count, 
                                   greenValue / count, 
                                   blueValue / count);
        pixel.setColor(newColor);      
      }
    }
  }
  
  /**
   * Method to blur the pixels using a copy of the original as the source for the
   * average
   * @param numPixels the number of pixels to average in either direction so if the 
   * numPixels is 2 then we will average all pixels in the rectange defined by 2 before
   * current to 2 after current
   */
  public void blurCopy(int numPixels)
  {
    Pixel pixel = null;
    Pixel samplePixel = null;
    int redValue = 0;
    int greenValue = 0;
    int blueValue = 0;
    int count = 0;
    Picture copy = this.copy();
    
    // loop through the pixels
    for (int x=0; x < this.getWidth(); x++) {
      for (int y=0; y < this.getHeight(); y++) {
        
        // get the current pixel
        pixel = this.getPixel(x,y);
        
        // reset the count and red, green, and blue values
        count = 0;
        redValue = greenValue = blueValue = 0;
        
        // loop through pixel numPixels before x to numPixels after x
        for (int xSample = x - numPixels; xSample <= x + numPixels; xSample++) {
          for (int ySample = y - numPixels; ySample <= y + numPixels; ySample++) {
            
            // check that we are in the range of acceptable pixels
            if (xSample >= 0 && xSample < this.getWidth() &&
                ySample >= 0 && ySample < this.getHeight()) {
              samplePixel = copy.getPixel(xSample,ySample);
              redValue = redValue + samplePixel.getRed();
              greenValue = greenValue + samplePixel.getGreen();
              blueValue = blueValue + samplePixel.getBlue();
              count = count + 1;
            }
          }
        }
        
        // use average color of surrounding pixels
        Color newColor = new Color(redValue / count, 
                                   greenValue / count, 
                                   blueValue / count);
        pixel.setColor(newColor);      
      }
    }
  }
  
  /**
   * Method to replace the background in the current picture with the background
   * from another picture
   * @param oldBackground a picture with the old background to replace
   * @param newBackground a picture with the new background to use
   */
  public void swapBackground(Picture oldBackground, Picture newBackground)
  {
    Pixel currPixel = null;
    Pixel oldPixel = null;
    Pixel newPixel = null;

    // loop through the columns
    for (int x=0; x<getWidth(); x++) 
    {
     
      // loop through the rows
      for (int y=0; y<getHeight(); y++) 
      {
        
        // get the current pixel and old background pixel
        currPixel = this.getPixel(x,y);
        oldPixel = oldBackground.getPixel(x,y);
        
        /* if the color at the current pixel is within 15.0 of the old background pixel
         * then swap in the new background pixel
         */
        if (currPixel.colorDistance(oldPixel.getColor()) < 50.0)
        {
          newPixel = newBackground.getPixel(x,y);
          currPixel.setColor(newPixel.getColor());
        }
      }
    }
  }
  
  /**
   * Method to replace the background in the current picture with the background
   * from another picture for pixels that have a color distance to the old
   * background of under the passed threshold
   * @param oldBackground a picture with the old background to replace
   * @param newBackground a picture with the new background to use
   * @param threshold the distance from the old background color to use
   * to figure out which pixels to swap with the new background
   */
  public void swapBackgroundForThreshold(Picture oldBackground, 
                                         Picture newBackground,
                                         double threshold)
  {
    Pixel currPixel = null;
    Pixel oldPixel = null;
    Pixel newPixel = null;

    // loop through the columns
    for (int x=0; x<getWidth(); x++) 
    {
     
      // loop through the rows
      for (int y=0; y<getHeight(); y++) 
      {
        
        // get the current pixel and old background pixel
        currPixel = this.getPixel(x,y);
        oldPixel = oldBackground.getPixel(x,y);
        
        /* if the color at the current pixel is within 15.0 of the old background pixel
         * then swap in the new background pixel
         */
        if (currPixel.colorDistance(oldPixel.getColor()) < threshold)
        {
          newPixel = newBackground.getPixel(x,y);
          currPixel.setColor(newPixel.getColor());
        }
      }
    }
  }
  
  /**
   * Method to do chromakey using a blue background
   * @param newBg the new background image to use to replace 
   * the blue from the current picture
   */
  public void chromakey(Picture newBg)
  {
    Pixel currPixel = null;
    Pixel newPixel = null;

    // loop through the columns
    for (int x=0; x<getWidth(); x++) 
    {
     
      // loop through the rows
      for (int y=0; y<getHeight(); y++) 
      {
        
        // get the current pixel 
        currPixel = this.getPixel(x,y);
        
        /* if the color at the current pixel mostly blue (blue value is
         * greater than red and green combined, then use new background color
         */
        if (currPixel.getRed() + currPixel.getGreen() < currPixel.getBlue())
        {
          newPixel = newBg.getPixel(x,y);
          currPixel.setColor(newPixel.getColor());
        }
      }
    }
  }
  
  /**
   * Method to do chromakey using a blue background
   * @param newBg the new background image to use to replace 
   * the blue from the current picture
   */
  public void chromakeyBlue(Picture newBg)
  {
    Pixel[] pixels = this.getPixels();
    Pixel currPixel = null;
    Pixel newPixel = null;
    
    // loop through the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel 
      currPixel = pixels[i];
      
      /* if the color at the current pixel mostly red (red value is
       * greater than green and blue combined, then use new background color
       */
      if (currPixel.getRed() + currPixel.getGreen() < currPixel.getBlue())
      {
        newPixel = newBg.getPixel(currPixel.getX(),currPixel.getY());
        currPixel.setColor(newPixel.getColor());
      }
      
    }
  }
  
  /**
   * Method to do chromakey using a red background
   * @param newBg the new background image to use to replace 
   * the blue from the current picture
   */
  public void chromakeyRed(Picture newBg)
  {
    Pixel[] pixels = this.getPixels();
    Pixel currPixel = null;
    Pixel newPixel = null;
    
    // loop through the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel 
      currPixel = pixels[i];
      
      /* if the color at the current pixel mostly blue (blue value is
       * greater than red and green combined, then use new background color
       */
      if (currPixel.getRed() > currPixel.getGreen() + currPixel.getBlue())
      {
        newPixel = newBg.getPixel(currPixel.getX(),currPixel.getY());
        currPixel.setColor(newPixel.getColor());
      }
      
    }
  }
  
  /**
   * Method to add vertical and horizontal lines to the current picture
   */
  public void addLines()
  {
    addHorizontalLines();
    addVerticalLines();
  }
  
  /** 
   * Method to add a horizontal line every 5 pixels in the current picture 
   */
  public void addHorizontalLines()
  {
    // loop through rows
    for (int y = 0; y < getHeight(); y+=5)
    {
      // loop through the columns
      for (int x = 0; x < getWidth(); x++)
      {
        // set the pixel to black
        this.getPixel(x,y).setColor(Color.black);
      }
    }
  }
  
  /**
   * Method to add a vertical line every 5 pixels in the current picture
   */
  public void addVerticalLines()
  {
    
    // loop through the columns
    for (int x = 0; x < getWidth(); x+=5)
    {
      // loop through the rows
      for (int y=0; y < getHeight(); y++)
      {
        // set the pixel to black
        this.getPixel(x,y).setColor(Color.black);
      }
    }
  }
  
  /**
   * Method to show using drawing on a picture
   * @return the example picture
   */
  public static Picture drawExample()
  {
    // start with a white 640 by 480 picture
    Picture p = new Picture(Picture.getMediaPath("640x480.jpg"));

    // get the graphics object to use for drawing
    Graphics graphics = p.getGraphics();

    // start with a black color
    graphics.setColor(Color.black);

    // draw the string with a upper left corner at x=10, y=75
    graphics.drawString("This is a test of drawing a string on a picture",10,75);

    // draw a line from (10,20) to (300,50)
    graphics.drawLine(10,20,300,50);

    // set the color to yellow
    graphics.setColor(Color.yellow);

    // draw a filled rectangle (filled with yellow) at upper left (0,200) with
    // a width of 300 and height 250
    graphics.fillRect(0,200,300,250);

    // set the color back to black
    graphics.setColor(Color.black);

    // draw the outline of a rectangle with the upper left at (10,210) and
    // a width of 200 and a height of 100
    graphics.drawRect(10,210,200,100);
    
    /* draw an oval enclosed by a rectangle with the top left corner at
     * (400,10) and a width of 200 and a height of 100 
     */
    graphics.drawOval(400,10,200,100);
    
    /* draw an arc which is part of an oval enclosed by a rectangle with the
     * top left corner at (400,300) a width of 200, and a height of 150.  The
     * arc starts at 0 (3 o'clock position) and goes 180 degrees counter-clockwise
     * to the 9 o'clock position
     */
    graphics.fillArc(400,300,200,150,0,180);

    // show the picture
    p.show();

    // return the picture
    return p;
  }
  
  /**
   * Method to draw a gray effect picture
   * @return the picture that shows the gray effect
   */
  public static Picture drawGrayEffect()
  {
    // create a picture to draw on
    Picture pic = new Picture(400,100);
    
    // create a medium gray color to use
    Color medGray = new Color(100,100,100);
    
    // Do 100 columns of medium gray
    for (int x = 0; x < 100; x++)
      for (int y = 0; y < 100; y++)
        pic.getPixel(x,y).setColor(medGray);
    
    // Do 100 columns of gray starting at medium gray and getting lighter
    for (int x=100, grayLevel=100; x < 200; x++,grayLevel++)
      for (int y=0; y < 100; y++)
        pic.getPixel(x,y).setColor(new Color(grayLevel,grayLevel,grayLevel));
    
    // Do 100 columns starting at black and getting lighter
    for (int x=200, grayLevel=0; x < 300; x++, grayLevel++)
      for (int y=0; y < 100; y++)
         pic.getPixel(x,y).setColor(new Color(grayLevel,grayLevel,grayLevel));
    
    // Do 100 columns of medium gray
    for (int x=300; x < 400; x++)
      for (int y=0; y < 100; y++)
         pic.getPixel(x,y).setColor(medGray);
    
    // show the picture
    pic.show();
    
    // return the picture
    return pic;
  }
      
  /**
   * Method to draw a picture with a succession of filled rectangles 
   * with the top left corner the darkest and the bottom right the 
   * lightest
   * @return the picture with the filled rectangles
   */
  public static Picture drawFilledRectangles()
  {
    Picture p = new Picture(250,250);
    Graphics g = p.getGraphics();
    Color color = null;
    
    // loop 25 times
    for (int i = 25; i > 0; i--)
    {
      color = new Color(i * 10, i * 5, i);
      g.setColor(color);
      g.fillRect(0,0,i*10,i*10);
    }
    
    // show the picture
    p.show();
    
    // return the picture
    return p;
  }
  
  /**
   * Method to draw a picture with a succession of rectangles 
   * @return the picture with the filled rectangles
   */
  public static Picture drawRectangles()
  {
    Picture p = new Picture(Picture.getMediaPath("640x480.jpg"));
    Graphics g = p.getGraphics();
    Color color = null;
    
    // loop 25 times
    for (int i = 25; i > 0; i--)
    {
      g.setColor(Color.black);
      g.drawRect(i,i,i*3,i*4);
      g.drawRect(100+i*4,100+i*3,i*8,i*10);
    }
    
    // show the picture
    p.show();
    
    // return the picture
    return p;
  }
  
  /**
   * Method to count teh number of white pixels in a picture 
   */
  public int countWhite()
  {
    int count = 0;
    Pixel pixel = null;
    Pixel[] pixels = this.getPixels();
    for (int i=0; i < pixels.length; i++)
    {
      pixel = pixels[i];
      if (pixel.getRed() == 255 && pixel.getGreen() == 255 && pixel.getBlue() == 255)
        count++;
    }
    return count;
  }
 /**
   * Method to scale the picture by a factor, and return the result
   * @param scale factor to scale by (1.0 stays the same, 0.5 decreases each side by 0.5, 2.0 doubles each side)
   * @return the scaled picture
   */
  public Picture scale(double factor)
  {
    Pixel sourcePixel, targetPixel;
    Picture canvas = new Picture((int) (factor*this.getWidth())+1,
                                 (int) (factor*this.getHeight())+1);
    // loop through the columns
    for (double sourceX = 0, targetX=0;
         sourceX < this.getWidth();
         sourceX+=(1/factor), targetX++)
    {
      // loop through the rows
      for (double sourceY=0, targetY=0;
           sourceY < this.getHeight();
           sourceY+=(1/factor), targetY++)
      {
        sourcePixel = this.getPixel((int) sourceX,(int) sourceY);
        targetPixel = canvas.getPixel((int) targetX, (int) targetY);
        targetPixel.setColor(sourcePixel.getColor());
      }
    }
    return canvas;
  }


  /**
   * Method to do chromakey using an input color for background
   * at a given point.
   * @param target the picture onto which we chromakey this picture
   * @param bgcolor the color to make transparent
   * @param threshold within this distance from bgcolor, make transparent
   * @param targetx target X position to start at
   * @param targety target Y position to start at
   */
  public void chromakey(Picture target, Color bgcolor, int threshold,
                        int targetx, int targety)
  {
    Pixel currPixel = null;
    Pixel newPixel = null;

    // loop through the columns
    for (int srcx=0, trgx=targetx; srcx<getWidth() && trgx<target.getWidth(); srcx++, trgx++) 
    {
     
      // loop through the rows
      for (int srcy=0, trgy=targety; srcy<getHeight() && trgy<target.getHeight(); srcy++, trgy++) 
      {
        
        // get the current pixel 
        currPixel = this.getPixel(srcx,srcy);
        
        /* if the color at the current pixel is within threshold of
         * the input color, then don't copy the pixel
         */
        if (currPixel.colorDistance(bgcolor)>threshold)
        {
          target.getPixel(trgx,trgy).setColor(currPixel.getColor());
        }
      }
    }
  }
    
  /**
   * Method to do chromakey assuming blue background for background
   * at a given point.
   * @param target the picture onto which we chromakey this picture
   * @param targetx target X position to start at
   * @param targety target Y position to start at
   */
  public void bluescreen(Picture target, 
                        int targetx, int targety)
  {
    Pixel currPixel = null;
    Pixel newPixel = null;

    // loop through the columns
    for (int srcx=0, trgx=targetx; 
         srcx<getWidth() && trgx<target.getWidth(); 
         srcx++, trgx++) 
    {
     
      // loop through the rows
      for (int srcy=0, trgy=targety; 
           srcy<getHeight() && trgy<target.getHeight(); 
           srcy++, trgy++) 
      {
        
        // get the current pixel 
        currPixel = this.getPixel(srcx,srcy);
        
        /* if the color at the current pixel mostly blue (blue value is
         * greater than red and green combined), then don't copy pixel
         */
        if (currPixel.getRed() + currPixel.getGreen() > currPixel.getBlue())
        {
          target.getPixel(trgx,trgy).setColor(currPixel.getColor());
        }
      }
    }
  }

  /**
   * Method to compose this picture onto target
   * at a given point.
   * @param target the picture onto which we chromakey this picture
   * @param targetx target X position to start at
   * @param targety target Y position to start at
   */
  public void compose(Picture target, int targetx, int targety)
  {
    Pixel currPixel = null;
    Pixel newPixel = null;

    // loop through the columns
    for (int srcx=0, trgx = targetx; srcx < getWidth(); 
         srcx++, trgx++) 
    {
     
      // loop through the rows
      for (int srcy=0, trgy=targety; srcy < getHeight(); 
           srcy++, trgy++) 
      {
        
        // get the current pixel 
        currPixel = this.getPixel(srcx,srcy);
        
        /* copy the color of currPixel into target,
         * but only if it'll fit.
         */
        if (trgx < target.getWidth() && trgy < target.getHeight())
        {
          newPixel = target.getPixel(trgx,trgy);
          newPixel.setColor(currPixel.getColor());
        }
      }
    }
  }

  /**
   * Method to flip an image left-to-right
   **/
  public Picture flip() {
    
    Pixel currPixel;
    Picture target = new Picture(this.getWidth(),this.getHeight());
    
    for (int srcx = 0, trgx = getWidth()-1; srcx < getWidth(); srcx++, trgx--)
    {
      for (int srcy = 0, trgy = 0; srcy < getHeight(); srcy++, trgy++)
      {
        // get the current pixel 
        currPixel = this.getPixel(srcx,srcy);
        
        /* copy the color of currPixel into target
         */
        target.getPixel(trgx,trgy).setColor(currPixel.getColor());
      }
    };
    return target;
  }
  
    /**
   * Method to reduce blue by 25% and increase green by 50%
   */
  public void reduceBlueIncreaseGreen()
  {
    Pixel[] pixels = this.getPixels();
    Pixel pixel = null;
    int value = 0;

    // loop through all the pixels
    for (int i = 0; i < pixels.length; i++)
    {
      // get the current pixel
      pixel = pixels[i];

      // get the value
      value = pixel.getBlue();

      // set the blue value to 75% of what it was
      pixel.setBlue((int) (value * 0.75));
      
      // get the value
      value = pixel.getGreen();

      // set the green value to 150% of what it was
      pixel.setGreen((int) (value * 1.50));

    }
  }

  
}