/**
 *  TEDInterface.java
 *
 *  Copyright Ben Pfistner and Jason Emmons (C) 2005
 *
 *  This program will be the GUI for our program.
 *
 *  **Important Note**
 *    All instnace names of graphical objects end in their respective classes.
 *     - TextFields all end in TF
 *     - Buttons all end in B
 *     - Labels all end in L
 *     - TextFields all end in TA
 *	   - ScrollPanes all end in SP
 *
 */

//import java.lang.*;
//import java.util.*;

import javax.swing.*;

import java.awt.event.*;
import java.awt.*;

public class TEDInterface extends JFrame
{
	JLabel alphabetL;
	JTextField alphabetTF;
	
	JLabel tapeL;
	JTextField tapeTF;
	
	JLabel rulesL;
	JTextArea rulesTA;
	
	JTextArea tupleListTA;
	JTextArea statusBoxTA;
	
	JButton validateB;
	JButton saveB;
	JButton loadB;
	JButton haltB;
	JButton runSpeedB;
	JButton stepSpeedB;
	JButton ludicrousSpeedB;
	JButton reloadB;
	
	TEDController controller;
	
	//These Labels represent the tape
	// X means the current position of the tape head.
	// "tapeXm5L" denotes that this is a label (the L)
	// It shows the location 5 cels to the left of the tapehead.(Tapehead - 5)
	JLabel tapeXm5L;
	JLabel tapeXm4L;
	JLabel tapeXm3L;
	JLabel tapeXm2L;
	JLabel tapeXm1L;
	JLabel tapeXL;
	JLabel tapeXp1L;
	JLabel tapeXp2L;
	JLabel tapeXp3L;
	JLabel tapeXp4L;
	JLabel tapeXp5L;
	
	JLabel tapeIm5L;
	JLabel tapeIm4L;
	JLabel tapeIm3L;
	JLabel tapeIm2L;
	JLabel tapeIm1L;
	JLabel tapeIL;
	JLabel tapeIp1L;
	JLabel tapeIp2L;
	JLabel tapeIp3L;
	JLabel tapeIp4L;
	JLabel tapeIp5L;
	
	JLabel cells[] = new JLabel [4096];
	JLabel numbers[] = new JLabel [4096];
	JScrollPane tapeSP;
	JPanel tapePanel;
	
	JButton serialNumberB;

// 2 lines - added by Brinton on 11/26/2005	
	JLabel stepL;
	JLabel stepV;
	/**
	 *  Constructor
	 *
	 */
	public TEDInterface(TEDController controller)
	{
		this.controller = controller;
		
//		2 lines - added by Brinton on 11/26/2005	
		stepL = new JLabel("Steps: ");
		stepV = new JLabel("");
		
		alphabetL = new JLabel("Enter the Alphabet:");
		alphabetTF = new JTextField(20);
		
		tapeL = new JLabel("Enter the Initial Tape:");
		tapeTF = new JTextField(20);
		
		rulesL = new JLabel("Enter the Rule Set:");
		rulesTA = new JTextArea("", 5, 12);
		rulesTA.setLineWrap(true);
		JScrollPane rulesTASP = new JScrollPane(rulesTA, 
				ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
	
		tupleListTA = new JTextArea(" ", 5, 12);
		tupleListTA.setLineWrap(true);
		JScrollPane tupleListTASP = new JScrollPane(tupleListTA, 
				ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		
		statusBoxTA = new JTextArea("", 5, 15);
		statusBoxTA.setLineWrap(true);
		JScrollPane statusBoxTASP = new JScrollPane(statusBoxTA, 
				ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
				
		validateB = new JButton("Validate");
		saveB = new JButton("Save");
		loadB = new JButton("Load");
		haltB = new JButton("Halt");
		stepSpeedB = new JButton("Step Speed");
		runSpeedB = new JButton("Run Speed");
		ludicrousSpeedB = new JButton("Ludicrous Speed");
		reloadB = new JButton("Reload TM");
		serialNumberB = new JButton("Print Serial Number");
		
		stepSpeedB.setEnabled(false);
		runSpeedB.setEnabled(false);
		ludicrousSpeedB.setEnabled(false);
		haltB.setEnabled(false);
		reloadB.setEnabled(false);
		serialNumberB.setEnabled(false);
		
		tapeXm5L = new JLabel("    ");
		tapeXm4L = new JLabel("    ");
		tapeXm3L = new JLabel("    ");
		tapeXm2L = new JLabel("    ");
		tapeXm1L = new JLabel("    ");
		tapeXL = new JLabel("    ");
		tapeXp1L = new JLabel("    ");
		tapeXp2L = new JLabel("    ");
		tapeXp3L = new JLabel("    ");
		tapeXp4L = new JLabel("    ");
		tapeXp5L = new JLabel("    ");
		
		tapeIm5L = new JLabel("    ");
		tapeIm4L = new JLabel("    ");
		tapeIm3L = new JLabel("    ");
		tapeIm2L = new JLabel("    ");
		tapeIm1L = new JLabel("    ");
		tapeIL = new JLabel("    ");
		tapeIp1L = new JLabel("    ");
		tapeIp2L = new JLabel("    ");
		tapeIp3L = new JLabel("    ");
		tapeIp4L = new JLabel("    ");
		tapeIp5L = new JLabel("    ");
		
		tapePanel = new JPanel();
		tapePanel.setLayout(new GridLayout(2, 0));
		tapePanel.setFont(new Font("Monospaced", 12, Font.PLAIN));
		
		tapeSP = new JScrollPane( 
				ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		for(int i = 0; i < 4096; i++)
		{
			cells[i] = new JLabel("_    ");
			tapePanel.add(cells[i]);
		}
		
		for(int i = 0; i < 4096; i++)
		{
			numbers[i] = new JLabel(padIndex(i));
			tapePanel.add(numbers[i]);
		}
		
		tapeSP.getViewport().add(tapePanel);
		
		//This is where we add all of our components to the gui
		GridBagLayout gbl = new GridBagLayout();
		
		JPanel mainP = new JPanel();
		
		mainP.setLayout(gbl);
		
		GridBagConstraints c = new GridBagConstraints();

		c.fill = GridBagConstraints.HORIZONTAL;	

		c.gridx = 0;
		c.gridy = 2;
		c.gridwidth = 1;
		mainP.add(alphabetL, c);
		
		c.gridy++;
		mainP.add(alphabetTF, c);

		c.gridy++;
		mainP.add(tapeL, c);
		
		c.gridy++;
		mainP.add(tapeTF, c);

//next 3 lines added by Brinton on 11/26/2005
		c.gridx+=2;
		mainP.add(stepL, c);
		c.gridx++;
		mainP.add(stepV, c);
		
		c.gridx=0;
		c.gridy++;
		mainP.add(rulesL, c);
		
		c.gridy++;
		c.gridheight = 5;
		mainP.add(rulesTASP, c);
		
		//c.fill = GridBagConstraints.BOTH;	
				
		c.gridx+=2;
		
		mainP.add(tupleListTASP, c);
		
		c.gridx++;
		
		mainP.add(statusBoxTASP, c);


		//c.fill = GridBagConstraints.HORIZONTAL;	
		
		c.gridx=0;
		c.gridy+=6;
		c.gridwidth = 1;
		c.gridheight = 1;
		mainP.add(validateB, c);
		c.gridx++;
		mainP.add(stepSpeedB, c);
		c.gridx++;
		mainP.add(haltB, c);
		
		c.gridy++;
		c.gridx-=2;
		mainP.add(saveB, c);
		c.gridx++;
		mainP.add(runSpeedB, c);
		c.gridx++;
		mainP.add(reloadB, c);
		c.gridy++;
		c.gridx-=2;
		mainP.add(loadB, c);
		c.gridx++;
		mainP.add(ludicrousSpeedB, c);
			
		c.gridx++;
		mainP.add(serialNumberB, c);
		
		setTitle("T.E.D.: Turing Educational Device");
		setSize(700, 500);
		getContentPane().add(tapeSP, BorderLayout.NORTH);
		getContentPane().add(mainP, BorderLayout.CENTER);
		show();
		
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				dispose();
				System.exit(0);
			}
		});
		
		validateB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				validateBAP(e);
	    	}
		});
		
		serialNumberB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				serialNumberBAP(e);
	    	}
		});
		
		saveB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				saveBAP(e);
	    	}
		});
		
		loadB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				loadBAP(e);
	    	}
		});
		
		haltB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				haltBAP(e);
	    	}
		});
		
		stepSpeedB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				stepSpeedBAP(e);
	    	}
		});
		
		runSpeedB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				runSpeedBAP(e);
	    	}
		});
		
		ludicrousSpeedB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				ludicrousSpeedBAP(e);
	    	}
		});
		
		reloadB.addActionListener(new ActionListener() 
		{
			public void actionPerformed(ActionEvent e)
			{
				reloadBAP(e);
	    	}
		});
	}
	
	/**
	 *  validateBAP
	 *
	 *  This method creates a parser to validate the currentTM
	 *
	 */
	public void validateBAP(ActionEvent e)
	{
		if(controller.validate())
		{
			for(int i = 0; i < 4096; i++)
			{
				cells[i].setText(controller.currentTM.getTapeCel(i));
				numbers[i].setText(padIndex(i));
			}		
			
			int q = controller.currentTM.getTapeHeadPos();		
			
			numbers[q].setText("^    ");
			
			Rectangle rect = cells[q].getBounds();
			tapePanel.scrollRectToVisible(rect);
					
			tupleListTA.setText(" ");
			statusBoxTA.setText(" ");
				
			stepSpeedB.setEnabled(true);
			runSpeedB.setEnabled(true);
			ludicrousSpeedB.setEnabled(true);
			haltB.setEnabled(true);
			reloadB.setEnabled(true);
			serialNumberB.setEnabled(true);
			
			JOptionPane.showMessageDialog(null, "Validation Successful");
		}
	}
	
	/**
	 *  saveBAP
	 *
	 *  This method saves the currentTM
	 *
	 */
	public void saveBAP(ActionEvent e)
	{
		controller.doSave();	
	}
	
	/**
	 *  loadBAP
	 *
	 *  This method loads the currentTM
	 *
	 */
	public void loadBAP(ActionEvent e)
	{
		haltB.setEnabled(false);
		runSpeedB.setEnabled(false);
		stepSpeedB.setEnabled(false);
		ludicrousSpeedB.setEnabled(false);
		reloadB.setEnabled(false);
		serialNumberB.setEnabled(false);
		
		controller.doLoad();	
	}
	
	/**
	 *  haltBAP
	 *
	 *  This method halts the currentTM during execution
	 *
	 */
	public void haltBAP(ActionEvent e)
	{
		haltB.setEnabled(true);
		runSpeedB.setEnabled(true);
		stepSpeedB.setEnabled(true);
		ludicrousSpeedB.setEnabled(true);
		reloadB.setEnabled(true);
		serialNumberB.setEnabled(true);
		
		controller.doHalt();	
	}
	
	/**
	 *  stepSpeedBAP
	 *
	 *  This method runs the currentTM at stepSpeed
	 *
	 */
	public void stepSpeedBAP(ActionEvent e)
	{
		controller.stepSpeed();	
	}
	
	/**
	 *  runSpeedBAP
	 *
	 *  This method runs the currentTM at Run speed
	 *
	 */
	public void runSpeedBAP(ActionEvent e)
	{
		haltB.setEnabled(true);
		runSpeedB.setEnabled(false);
		stepSpeedB.setEnabled(false);
		ludicrousSpeedB.setEnabled(false);
		reloadB.setEnabled(false);
		serialNumberB.setEnabled(false);
		
		controller.runSpeed();	
	}
	
	/**
	 *  ludicrousSpeedBAP
	 *
	 *  This method runs the currentTM at ludicrous speed
	 *
	 */
	public void ludicrousSpeedBAP(ActionEvent e)
	{
		controller.ludicrousSpeed();	
	}
	
	/**
	 *  reloadBAP
	 *
	 *  This method reloads the currentTM
	 *
	 */
	public void reloadBAP(ActionEvent e)
	{
		controller.reload();
		
		haltB.setEnabled(true);
		runSpeedB.setEnabled(true);
		stepSpeedB.setEnabled(true);
		ludicrousSpeedB.setEnabled(true);
		reloadB.setEnabled(true);
		
		tupleListTA.setText(" ");
		statusBoxTA.setText(" ");
	}
	
	/**
	 *  updateTape()
	 *
	 *  This method updates the tape display
	 *
	 *  @param x: the cell of the tape that the tape head is on
	 *
	 */
	public void updateTape(int x)
	{
		cells[x].setText(controller.currentTM.theTape[x]+ "    ");

		Rectangle rect = cells[x].getBounds();
		tapePanel.scrollRectToVisible(rect);
	}
	
	public void uncarat(int x)
	{
		numbers[x].setText(padIndex(x));	
	}
	
	public void carat(int x)
	{
		numbers[x].setText("^    ");	
	}
	
	public void resetTape()
	{
		for(int n = 0; n < 4096; n++)
		{
			cells[n].setText(controller.currentTM.getTapeCel(n));	
		}	
	}
	
	/**
	 *  updateStep
	 *
	 *  This method updates the Step
	 *
	 *  @param currentTuple: the current 5Tuple we are printing out.
	 *
	 */
	public void updateRuleDisplay(String tuple)
	{
		tupleListTA.insert(tuple + "\n", 0);
	}
	
	/**
	 *  updateStepDisplay
	 *
	 *  This method updates the step history
	 *
	 */
	public void updateStepDisplay(int step_value)
	{
		String step_value_str = step_value + "";
		stepV.setText(step_value_str);	
	}

	public String padIndex(int num)
	{
		String padded = num + "";
		
		while(padded.length() < 5)
		{
			padded = padded + " ";	
		}
		
		return padded;
	}
	
	/**
	 *  updateStausBox()
	 *
	 *  This method tells the user just what the TM is doing
	 *
	 *  @param currentTuple: the current 5Tuple we are printing out.
	 *
	 */
	public void updateStatusBox(TED5tuple currentTuple)
	{
		statusBoxTA.setText("");
		statusBoxTA.append("In state: " + currentTuple.getInitialState() + "\n");
		statusBoxTA.append("Character being Read: " + currentTuple.getReadChar() + "\n");
		statusBoxTA.append("Character to Write: " + currentTuple.getWriteChar() + "\n");
		if(Character.toUpperCase(currentTuple.getDirection()) == 'L')
		{
			statusBoxTA.append("Moving LEFT"+ "\n");
		}
		else
		{
			statusBoxTA.append("Moving RIGHT"+ "\n");
		}
				
		statusBoxTA.append("Transitioning to State: " + currentTuple.getFinalState());		
	}
	
	/**
	 *  serialNumberBAP
	 *
	 *  This method prints the serialNumber of the currentTM
	 *
	 */
	public void serialNumberBAP(ActionEvent e)
	{
		JOptionPane.showMessageDialog(null, controller.printSerialNumber());
	}
}	