/*****************************************************************
* PictureDisplay
*
* Description: This class interacts with the Picture class to 
*              display and manipulate an image
*
* Input: An image on disk
*
* Output: Display Image in a GUI
*
******************************************************************/

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.MouseInputListener;
public class PictureDisplay extends JPanel implements ActionListener, MouseInputListener{
	
	private JButton flipHorizontal;
	private JButton flipVertical;
	private JButton scaleUp;
	private JButton scaleDown;
	private JButton reset;
	private JLabel info;
	private Picture picture;
	private BufferedImage img;
	private int mouseX;
	private int mouseY;
	private int newMouseX;
	private int newMouseY;
	private boolean drawRect;
	private JFrame jf;
	
	public PictureDisplay(){
		jf = new JFrame();
		jf.setLayout(new BorderLayout());
		
		drawRect=false;
		
		setupPicture();
		
		Dimension d = new Dimension(picture.getWidth(),picture.getHeight());
		this.setPreferredSize(d);
		
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		
		flipHorizontal = new JButton("Flip Horizontally");
		flipVertical = new JButton("Flip Vertically");
		scaleDown = new JButton("Scale Down");
		scaleUp = new JButton("Scale Up");
		reset = new JButton("Reset");
		
		info = new JLabel("");
		info.setText(picture.getWidth()+"x"+picture.getHeight());
		
		flipHorizontal.addActionListener(this);
		flipVertical.addActionListener(this);
		scaleDown.addActionListener(this);
		scaleUp.addActionListener(this);
		reset.addActionListener(this);
		
		JPanel buttons = new JPanel(new GridLayout(5,1));
		buttons.add(flipHorizontal);
		buttons.add(flipVertical);
		buttons.add(scaleDown);
		buttons.add(scaleUp);
		buttons.add(reset);
		
		jf.add(this,BorderLayout.CENTER);
		jf.add(buttons,BorderLayout.EAST);
		jf.add(info,BorderLayout.SOUTH);
		jf.pack();
		
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);
		jf.setResizable(false);
	}
	
	public void paint(Graphics g){
		if (!drawRect)
			for (int x=0;x<picture.getWidth();x++)
				for (int y=0;y<picture.getHeight();y++)
					img.setRGB(x,y,picture.getPixel(x, y));
		g.drawImage(img,0,0,null);
		if (!drawRect(g))
			info.setText(picture.getWidth()+"x"+picture.getHeight());
	}
	
	public boolean drawRect(Graphics g){
		if (!drawRect)
			return false;
		int minx=Math.max(Math.min(mouseX, newMouseX),0);
		int maxx=Math.min(Math.max(mouseX, newMouseX),picture.getWidth()-1);
		int miny=Math.max(Math.min(mouseY, newMouseY),0);
		int maxy=Math.min(Math.max(mouseY, newMouseY),picture.getHeight()-1);
		int width=maxx-minx;
		int height=maxy-miny;
		g.setColor(Color.YELLOW);
		if (width>0&&height>0){
			g.drawRect(minx,miny,width,height);
			info.setText(picture.getWidth()+"x"+picture.getHeight()+" Rectangle: "+width+"x"+height);
			return true;
		}
		return false;
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource()==flipHorizontal)
			picture.flipHorizontal();
		else if (e.getSource()==flipVertical)
			picture.flipVertical();
		else if (e.getSource()==scaleDown)
			picture.scaleDown();
		else  if (e.getSource()==scaleUp)
			picture.scaleUp();
		else if (e.getSource()==reset)
			setupPicture();		
		if (picture.getWidth()!=this.getWidth()||picture.getHeight()!=this.getHeight()){
			img = new BufferedImage(picture.getWidth(),picture.getHeight(),BufferedImage.TYPE_INT_RGB);
			Dimension d = new Dimension(picture.getWidth(),picture.getHeight());
			this.setPreferredSize(d);
			jf.pack();
			jf.repaint();
		}
		repaint();
	}
	
	public void setupPicture(){
		BufferedImage image=null;
		
		if (image==null)
			try {
				image = ImageIO.read(new File(System.getProperty("user.dir")+File.separator+"sample.jpg"));
			} catch (IOException e) {}
		
		if (image==null)
			try {
				image = ImageIO.read(new File(System.getProperty("user.dir")+File.separator+"src"+File.separator+"sample.jpg"));
			} catch (IOException e) {}
		
		if (image==null)
			try {
				image = ImageIO.read(new URL("http://www.cs.unc.edu/~jbhansen/comp110/assignments/images/sample.jpg"));
			} catch (IOException e) {}
		
		if (image==null)
			try {
				JFileChooser fc = new JFileChooser();
				fc.setDialogTitle("Select an image file to open:");
				int returnVal = fc.showOpenDialog(this);
	
				if (returnVal == JFileChooser.APPROVE_OPTION)
					image = ImageIO.read(fc.getSelectedFile());
		        else
		            System.exit(0);
	
				
			} catch (IOException e) {
				System.out.println("Could not open image file!");
				System.exit(0);
			}
		
		int width=image.getWidth();
		int height=image.getHeight();
		Raster raster = image.getData();
		
		picture = new Picture(width,height);
		img = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
		
		for (int x=0;x<width;x++)
			for (int y=0;y<height;y++){
				int[] pixelArray = new int[3];
				raster.getPixel(x, y, pixelArray);
				picture.setPixel(x, y, new Color(pixelArray[0],pixelArray[1],pixelArray[2]).getRGB());
			}
		Dimension d = new Dimension(picture.getWidth(),picture.getHeight());
		this.setPreferredSize(d);
	}
	

	public void mouseDragged(MouseEvent e) {
		if ((e.getModifiersEx()&MouseEvent.BUTTON2_DOWN_MASK)!=0||(e.getModifiersEx()&MouseEvent.ALT_DOWN_MASK)!=0){
			drawRect=true;
			newMouseX=e.getX();
			newMouseY=e.getY();
		}else{
			picture.translate(e.getX()-mouseX,e.getY()-mouseY);
			mouseX=e.getX();
			mouseY=e.getY();
		}
		repaint();
	}
	
	public void mousePressed(MouseEvent e) {
		mouseX=e.getX();
		mouseY=e.getY();
		newMouseX=e.getX();
		newMouseY=e.getY();
	}
	
	public void mouseReleased(MouseEvent e) {
		if ((e.getModifiersEx()&MouseEvent.BUTTON2_DOWN_MASK)!=0||(e.getModifiersEx()&MouseEvent.ALT_DOWN_MASK)!=0){
			int minx=Math.max(Math.min(mouseX, e.getX()),0);
			int maxx=Math.min(Math.max(mouseX, e.getX()),picture.getWidth()-1);
			int miny=Math.max(Math.min(mouseY, e.getY()),0);
			int maxy=Math.min(Math.max(mouseY, e.getY()),picture.getHeight()-1);
			int width=maxx-minx;
			int height=maxy-miny;
			if (width>0&&height>0){
				picture.crop(minx,miny,width,height);
				if (picture.getWidth()!=this.getWidth()||picture.getHeight()!=this.getHeight()){
					img = new BufferedImage(picture.getWidth(),picture.getHeight(),BufferedImage.TYPE_INT_RGB);
					Dimension d = new Dimension(picture.getWidth(),picture.getHeight());
					this.setPreferredSize(d);
					jf.pack();
					jf.repaint();
				}
			}
		}
		drawRect=false;
		
		
	}

	public void mouseMoved(MouseEvent arg0) {}

	public void mouseClicked(MouseEvent e) {}

	public void mouseEntered(MouseEvent e) {}

	public void mouseExited(MouseEvent e) {}

	
	
	public static void main(String[] args){
		new PictureDisplay();
	}


}
