</COMMENT>

/**
 * Maze.java - Cory J. Goldfuss - 12 Feb 2001
 * Program builds a maze made with labels and recursivley finds
 * the solution (exit).
 * User can change layout of maze by altering the 15 element string array; Using
 * capital letters, where W represents a wall and S is the starting location.
 * Note: The maze cannot exceed 15 elments by 15 elements. (0-14 by 0-14)
 */


import java.awt.*;
import javax.swing.*;
import java.awt.event.*;



public class Maze extends JApplet implements ActionListener, ItemListener
{
   
    private ButtonGroup radioGroup;
    private int xStart, yStart; // store start location
    private int xIndex = -1, yIndex = -1, counter = -1; // used for animation (note starting at -1)
    private static int mazeSize = 15;
    private JLabel mazeArray[][] = new JLabel[mazeSize][mazeSize];
    private boolean breadCrumbs = false; // show recursion or not
    private int animateXarray[] = new int[225]; // store values for animation 
    private int animateYarray[] = new int[225];
    private boolean haveWall[][] = new boolean[mazeSize][mazeSize];
    private boolean haveChecked[][] = new boolean[mazeSize][mazeSize];
    private boolean startLocation[][] = new boolean[mazeSize][mazeSize];
    private Timer animate; // Swing timer for "animating" the maze
    private final String[] Map = {"WWWWWWWWWWWWWWW",
                                  "W W       W   W",
                                  "W W WWWWW WWW W",
                                  "W   W   W   W W",
                                  "W W W W WWW W W",
                                  "W W W W W W   W",
                                  "W WWWWW W WWW W",
                                  "W W    SW   W W",
                                  "W W WWW WWW W W",
                                  "W W   W     W W",
                                  "W WWW WWWWW W W",
                                  "W   W     W   W",
                                  "W W WWWWW WWWWW",
                                  "W W     W     W",
                                  "WWWWWWW WWWWWWW"};  
                                  
    // Images for GUI                                                            
   	private ImageIcon wallIcon;
   	private ImageIcon theta;
   	private ImageIcon xImage;
	
	// Neat way to show my authorship - start called upon applet start, Applet does not run until "Ok" is clicked
	public void start(){ JOptionPane.showMessageDialog( null, "Maze 1.0 by Cory J. Goldfuss", "Maze 1.0a", JOptionPane.INFORMATION_MESSAGE, null);}
	public void init()
	{
		
		
		// This line prevents the "Swing: checked access to system event queue" message seen in some browsers.
		getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
		
		// This code is automatically generated by Visual Cafe when you add
		// components to the visual environment. It instantiates and initializes
		// the components. To modify the code, only use code syntax that matches
		// what Visual Cafe can generate, or Visual Cafe may be unable to back
		// parse your Java file into its visual environment.
		//{{INIT_CONTROLS
		getContentPane().setLayout(null);
		setSize(500,512);
		mazePanel.setToolTipText("Maze appears here.");
		mazePanel.setLayout(new GridLayout(15,15,0,0));
		getContentPane().add(mazePanel);
		mazePanel.setBackground(java.awt.Color.black);
		mazePanel.setBounds(12,12,450,450);
		JstartBtn.setText("Go!");
		JstartBtn.setActionCommand("Go!");
		JstartBtn.setNextFocusableComponent(JstopBtn);
		JstartBtn.setSelected(true);
		JstartBtn.setToolTipText("Start Solving");
		JstartBtn.setFocusPainted(false);
		JstartBtn.setMnemonic((int)'G');
		getContentPane().add(JstartBtn);
		JstartBtn.setBounds(36,468,78,32);
		JstopBtn.setRequestFocusEnabled(false);
		JstopBtn.setText("Stop");
		JstopBtn.setActionCommand("Stop");
		JstopBtn.setNextFocusableComponent(JresetBtn);
		JstopBtn.setToolTipText("Stop Solving");
		JstopBtn.setFocusPainted(false);
		JstopBtn.setMnemonic((int)'S');
		getContentPane().add(JstopBtn);
		JstopBtn.setBounds(132,468,78,32);
		JstopBtn.setVisible(false);
		JresetBtn.setRequestFocusEnabled(false);
		JresetBtn.setToolTipText("Start Over");
		JresetBtn.setFocusPainted(false);
		JresetBtn.setText("Reset");
		JresetBtn.setActionCommand("Reset");
		JresetBtn.setNextFocusableComponent(JstartBtn);
		JresetBtn.setMnemonic((int)'R');
		getContentPane().add(JresetBtn);
		JresetBtn.setBounds(228,468,78,32);
		JresetBtn.setVisible(false);
		JsimpleRadio.setText("Simple Solve");
		JsimpleRadio.setSelected(true);
		getContentPane().add(JsimpleRadio);
		JsimpleRadio.setBounds(324,468,108,12);
		JrecursiveRadio.setText("Show Recursive Solve");
		getContentPane().add(JrecursiveRadio);
		JrecursiveRadio.setBounds(324,492,156,12);
		//}}
		
		// Button Group
		radioGroup = new ButtonGroup();
	    radioGroup.add( JrecursiveRadio );
	    radioGroup.add( JsimpleRadio );
	    
	    // create images
		wallIcon = new ImageIcon( getImage( getCodeBase(), "brick.gif" ));
		theta = new ImageIcon( getImage( getCodeBase(), "theta.gif" ));
		xImage = new ImageIcon( getImage( getCodeBase(), "xpic.gif" ));
		animate = new Timer( 250, this );
        
        JstartBtn.grabFocus(); //get focus so mnemonics work when applet starts
		
		// Gather info about layout of maze - from Map[].
		   for (int i = 0; i < mazeSize; i++){
                for ( int j = 0; j < mazeSize; j++){
                    
                    if (Map[i].charAt(j) == 'W'){
                          haveWall[i][j] = true;
                    }
                    else if (Map[i].charAt(j) == 'S'){
                       startLocation[i][j] = true;
                       
                    }
                    else{
                       haveWall[i][j] = false;
                       startLocation[i][j] = false;
                    }
               }
            }
       
        
        // Create maze from boolean arrays used when reading in Map[].
        for (int i = 0; i < mazeSize; i++){
            for (int j = 0; j < mazeSize; j++){
                mazeArray[i][j] = new JLabel();
                mazeArray[i][j].setForeground( Color.green );
                mazeArray[i][j].setOpaque( true );
                mazeArray[i][j].setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
                mazePanel.add( mazeArray[i][j] );
                if ( haveWall[i][j] ){
                    mazeArray[i][j].setIcon( wallIcon );
                }
                else if ( startLocation[i][j] ){
                         mazeArray[i][j].setIcon( theta );
                         xStart = i;
                         yStart = j;
                }
                else{
                    mazeArray[i][j].setBackground( Color.black );
                }
                
            }
        }
        
        JstartBtn.addActionListener( this );
        JstopBtn.addActionListener( this );
        JresetBtn.addActionListener( this );
        JrecursiveRadio.addItemListener( this );
        JsimpleRadio.addItemListener( this );
    
       
	}

    
            
	//{{DECLARE_CONTROLS
	javax.swing.JPanel mazePanel = new javax.swing.JPanel();
	javax.swing.JButton JstartBtn = new javax.swing.JButton();
	javax.swing.JButton JstopBtn = new javax.swing.JButton();
	javax.swing.JButton JresetBtn = new javax.swing.JButton();
	javax.swing.JRadioButton JsimpleRadio = new javax.swing.JRadioButton();
	javax.swing.JRadioButton JrecursiveRadio = new javax.swing.JRadioButton();
	//}}
	
	public void actionPerformed( ActionEvent e ){
	    
	    if ( e.getSource() == JstartBtn ){
	        JstopBtn.setVisible( true );
	        exitTheseus( xStart, yStart );
	        animate.start();
	        JstartBtn.setEnabled( false );
	        JsimpleRadio.setEnabled( false );
	        JrecursiveRadio.setEnabled( false );
	        
	    }
	    
	    if ( e.getSource() == JstopBtn ){
	        JstopBtn.setVisible( false );
	        animate.stop();
	        JresetBtn.setVisible( true );
	        
	    }
	    if ( e.getSource() == JresetBtn ){
	        JstartBtn.setEnabled( true );
	        JresetBtn.setVisible( false );
	        resetMaze(); // calls function that resets all arrays and icons
	        
	    }
	    
	    if ( e.getSource() == animate ){
	        if ( xIndex < counter ){
	        xIndex++;
	        yIndex++;
	        mazeArray[animateXarray[xIndex]][animateYarray[yIndex]].setVisible( true );
	        }
	        else{
	            animate.stop();
	            JstopBtn.setVisible( false );
	            JresetBtn.setVisible( true );
	        }
	        
	    }
    }// end action Performed
    
    public void itemStateChanged( ItemEvent e ) {       
        if ( e.getSource() == JrecursiveRadio )
            breadCrumbs = true;
        if ( e.getSource() == JsimpleRadio )
            breadCrumbs = false;
      
        
    }
    
	
	


	// solves maze - called exitTheseus for historical factors
	public boolean exitTheseus(int x, int y){
	    
	 
	    if ( x <= 0 || y <= 0 || x >= mazeSize - 1 || y >= mazeSize - 1){
	        mazeArray[x][y].setVisible( false );
	        animateLater( x,y );
	        mazeArray[x][y].setText("Exit!!");
	        return true;
	    }
	    if ( haveChecked[x][y] ){
	        return false;
	    }
	    
	    haveChecked[x][y] = true;
	    mazeArray[x][y].setVisible( false );
	    animateLater( x, y );
	    mazeArray[x][y].setIcon( theta );
	    
	    // can we move north?
	    if ( !haveWall[x-1][y] ){
	        if ( exitTheseus( x - 1, y )){
	            
	            return true;
	        }
	    }
	    // south?
	    if ( !haveWall[x+1][y] ){
	        if ( exitTheseus( x + 1, y )){
	            
	            return true;
	        }
	    }
	    // west?
	    if ( !haveWall[x][y-1] ){
	        if ( exitTheseus( x, y - 1 )){
	            
	            return true;
	        }
	    }
	    // east?
	    if ( !haveWall[x][y+1] ){
	        if ( exitTheseus( x, y + 1 )){
	            
	            return true;
	        }
	    }
	    
	    mazeArray[x][y].setVisible( false );
	    if( breadCrumbs ){
	    animateLater( x, y );
	    mazeArray[x][y].setIcon( xImage );
	    }
	    else{
	        mazeArray[x][y].setIcon(null);
	    }
	    
	    return false;
	}// end exitTheseus
	
	
	// method resets maze
	public void resetMaze(){
	  for (int i = 0; i < mazeSize; i++){
            for (int j = 0; j < mazeSize; j++){
                if ( haveWall[i][j] ){
                    mazeArray[i][j].setIcon( wallIcon );
                }
                else if ( startLocation[i][j] ){
                         mazeArray[i][j].setIcon( theta );
                         xStart = i;
                         yStart = j;
                }
                else{
                    mazeArray[i][j].setBackground( Color.black );
                    mazeArray[i][j].setText("");
                    mazeArray[i][j].setIcon( null );
                }
                haveChecked[i][j] = false;
                counter = -1;
                xIndex = -1;
                yIndex = -1;
                JsimpleRadio.setEnabled( true );
	            JrecursiveRadio.setEnabled( true );
                
            }
        }
    }// end resetMaze
    
    
    /* Due to the recursive fuction, we must store values for later reference 
     * Function reads in the current x and y values (from the 2-D mazeArray)
     */
    private void animateLater( int x, int y  ){
        counter++;
        animateXarray[counter] = x;
        animateYarray[counter] = y;
        
    }
        
	
	
}