/**
 * @(#)Menu.java
 *
 * <code>Menu</code> class is the class controlling the buttons
 * over the main screen. To bind the Menu class to Display class
 * and vice versa, both of the classes have reference variables
 * pointing to each other. This way, the Menu will be easy-to-change
 * and Display will consist of less code.
 *
 * @author Onur Erdem
 * @version 1.00 21.12.2009
 */
 
package bin;
 
import java.awt.image.BufferedImage;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import javax.swing.border.EmptyBorder;
import java.awt.event.MouseEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JTextField;
import javax.swing.JColorChooser;
import javax.imageio.ImageIO;
import java.io.File;
import java.util.Scanner;

public class Menu {

    /**
	 * <code>menuImage</code><br>
     * Image of the menu.
     */
    private BufferedImage menuImage;
	
	/**
	 * <code>hoverMenuImage</code><br>
     * Image of the hover menu.
     */
    private BufferedImage hoverMenuImage;
	
	/**
	 * <code>hMI</code><br>
     * Whether the hoverMenu is open.
     */
    private boolean hMI=false;
	
	/**
	 * <code>gotoPageField</code><br>
     * Used for "go to page" feature.
     */
    private JTextField gotoPageField = new JTextField(6);
	
    /**
	 * <code>menuMapImage</code><br>
	 * The "color map" for the toolbar.
	 */
	private BufferedImage menuMapImage;
	
	/**
	 * <code>mMI</code><br>
     * The menu map image.
     */
    private BufferedImage mMI;
    
    /**
	 * <code>hMMI</code><br>
     * The hoverMenu map image.
     */
    private BufferedImage hMMI;

    /**
	 * <code>menuHover</code><br>
	 * Holds the color value read using
	 * BufferedImage's getRGB() method.
	 * Since getRGB() returns an int value,
	 * menuHover is not a Color object.
	 */
    private int menuHover=0;
        
    /**
	 * <code>cf</code><br>
     * Configurations object to allow the menu 
     * reach to the settings.
     */
    private Configurations cf;
    
    /**
	 * <code>d</code><br>
     * Reference to the Display object.
     */
    private Display d;
    
    /**
	 * Menu's constructor.
	 * @param dis A reference to the caller Display object.
	 * @param conf A reference to the Configurations object.
     */
    public Menu(Display dis,Configurations conf) {
    	// Assign d
    	d = dis;
    	// Assign cf
    	cf = conf;
		// Don't use any layout in Display!
		d.setLayout(null);
    	// Set gotoPageField's location
    	gotoPageField.setLocation(141,14);
    	// Set gotoPageField's size
    	gotoPageField.setSize(74,25);
    	// Remove gotoPageField's borders
    	gotoPageField.setBorder(new EmptyBorder(0, 0, 0, 0));
    	// Set the background color to white
    	gotoPageField.setBackground (Color.WHITE);
    	// Add a keyListener to the field ...
    	gotoPageField.addKeyListener(new KeyAdapter(){
    		// ... to ...
    		public void keyReleased(KeyEvent ke) {
    			// ... send some events to the Display object ...
    			d.pressKey(ke);
    			// ... and consume these events.
    			ke.consume();
    		}
    	});
    	// Add gotoPageField to the Display object
    	d.add(gotoPageField);
		// Try to load more crucial images such as...
		try {
			// Load language-specific menu images
			Language.loadResources();
			// ... color map for the menu ...
			mMI = ImageIO.read(new File("images/gui/menumap.bmp"));
			// ... and the color map for the hover menu
			hMMI = ImageIO.read(new File("images/gui/hovermenumap.bmp"));
		// If an exception is thrown
		} catch(Exception ex) {
			// Should never happen
			System.out.println(Language.getText(0)+ex);
			// Exit
			System.exit(0);
		}
		// Assign the menu image
		menuImage = Language.getMenu();
		// Assign the hover menu image
		hoverMenuImage = Language.getHoverMenu();
		// Assign the menu map image
		menuMapImage = mMI;
    }
    
    /**
	 * <code>mouseReleased</code><br>
	 * MouseListener's method. Called when mouse is released.
     * @param e The MouseEvent object.
     */
    public void mouseReleased(MouseEvent e) {
		// Switch according to the color
		switch (colorMapIndicator(e)) {
			case 1:  // Help
				// Dispose the current Display object
				d.dispose();
				// Set the book path to null
				cf.setBookPath("");
				// Go to the first page
				cf.setPageNum(0);
		    	// Save the configurations
		    	cf.saveConfigurations();
				// Create a new Display object
				new Display();
				// End of case
				break;
			case 2:  // Open Extra Menu
				// Toggle Menu
				hMI = !hMI;
				// Assign the menuMapImage to either hoverMenu's or menu's map
				menuMapImage = (hMI)?hMMI:mMI;
				// Set gotoPageField enabled of disabled accordingly
				gotoPageField.setEnabled(!hMI);
				// Refresh the page
				d.repaint();
				// Break
				break;
			case 3:  // Goto Page
				// Try to ...
				try {
					// ... create a Scanner to read gotoPageField's text ...
					Scanner scan = new Scanner(gotoPageField.getText());
					// ... and go to the specified page ...
					d.toPage(scan.nextInt()-1);
				// If gotoPageField consists no valid integer
				} catch (Exception eex) {
					// Clear the text the field has
					gotoPageField.setText("");
				}
				// Break
				break;
			case 4:  // Open File...
				// Save things again, just in case
				d.updateConfig();
				try {
					// Create a new ReadFiles object
					ReadFiles a = new ReadFiles();
					// Get the book path and update config
					cf.setBookPath(a.getPath());
					// Go to the first page
					cf.setPageNum(0);
					// Update config file
					d.updateConfig();
					// Dispose this one
					d.dispose();
					// Create a new Display object
					new Display();
				// If Cancel is pressed
				} catch (Exception ex) {
					// Give up
					break;
				}
				// End of case
				break;
			case 5:  // Select Language
				// Choose a language from the gallery
				new LanguageGallery(d);
				// Break
				break;
			case 6:  // Exit
				// Simply exit
				System.exit(0);
				// End of case
				break;
			case 7:  // First Page
				d.firstPage();
				// End of the case
				break;
			case 8:  // Prev. Page
				d.prevPage();
				// End of the case
				break;
			case 9:  // Credits
				// Create a new Credits instance
				new Credits();
				// End of the case
				break;
			case 10: // Next Page
				d.nextPage();
				// End of the case
				break;
			case 11: // Last Page
				d.lastPage();
				// End of the case
				break;
			// HOVER MENU OPTIONS
			case 12:  // FONT FACE
				// Check if another FontChooser is open, if not, ...
				if (!FontChooser.isAlreadyOpen() ) {
					//... then create one
					FontChooser chooseFont = new FontChooser(d, d.getFont().getName() );
					// Put it in the middle of the screen
					chooseFont.setLocationRelativeTo(null);
					// Make it visible
					chooseFont.setVisible(true);
				}
				// End of the case
				break;
			case 13:  // FONT COLOR
				// Create a new JColorChooser dialog and get the new color
				Color newFontColor = JColorChooser.showDialog(null,Language.getText(2),cf.getFontColor());
				// If not null (which happens when the user presses "cancel")
				if (newFontColor!=null) {
					// Set the new color
					cf.setFontColor(newFontColor);
					// Repaint the screen
					d.repaint();
					// Update config file
					d.updateConfig();
				}
				// End of the case
				break;
			case 14:  // TOGGLE BG IMAGE
				// Toggle useBGImage
				cf.setUseBGImage(!cf.isUseBGImage());
				// Repaint the screen
				d.repaint();
				// Update config file
				d.updateConfig();
				// End of case
				break;
			case 15:  // BG IMAGE
				d.changeBGImage();
				// End of the case
				break;
			case 16:  // BACK COLOR
				// Create a new JColorChooser to choose a background color
				Color newBackColor = JColorChooser.showDialog(null,Language.getText(3),cf.getBackColor());
				// If not null (which happens when Cancel is pressed)
				if (newBackColor!=null) {
					// Update Config
					cf.setBackColor(newBackColor);
					// Repaint the screen
					d.repaint();
					// Update the config file
					d.updateConfig();
				}
				// End of the case
				break;
			case 17: // PRESET THEME
				// Create a new ThemeGallery
				new ThemeGallery(d,cf);
				// End of the case
				break;
			case 18: // SHOW READING DURATION
				// Call ReadingDuration's showTime function
				ReadingDuration.showTime();
				// End of the case
				break;
		}
		// Consume the event, just in case
		e.consume();
    }
    
    /**
	 * <code>mouseMoved</code><br>
	 * MouseListener's method. Called when mouse is moved.
     * @param e The MouseEvent object.
     */
    public void mouseMoved(MouseEvent e) {
    	// Read the color map again
		int newerMenuHover=colorMapIndicator(e);
		// If it is not the same with the previous 
		// one (which means that mouse changed area,
		// for example entered or exited into the field
		// of a button)
		if (newerMenuHover != menuHover) {
			// Update menuHover
			menuHover = newerMenuHover;
			// If not a button
			if (newerMenuHover==0)
				// Set cursor to "default"
				d.setCursor(Cursor.DEFAULT_CURSOR);
			// If it is a button
			else
				// Set cursor to "hand"
				d.setCursor(Cursor.HAND_CURSOR);
		}
		// Consume the event
		e.consume();
	}
	
    /**
     * <code> colorMapIndicator </code><br>
     * Reads a MouseEvent object and returns an 
     * int value. This int value represents the 
     * color at <code>(x,y)</code> position of 
     * the menu's color map image. x and y
     * are read using MouseEvent object's getX()
     * and getY() methods and then transformed
     * to color map's coordinates.
     * @param e the MouseEvent object.
     * @return An int value representing the color code.
     */
	private int colorMapIndicator (MouseEvent e) {
		// Get X position
		int posX = e.getX();
		// If x is inside the bounds
		if (posX >= 0 && posX < Display.PAGEWIDTH) {
			// Return the color value
			return (menuMapImage.getRGB(posX,e.getY()) & 0xffffff);
		// If X is out of bounds
		} else
			// return 0
			return 0;
	}
	
	/**
	 * <code>render</code><br>
	 * The method that renders the menu.
     * @param g2d Graphics2D object to draw on.
     */
    public void render (Graphics2D g2d) {
        // Draw menu image
        g2d.drawImage(menuImage,null,0,0);

        // If hoverMenu is open
        if (hMI)
        	// Draw the hoverMenuImage
	        g2d.drawImage(hoverMenuImage,null,0,0);
	    // If not
        else
        	// Draw gotoPageField
        	gotoPageField.repaint();
	}
	
	/**
	 * <code>isIdle</code><br>
	 * Returns if the mouse is not over a button. Needed for dragging.
     * @param pressed The MouseEvent object.
     * @return true if colorMap value is zero, false otherwise.
     */
    public boolean isIdle(MouseEvent pressed) {
    	// Return if the mouse is not over a button
		return colorMapIndicator(pressed) == 0;
	}
}