package knightstour;

import java.applet.Applet;
import java.applet.AppletContext;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
 * This class provides a basic graphical user interface
 * that shows a 5 x 5 array of integer numbers to visualize
 * a chess board for a knight's tour.
 * The UI provides a button entitled <em>Find Tour</em>
 * that sets the initial position of the knight on the board.
 * The UI also provides a button entitled <em>Find Tour</em>
 * that starts the Knight's tour solver
 * and displays the calculated tour.
 * For Homework one, it also supports the mysterious red button.
 * <p>
 * Note that the GUI layout is far from being nice. It is basically a proof-of-concept.
 * @author Han Li, Peter Kemper
 *
 */
public class GUI extends Applet implements ActionListener {
	private static final long serialVersionUID = 1L;

	private final int dimension = 5; // fixed dimension of chess board, currently set to 5 x 5
	
	/** the knight's tour solver  */
	Tour solver;
	
	/** initial position */
	int initX = 0; // range: [0,dimension-1] 
	int initY = 0; // range: [0,dimension-1] 
	Random random = new Random(4711); // random number stream to select the initial position
	/** the graphics side, 
	 * each chess board entry is visualized as a button, 
	 * the board is a 2-dimensional array of buttons
	 */
	protected Button[][] view;	
	JPanel buttonPanel = new JPanel();
	Button solveButton = new Button(BUTTON_LABEL1);
	Button initButton = new Button(BUTTON_LABEL2);
	
	JButton redButton = new JButton(BUTTON_LABEL3);
	Random r = new Random(12345);
	int count = 0;
	
	/** String constants */
	final static String BUTTON_LABEL1 = "Find Tour";
	final static String BUTTON_LABEL2 = "Position Knight";
	final static String BUTTON_LABEL3 = "RED BUTTON";
	final static String BOOK = "http://books.google.com/books?id=ppLI3zTIhQ4C&pg=PA84&lpg=PA84&dq=hitchhiker+red+button&source=bl&ots=PBPmarkPR7&sig=myS2Na5mWNl-DQ1sbRErxfTKyIM&hl=en&sa=X&ei=lj6xUavDDIn64APxpYH4Bg&ved=0CFQQ6AEwBw#v=onepage&q=hitchhiker%20red%20button&f=false";

	/** 
	 * Creates the view that contains the knight's tour problem, a button to select an initial position and a solve button to compute a tour.
	 */
	protected void createView() {
		setLayout(new BorderLayout());

		// instantiate the chess board and add buttons to it
		JPanel p = new JPanel();
		p.setLayout( new GridLayout(dimension, dimension) ); // we choose a grid layout of 5 rows, 5 columns
		p.setPreferredSize(new Dimension(500, 500));
		view = new Button[dimension][dimension];
		for( int row = 0; row < dimension; row++ )
			for( int col = 0; col < dimension; col++ ) {
				view[row][col]  = new Button();
				p.add( view[row][col] );
			}
		add(p, BorderLayout.CENTER);


		// add the button panel and corresponding buttons
		add( buttonPanel, BorderLayout.SOUTH);
		// add the button to set the knight at an initial position
		buttonPanel.add(initButton);
		initButton.addActionListener(this);
		// add the button to compute a knight's tour and update the visual display with the tour
		buttonPanel.add(solveButton);
		solveButton.addActionListener(this);
		// add the red button
		buttonPanel.add(redButton);
		redButton.addActionListener(this);
		redButton.setBackground(Color.RED);
		redButton.setForeground(Color.RED);
		redButton.setOpaque(true);
		
		resize(450,450);
	}
	/**
	 * Assigns values 1,2,3, ... to the view following a series of coordinates as given by the tour parameter.
	 * Tour.length == 2 * dimension * dimension is expected for a full knight's tour but method tolerates shorter tours, will truncate longer tours.
	 * @param tour holds a series of coordinates (x,y), such that (tour[0],tour[1]) obtains value 1, and so forth
	 * @precondition tour != null
	 * @precondition view != null, view initialized as array to hold dimension x dimension buttons
	 */
	private void loadValuesForView(int[] tour) {
		int val = 1;
		int x;
		int y;
		int stop = 2 * dimension * dimension; // should be 2 * dimension * dimension for a full tour 
		if (tour.length < stop)
			stop = tour.length; // avoids out of bounds access to tour array
		for( int i = 0; i < stop; i+=2 ) {
			x = tour[i];
			y = tour[i+1];
			view[x][y].setLabel(String.valueOf(val));
			val++;
		}
	}
	/**
	 * Resets the buttons to empty labels
	 * @precondition view != null, view initialized as array to hold dimension x dimension buttons
	 */
	private void resetView() {
		for (int i = 0; i < dimension; i++)
			for (int j =0; j < dimension; j++)
				view[i][j].setLabel("");
	}

	/** 
	 * This method is called by the browser when the applet is loaded.
	 */
	public void init() {
		solver = new KnightsTourP1();
		solver.setDimension(dimension);
		createView();
	}

	/** 
	 * This method is notified whenever a button is clicked
	 * that has this class as a registered listener.
	 */
	public void actionPerformed(ActionEvent e) {
		if( e.getSource() == solveButton ) {
			int[] tour = solver.getTour(initX, initY);
			if ((null != tour) && (0 < tour.length))  {
				resetView();
				loadValuesForView(tour);
			}
			else {
				System.out.println("Trace: no solution found!");
				JOptionPane.showMessageDialog(this, "No solution found, please choose a different problem!");
			}
		}
		if( e.getSource() == initButton ) {
			resetView();
			initX = random.nextInt(dimension);
			initY = random.nextInt(dimension);
			view[initX][initY].setLabel("1");
			System.out.println("Trace: Initial position: "
					+ (initX + 1) + ", " + (initY + 1));
			// output adjusted for common 1,2,3 .. indexing
		}

		if (e.getSource() == redButton) {
			switch(count) {
			case 0 :
				System.out.println("Please do not press this button again!");
				System.out.println("The secret number to answer Q1 for HW1 is: "
				+ r.nextInt());
				count++;
				break;
			case 1:
				System.out.println("Sure, you are one of those guys who couldn't resist!");
				System.out.println("Thank you for making a simple program really happy, good bye!");
				count++;
				break;
			case 2:
				System.out.println("Still pressing the red button?");
				System.out.println("One more time and you will execute a call for /bin/rm -rf ~ in the background!");
				count++;
				break;
			default:
				System.out.println("You are really not easy to scare .. ");
				System.out.println("If this runs in a browser (you exported a jar file, signed and deployed it), I'll give you another hint for your homework.");
				try {
					URL url = new URL(BOOK);
					AppletContext ac = getAppletContext();
					ac.showDocument(url);
				}
				catch (Exception ex) {
					System.out.println("Sorry could not load requested page");
				}
				break;
			}
		}
		this.repaint();
	}
}
