package mosaic_draw;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

/**
 * A "Controller" has an associated MosaicPanel and is repsonsible for responding to mouse 
 * events and menu events by taking appropriate actions.
 */
public class Controller {
	
	private MosaicPanel mosaic;  // The MosaicPanel on which this controller acts.
	
	private int currentRed = 180;    // The red component of the current drawing color.
	private int currentGreen = 180;  // The green component of the current drawing color.
	private int currentBlue = 255;   // the blue component of the current drawing color.
	     // Note: The current drawing color is changed in the doSetColor() method.
	
	/**
	 * Constructor; creates a Controller object and specifies the MosaicPanel on which the controller acts.
	 * This method also sets up "listeners" that detect mouse events on the mosaic and call other methods in
	 * this class to respond to the mouse events.
	 */
	public Controller(MosaicPanel controllee) {
		mosaic = controllee;
		mosaic.addMouseListener( new MouseAdapter() {
			public void mousePressed(MouseEvent evt) {
				int c = mosaic.xCoordToColumnNumber(evt.getX());
				int r = mosaic.yCoordToRowNumber(evt.getY());
				doMouseDown(r,c);
			}
			public void mouseReleased(MouseEvent evt) {
				int c = mosaic.xCoordToColumnNumber(evt.getX());
				int r = mosaic.yCoordToRowNumber(evt.getY());
				doMouseUp(r,c);
			}
		});
		mosaic.addMouseMotionListener( new MouseMotionAdapter() {
			public void mouseDragged(MouseEvent evt) {
				int c = mosaic.xCoordToColumnNumber(evt.getX());
				int r = mosaic.yCoordToRowNumber(evt.getY());
				doMouseDrag(r,c);
			}
		});
	}
	
	/**
	 * This method is called when the user presses the mouse in one of the squares of the mosaic.
	 * It just applys the current drawing color to the square.
	 * @param row  the row number of the square where the user released the mouse
	 * @param col  the column number of he square where the user released the mouse
	 */
	private void doMouseDown(int row, int col) {
		applyColor(row,col);
	}
	
	/**
	 * This method is called when the user releases the mouse in one of the squares of the mosaic.
	 * This method does nothing.
	 * @param row  the row number of the square where the user pressed the mouse
	 * @param col  the column number of he square where the user pressed the mouse
	 */
	private void doMouseUp(int row, int col) {
	}
	
	/**
	 * This method is called over and over as the user drags the mouse, after pressing a mouse button.
	 * It just applys the current drawing color to the square.
	 * @param row  the row number of the square where the mouse is currently located
	 * @param col  the column number of he square where the mouse is currently located
	 */
	private void doMouseDrag(int row, int col) {
		applyColor(row,col);
	}

	/**
	 * This method is called when the user selects a command from one of the menus.
	 * (The menus are actually defined in the class named Menus.)  This method simply
	 * checks the command name and calls another method to actually carry out the command.
	 * TODO: Add support for other commands.
	 * @param commandName the text of the command, as shown in the menu.
	 */
	public void doMenuCommand(String commandName) {
		if (commandName.equals("Set Color..."))
			doSetColor();
		else if (commandName.equals("Save PNG Image..."))
			doSaveImage("PNG");
		else if (commandName.equals("Save JPEG Image..."))
			doSaveImage("JPEG");
		else if (commandName.equals("Quit"))
			System.exit(0);
		else { // in case the command is not among those checked above, a message is displayed to the user.
			JOptionPane.showMessageDialog(mosaic,"   Sorry, the command \"" + commandName 
					+ "\"\nis not yet implemented.");
		}
	}
	
	/**
	 * Let's the user select the current drawing color.  A color choice dialog box is displayed to the user.
	 * This method is called by the doMenuCommmand() method when the user selects "Set Color..." from the menus.
	 */
	private void doSetColor() {
		Color c = new Color(currentRed, currentGreen, currentBlue);
		c = JColorChooser.showDialog(mosaic, "Select Drawing Color", c);
		if (c != null) {  // If c is null, it means that the user canceled the dialog.
			currentRed = c.getRed();
			currentGreen = c.getGreen();
			currentBlue = c.getBlue();
		}
	}
	
	/**
	 * Saves the current mosaic image to a file in PNG or JPEGformat.  A file dialog box is displayed to the
	 * user where the user can name the file and select the destination directory.  If the user
	 * selects a file name that already exists, the user is asked whether the existing file should
	 * be replaced.  This method is called by the doMenuCommand() method when the user selects "Save PNG Image"
	 * or "Save JPEG Image" from the menu.  The imageFormat is either "PNG" or "JPEG", depending on which
	 * command was chosen. 
	 */
	private void doSaveImage(String imageFormat) {
		BufferedImage image = mosaic.getImage();
		JFileChooser fileDialog = new JFileChooser();
		String defaultName = "mosaic." + imageFormat.toLowerCase();
		File selectedFile = new File(defaultName);
		fileDialog.setSelectedFile(selectedFile);
		fileDialog.setDialogTitle("Save Image as " + imageFormat + " File");
		int option = fileDialog.showSaveDialog(mosaic);
		if (option != JFileChooser.APPROVE_OPTION)
			return;  // user canceled
		selectedFile = fileDialog.getSelectedFile();
		if (selectedFile.exists()) {
			int response = JOptionPane.showConfirmDialog(mosaic,
					"The file \"" + selectedFile.getName() + "\" already exists.\nDo you want to replace it?",
					"Replace file?",
					JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
			if (response == JOptionPane.NO_OPTION)
				return;
		}
		try {
			if ( ! ImageIO.write(image,imageFormat,selectedFile) )
				JOptionPane.showMessageDialog(mosaic,"Sorry, it looks like " + imageFormat + " files are not supported!");
		}
		catch (Exception e) {
			JOptionPane.showMessageDialog(mosaic,"Sorry, an error occurred while trying to save the file:\n" + e.getMessage());
		}
	}
	
	/**
	 * Apply the current drawing color to the specified squre in the mosaic.  The RGB components of
	 * the current drawing color are in the member variables currentRed, currentGreen, and currentBlue.
	 * TODO: Add support for random color variation.
	 * @param row the row number of the square whose color is to be changed
	 * @param col the column number of the square whose color is to be changed.
	 */
	private void applyColor(int row, int col) {
		mosaic.setColor(row, col, currentRed, currentGreen, currentBlue);
	}
	
	// TODO: Add methods to implement the other menu commands, including Fill, Erase, Frame, and
	//       the three "randomness" commands in the color menu.
	
}

