/*****************************************************************
* MouseMaze.java
* Programmer: John Hansen
* Last Edited: February 19, 2009
* 
* This class creates a window that corresponds to a maze. Inside
* the maze is a blindfolded mouse who will search for cheese using
* only the power of scent.
*
******************************************************************/

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class MouseMaze extends JPanel implements ActionListener{
	
	//Enum to determine the current status of the maze
	// INCOMPLETE = mouse hasn't finished trying to find the cheese
	// FAIL = mouse has finished trying to find the cheese and failed
	// SUCCESS = mouse has finished trying to find the cheese and succeeded
	private enum MazeStatus{INCOMPLETE,FAIL,SUCCESS,BULLSEYE};
	
	//Current status of the mouse in the maze
	private MazeStatus currentStatus;
	
	//The size of the cheese and mouse in pixels
	private static final int ITEM_SIZE=64;
	
	//Button to begin running the mouse through the maze
	private JButton runButton;
	
	//Button to drop the mouse and cheese in a new random location
	private JButton resetButton;
	
	//Our mouse that is running through the maze blindfolded
	private MouseBody mouseBody;
	
	//The AI controlling our mouse
	private MouseBrain mouseBrain;
	
	//The cheese our mouse is desperately seeking
	private Cheese cheese;
	
	/**
	 * Constructor for our MouseMaze. Creates the window holding our
	 * maze, and accepts a mouse brain and body
	 */
	public MouseMaze(MouseBrain brain, MouseBody body){
		
		//Create a cheese object our mouse will search for
		cheese = new Cheese();
		
		//Set our instance variable for the mouse body
		mouseBody = body;
		
		//Set our instance variable for the mouse brain
		mouseBrain = brain;
		
		//Set the maze our mouse will be running in
		mouseBody.setMaze(this);
		
		//Set up the window holding our maze
		createWindow(); 
		
		//Initialize our maze
		resetMaze();
	}
	
	//Resets the maze by dropping the mouse and cheese in random
	// locations, ensures the run button is enabled, and sets
	// the status of the maze to incomplete. Also repaints the maze.
	private void resetMaze(){
		
		//Drop the mouse in a new random spot fully within our maze
		mouseBody.dropInRandomSpot(this.getWidth()-ITEM_SIZE,this.getHeight()-ITEM_SIZE);
		
		//Drop the cheese in a new random spot fully within our maze
		cheese.dropInRandomSpot(this.getWidth()-ITEM_SIZE,this.getHeight()-ITEM_SIZE-28);
		
		//Make sure the run button is enabled
		runButton.setEnabled(true);
		
		//Set the current status of the maze to incomplete
		currentStatus=MazeStatus.INCOMPLETE;
		
		//Repaint our maze
		repaint();
	}
	
	/**
	 * Gets the mouseBrain object contained in the maze
	 * 
	 * @return mouseBrain The cheese contained in the maze
	 */
	public MouseBrain getMouseBrain() {
		return mouseBrain;
	}
	
	/**
	 * Gets the cheese object contained in the maze
	 * 
	 * @return cheese The cheese contained in the maze
	 */
	public Cheese getCheese() {
		return cheese;
	}
	
	/**
	 * Gets the right edge of the maze
	 * 
	 * @return int containing right edge of the maze
	 */
	public int getRightEdge() {
		return this.getWidth()-ITEM_SIZE;
	}
	
	/**
	 * Gets the bottom edge of the maze
	 * 
	 * @return int containing bottom edge of the maze
	 */
	public int getBottomEdge() {
		return this.getHeight()-ITEM_SIZE;
	}
	
	/**
	 * Redraws our canvas after the mouse has changed locations and
	 *  pauses for a bit to allow the mouse to rest between movements
	 */
	public void updateMouseLocation(){
		
		//Repaint the maze
		repaint();
		
		try {
			//Give the mouse a chance to rest between movements
			Thread.sleep(5);
		} catch (InterruptedException e) {}
	}
	

	//Creates the window containing the maze, along with the buttons
	private void createWindow(){
		
		//Create the window object (called a JFrame)
		JFrame window = new JFrame();
		
		//Give the window a title
		window.setTitle(mouseBrain.getName()+" the stupendous finds the cheese!");
		
		//Set the location and size of the window
		window.setLocation(50,50);
		window.setSize(600,600);
		window.setResizable(false);
		
		//Tell the program that when we close the window
		// we want to exit the program (rather than keep
		// running)
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	
		//Create our buttons and add listeners to see when they are pressed
		runButton = new JButton("Get the Cheese!");
		runButton.addActionListener(this);
		resetButton = new JButton("New Maze");
		resetButton.addActionListener(this);
		
		//Add our buttons to a container called bottomPanel 
		// that is set up in a 2x1 grid
		JPanel buttonPanel = new JPanel(new GridLayout(2,1));
		buttonPanel.add(runButton);
		buttonPanel.add(resetButton);
		
		//Add our buttonPanel and our drawing area to our window
		window.setLayout(new BorderLayout());
		window.add(this,BorderLayout.CENTER);
		window.add(buttonPanel,BorderLayout.SOUTH);
		
		//Set our window to be visible (shown on screen)
		window.setVisible(true);
	}
	
	/**
	 * Respond to buttons being pressed by the user
	 * 
	 * @param action The event generated by a button press
	 */
	public void actionPerformed(ActionEvent action) {
		
		//If the run button was pressed, we want to tell
		// the mouse to begin his hunt for the cheese
		if (action.getSource()==runButton){
			new Thread(){
				public void run(){
					//Disable buttons until the mouse completes his
					// attempt at finding the cheese
					runButton.setEnabled(false);
					resetButton.setEnabled(false);
					
					//Tell the mouse to search for the cheese
					mouseBrain.findCheese();
					
					//Check to see if the mouse hit the bullseye
					if (mouseBody.sniffForCheese()==1)
						currentStatus=MazeStatus.BULLSEYE;
					else{
						int xDiff=mouseBody.getXLocation()-cheese.getXLocation();
						int yDiff=mouseBody.getYLocation()-cheese.getYLocation();
						if(Math.abs(xDiff)<=1&&Math.abs(yDiff)<=1)
							currentStatus=MazeStatus.SUCCESS;
						else
							currentStatus=MazeStatus.FAIL;
					}

					//Re-enable the reset button
					resetButton.setEnabled(true);
					
					//Repaint the canvas
					repaint();
				}
			}.start();
		
		//If the reset button was pressed, we want to place
		// the mouse and cheese in a new random location
		}else if (action.getSource()==resetButton){
			//reset our maze
			resetMaze();
		}
	}
	
	
	/**
	 * Paints our maze, complete with cheese and mouse
	 * 
	 * @param painter the graphics object painting on our canvas
	 */
	public void paint(Graphics painter){
		
		//Get the width and height of our drawing area
		int width=this.getWidth();
		int height=this.getHeight();
		
		//Paint the maze area white
		painter.setColor(Color.WHITE);
		painter.fillRect(0,0,width,height);
		
		//Draw the cheese
		drawCheese(painter);
		
		//Draw the mouse
		drawMouse(painter);
		
		//Draw a string containing the strength of the odor
		painter.setColor(Color.BLACK);
		painter.drawString("Odor Strength="+(int)(100*mouseBody.sniffForCheese())+"%",0,12);
		
		if (currentStatus==MazeStatus.BULLSEYE){
			painter.setColor(Color.RED);
			painter.drawString("Bullseye!",mouseBody.getXLocation(),mouseBody.getYLocation()-16);
			painter.setColor(Color.BLUE);
			painter.drawString("NOM NOM NOM",mouseBody.getXLocation(),mouseBody.getYLocation()-2); 
		}
		
		//If the mouse succeeds, draw the mouse eating the cheese
		if (currentStatus==MazeStatus.SUCCESS){
			painter.setColor(Color.GREEN);
			painter.drawString("Close Enough!",mouseBody.getXLocation(),mouseBody.getYLocation()-16);
			painter.setColor(Color.BLUE);
			painter.drawString("NOM NOM NOM",mouseBody.getXLocation(),mouseBody.getYLocation()-2); 
		}
		
		//If the mouse fails, indicate failure
		if (currentStatus==MazeStatus.FAIL){
			painter.setColor(Color.RED);
			painter.drawString("FAIL",mouseBody.getXLocation(),mouseBody.getYLocation()-2);
		}
		
		// show the location of the mouse and the cheese when finished
		if (currentStatus!=MazeStatus.INCOMPLETE){
			painter.setColor(Color.BLACK);
			painter.drawString("Cheese ("+cheese.getXLocation()+", "+cheese.getYLocation()+")",0,26);
			painter.drawString("Mouse ("+mouseBody.getXLocation()+", "+mouseBody.getYLocation()+")",0,40);	
		}
		
		
	}
	
	//Draw the blindfolded mouse searching for a piece of cheese
	private void drawMouse(Graphics painter){
		
		//Get the location of the mouse
		int xLocation=mouseBody.getXLocation();
		int yLocation=mouseBody.getYLocation();
		
		//Draw the mouse's ears
		painter.setColor(Color.GRAY);
		painter.fillOval(xLocation+ITEM_SIZE/8-1,yLocation-1,ITEM_SIZE/4+2,ITEM_SIZE/4+2);
		painter.fillOval(xLocation+ITEM_SIZE*5/8-1,yLocation-1,ITEM_SIZE/4+2,ITEM_SIZE/4+2);
		painter.setColor(Color.PINK);
		painter.fillOval(xLocation+ITEM_SIZE/8,yLocation,ITEM_SIZE/4,ITEM_SIZE/4);
		painter.fillOval(xLocation+ITEM_SIZE*5/8,yLocation,ITEM_SIZE/4,ITEM_SIZE/4);
		
		//Draw the mouse's body
		painter.setColor(Color.LIGHT_GRAY);
		painter.fillOval(xLocation+ITEM_SIZE*3/16,yLocation+ITEM_SIZE/4,ITEM_SIZE*5/8,ITEM_SIZE*5/8);
		painter.setColor(Color.GRAY);
		painter.fillOval(xLocation+ITEM_SIZE/4,yLocation,ITEM_SIZE/2,ITEM_SIZE/2);
		
		//Draw the mouse's legs
		painter.setColor(Color.DARK_GRAY);
		painter.drawLine(xLocation+ITEM_SIZE*3/4, yLocation+ITEM_SIZE*3/5, xLocation+ITEM_SIZE, yLocation+ITEM_SIZE/4);
		painter.drawLine(xLocation+ITEM_SIZE/4, yLocation+ITEM_SIZE*3/5, xLocation, yLocation+ITEM_SIZE/4);
		painter.drawLine(xLocation+ITEM_SIZE*5/8, yLocation+ITEM_SIZE*4/5, xLocation+ITEM_SIZE*3/4, yLocation+ITEM_SIZE);
		painter.drawLine(xLocation+ITEM_SIZE*3/8, yLocation+ITEM_SIZE*4/5, xLocation+ITEM_SIZE/4, yLocation+ITEM_SIZE);
		
		//Draw the mouse's blindfold
		painter.setColor(Color.MAGENTA);
		painter.fillRect(xLocation+ITEM_SIZE/4,yLocation+ITEM_SIZE/8,ITEM_SIZE/2,ITEM_SIZE/8);
		
		//Draw the mouse's whiskers
		painter.setColor(Color.BLACK);
		painter.drawLine(xLocation+ITEM_SIZE*7/16, yLocation+ITEM_SIZE*5/16, xLocation+ITEM_SIZE/2, yLocation+ITEM_SIZE*3/8);
		painter.drawLine(xLocation+ITEM_SIZE*9/16, yLocation+ITEM_SIZE*5/16, xLocation+ITEM_SIZE/2, yLocation+ITEM_SIZE*3/8);
		painter.drawLine(xLocation+ITEM_SIZE*6/16, yLocation+ITEM_SIZE*3/8, xLocation+ITEM_SIZE/2, yLocation+ITEM_SIZE*3/8);
		painter.drawLine(xLocation+ITEM_SIZE*10/16, yLocation+ITEM_SIZE*3/8, xLocation+ITEM_SIZE/2, yLocation+ITEM_SIZE*3/8);
		painter.drawLine(xLocation+ITEM_SIZE*7/16, yLocation+ITEM_SIZE*7/16, xLocation+ITEM_SIZE/2, yLocation+ITEM_SIZE*3/8);
		painter.drawLine(xLocation+ITEM_SIZE*9/16, yLocation+ITEM_SIZE*7/16, xLocation+ITEM_SIZE/2, yLocation+ITEM_SIZE*3/8);
	
		//Draw the mouse's nose
		painter.setColor(Color.RED);
		painter.fillOval(xLocation+ITEM_SIZE/2-ITEM_SIZE/32, yLocation+ITEM_SIZE*3/8-ITEM_SIZE/32, ITEM_SIZE/16,ITEM_SIZE/16);
	
	}
	
	//Draw the piece of cheese the mouse will try to find and eat
	private void drawCheese(Graphics painter){
		
		//Get the location of the cheese
		int xLocation=cheese.getXLocation();
		int yLocation=cheese.getYLocation();
		
		//Draw cheese
		painter.setColor(Color.ORANGE);
		painter.fillRect(xLocation,yLocation,ITEM_SIZE,ITEM_SIZE);
		
		//Draw holes in cheese
		painter.setColor(Color.BLACK);
		painter.fillOval(xLocation+ITEM_SIZE*1/16,yLocation+ITEM_SIZE*1/16,ITEM_SIZE*1/2,ITEM_SIZE*1/2);
		painter.fillOval(xLocation+ITEM_SIZE*11/16,yLocation+ITEM_SIZE*6/16,ITEM_SIZE*1/4,ITEM_SIZE*1/5);
		painter.fillOval(xLocation+ITEM_SIZE*7/16,yLocation+ITEM_SIZE*11/16,ITEM_SIZE*1/4,ITEM_SIZE*1/4);
		painter.fillOval(xLocation+ITEM_SIZE*2/16,yLocation+ITEM_SIZE*10/16,ITEM_SIZE*1/8,ITEM_SIZE*1/4);
	}

}
