import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.net.*;

/** An instance contains 
     (1) an image,
     (2) the name (path) of the file from which it was read,
     (3) the image in a JPanel, for putting in a JFrame,
     (4) an ImageMap that allows the displayed image
         (but not the file from which it came) to be changed,
     
     (5) a thumbnail description of it (in a small JPanel),
     
     (6) The name of the "image handler" that created this instance  
     (7) a copy of the original ImageMap (for possible restoration),
     
 */
public class ImageMaintainer {
    
    private Image image; // The image that is currently being used
    private String fileName;  // The name (the whole path) of the file for this image
    private ImagePanel imagePanel; // A panel that contains the image, to be placed in a JFrame
    private ImageMap imageMap; // A map of image, which allows us to change it
    
    private ThumbnailPanel thumbnail; // Thumbnail version of image (it is in this panel)
    
    private ImageHandler imageHand; // The object that is doing all this
    private ImageMap originalMap; // The original image map, for restoration purposes
    
    
    /** Constructor: an instance for image im (none if im = null) with title fileName */
    public ImageMaintainer(Image im, String fileName, ImageHandler imageHand) {
        image= im;
        this.fileName= fileName;
        this.imageHand= imageHand;
        thumbnail= new ThumbnailPanel(im, fileName, imageHand);
        imagePanel= new ImagePanel(image);
        imageMap= new ImageMap(image, image.getHeight(imagePanel), image.getWidth(imagePanel));
        originalMap= imageMap.copy();
    }
    
    // = the image maintained by this ImageMaintainer
    public Image getImage() {
        return image;
    }
    
    // = a panel that contains this image, to go in a JFrame
    public ImagePanel getImagePanel() {
        return imagePanel;
    }
    
    // = the filename for this image
    public String getFileName() {
        return fileName;
    }
    
    // = the ImageMap, which allows us to change the image
    public ImageMap getImageMap() {
        return imageMap;
    }
 
    
    // = the thumbnail panel for this image
    public ThumbnailPanel getThumbnail() {
        return thumbnail;
    }
    

    
    /** = the image for file name f, using the toolkit for jframe */
    public static Image getImage(String f, JFrame jframe) {
        Image image= null;
        try {
            image= jframe.getToolkit().getImage(new URL("file:" + f));
        } 
        catch (MalformedURLException e) {
            System.err.println("Bad URL!");
            return null;
        }
        // set media tracker to wait for image to load
        MediaTracker tracker= new MediaTracker(jframe);
        tracker.addImage(image,0);    
        
        // wait for image to load
        try { tracker.waitForID(0); 
        }
        catch (InterruptedException e) {
            // handler.flashMessage(ImageHandler.LOAD_INTERRUPTED);
            return null;
        }
        return image;
    }
    
    /** = the file name of an image loaded by the user using a dialog window */
    public static String getImageName() {
        FileDialog fd = new FileDialog(new Frame(), "Open File", FileDialog.LOAD);
        fd.setVisible(true);
        if (fd.getFile() == null) 
            return null;
        return fd.getDirectory() + fd.getFile();
    }
    
    // Create an image from image map
    public void formImage(ImageMap map) {
        int rows= map.getRows();
        int cols= map.getCols();
        image= imagePanel.createImage(
               new MemoryImageSource(cols,rows,map.getMap(),0,cols));
        imagePanel.changeImage(image);
        thumbnail.setImage(image);
        //imageCanvas= new ImageCanvas(this);
        //handler.displayThumbnails();
        //pack();
        //setVisible(false);
        //setVisible(true);
    }
    
    // Invert the image, replacing each element with its color complement
    // When done, call formImage(imageMap).
    public void invert() {
        //System.out.println("in body of invert");
        DirectColorModel dm = (DirectColorModel) ColorModel.getRGBdefault();
        
        int rows= imageMap.getRows();
        int cols= imageMap.getCols();
        // invert all pixels (leave alpha/transparency value alone)
        for (int i=0; i<rows; i++)
            for (int j=0; j<cols; j++) {
            int rgb= imageMap.getPixel(i,j);
            int red= 255 - dm.getRed(rgb);
            int blue= 255 - dm.getBlue(rgb);
            int green= 255 - dm.getGreen(rgb);
            int alpha= dm.getAlpha(rgb);
            imageMap.setPixel(i,j,
                              (alpha << 24) | (red << 16) | (green << 8) | blue);
        } 
        formImage(imageMap);
    }
    
       /** Transpose the image that is in variable imageMap. When done, call
        formImage(imageMap).
        Transposing will require constructing a new variable b (say) of class imageMap,
        storing the transpose of imageMap in b, and then assigning b to imageMap
        
        */
    public void transpose() {
        // Put your code for transposing the image here and delete this comment
        
        
        
        formImage(imageMap);
    }
    
    /** Reflect the image in variable imageMap around the horizontal middle.
        This turns it upside down. When done, call formImage(imageMap).
        Look in class ImageMap for methods for manipulating the rectangular
        array of pixels in the image.
        */
    public void hreflect() {
        // Put your code for reflecting the image here and delete this comment
        
        formImage(imageMap);
    }
    
    /** Reflect this image (in variable imageMap) around the vertical middle.
        This swaps the left and right sides. When done, call formImage(imageMap).
        Look in class ImageMap for methods for manipulating the rectangular
        array of pixels in the image.
        */
    public void vreflect() {
        // Put your code for reflecting the image here and delete this comment
        
        formImage(imageMap);
    }
    
    /** Restore the original image */
    public void restore() {
        imageMap= originalMap.copy();
        formImage(imageMap);
    }
    
    
    
    
}