import java.awt.*;import java.awt.event.*;
import java.lang.reflect.*;
import java.util.*;
import java.io.*;


public class ScriptRunner extends Frame {
	Panel mainPanel, scriptListPanel, scriptInputPanel;
	Label scriptListLabel, scriptInputLabel;
	java.awt.List scriptList;
	TextField scriptInputField;
	Button runListButton, runTextButton;

	Panel processPanel;
	Label runningScriptLabel;
	java.awt.List runningScriptList;
	Button showButton;

	Panel buttonPanel;
	Button quitButton;

	HashMap currentProcessList;

	Panel runningScriptLabelPanel;
	Panel runningScriptListPanel;
	Panel showButtonPanel;

	Panel scriptListLabelPanel;
	Panel runListButtonPanel;
	Panel scriptInputLabelPanel;
	Panel runTextButtonPanel;

	ArrayList tempScriptList;

	static final int FRAME_POSITION_TOP = 0;
	static final int FRAME_POSITION_LEFT = 0;

	ScriptRunner(String args[]) {

		getScriptList(args);

		buildMainDisplay();

		setListeners();

		currentProcessList = new HashMap();

                show();

		fillScriptList();
	}

	void getScriptList(String args[]) {
		BufferedReader in;
		String strLine;

		tempScriptList = new ArrayList();

		if(args.length <= 0) {
			return;
		}

		if(!((new File(args[0])).exists())) {
			return;
		}

		try {
			in = new BufferedReader(new FileReader(args[0]));
			while((strLine = in.readLine()) != null) {
				if(strLine.trim().length() == 0) {
					continue;
				}

				tempScriptList.add(strLine);
			}
		} catch(Exception e) {
			return;
		}
	}

	void buildMainDisplay() {
		Label tempLabel;
		GridBagLayout gridBag;
		GridBagConstraints gridConstraints;

		mainPanel = new Panel();
		gridBag = new GridBagLayout();

		gridConstraints = new GridBagConstraints();

		mainPanel.setLayout(gridBag);
		gridConstraints.fill = GridBagConstraints.BOTH;

		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		//for(int i = 0; i < 5; i++) {
		//	tempLabel = new Label(" ");
		//	if(i == 4) {
		//		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		//	}
		//	gridBag.setConstraints(tempLabel, gridConstraints);
		//	mainPanel.add(tempLabel);
		//}

		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		tempLabel = new Label("A tool to execute shell scripts");
		gridBag.setConstraints(tempLabel, gridConstraints);
		mainPanel.add(tempLabel);

		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		tempLabel = new Label("");
		gridBag.setConstraints(tempLabel, gridConstraints);
		mainPanel.add(tempLabel);

		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		scriptListLabel = new Label("Select a script from the list and press Run");
		gridBag.setConstraints(scriptListLabel, gridConstraints);
		mainPanel.add(scriptListLabel);

		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 0.0;
		gridConstraints.gridheight = 4;
		scriptList = new java.awt.List(4, false);
		gridBag.setConstraints(scriptList, gridConstraints);
		mainPanel.add(scriptList);


		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		tempLabel = new Label("");
		gridBag.setConstraints(tempLabel, gridConstraints);
		mainPanel.add(tempLabel);


		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 0.0;
		gridConstraints.gridheight = 1;
		scriptInputLabel = new Label("Type the script (with full path) and press Run");
		gridBag.setConstraints(scriptInputLabel, gridConstraints);
		mainPanel.add(scriptInputLabel);

		gridConstraints.gridwidth = 4;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		scriptInputField = new TextField(10);
		gridBag.setConstraints(scriptInputField, gridConstraints);
		mainPanel.add(scriptInputField);

		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		runTextButton = new Button("Run");
		gridBag.setConstraints(runTextButton, gridConstraints);
		mainPanel.add(runTextButton);





		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		tempLabel = new Label("");
		gridBag.setConstraints(tempLabel, gridConstraints);
		mainPanel.add(tempLabel);



		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		runningScriptLabel = new Label("Select a script and press Show to see the output");
		gridBag.setConstraints(runningScriptLabel, gridConstraints);
		mainPanel.add(runningScriptLabel);

		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 0.0;
		gridConstraints.gridheight = 4;
		runningScriptList = new java.awt.List(4, false);
		gridBag.setConstraints(runningScriptList, gridConstraints);
		mainPanel.add(runningScriptList);

		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		showButton = new Button("Show");
		gridBag.setConstraints(showButton, gridConstraints);
		mainPanel.add(showButton);

		// create the bottom button panel
		gridConstraints.gridwidth = GridBagConstraints.REMAINDER;
		gridConstraints.weightx = 1.0;
		gridConstraints.gridheight = 1;
		quitButton = new Button("Quit");
		gridBag.setConstraints(quitButton, gridConstraints);
		mainPanel.add(quitButton);
                //mainPanel.setSize(getToolkit().getScreenSize());

		add("Center", mainPanel);
		//pack();
		setSize(getToolkit().getScreenSize());
		//setSize(getPreferredSize());
                setTitle("UoB Script Runner");
                setLocation(FRAME_POSITION_TOP, FRAME_POSITION_LEFT);
	}

	void fillScriptList() {

		for(int i = 0; i < tempScriptList.size(); i++) {
			scriptList.add((String) tempScriptList.get(i));
		}
	}

	void setListeners() {

		//runListButton.addActionListener(new ActionListener() {
		//	public void actionPerformed(ActionEvent e) {
		//		String scr;

		//		scr = scriptList.getSelectedItem();
		//		runScript(scr);
		//	}
		//});

		runTextButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String scr;

				scr = scriptInputField.getText();
				if(scr == null || scr.trim().length() == 0) {
					return;
				}
				runScript(scr);
			}
		});

		showButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String scr;

				scr = runningScriptList.getSelectedItem();
				showOutput(scr);
			}
		});

		quitButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				exitAppGracefully();
			}
		});

		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				exitAppGracefully();
			}
		});

		scriptList.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent e) {
				String scr;

				scr = scriptList.getSelectedItem();
				if(scr == null || scr.substring(0, 1).equals("-")) {
					scriptInputField.setText("");
				} else {
					scriptInputField.setText(scr);
				}
			}
		});
	}

	void showOutput(String scr) {
		RunningScript rs;

		rs = (RunningScript) currentProcessList.get(scr);
		if(rs == null) {
			return;
		}

		rs.showDialog();
	}

	void runScript(String scr) {
		RunningScript rs;

		if(scr.trim().length() == 0) {
			return;
		}

		//if(!((new File(scr)).exists())) {
		//	return;
		//}

		rs = (RunningScript) currentProcessList.get(scr);
		if(rs != null) {
			return;
		}

		try {
			rs = new RunningScript(scr, this);

			currentProcessList.put(scr, rs);
			runningScriptList.add(scr);
			rs.startScript();

		} catch(Exception e) {
			return;
		}
	}

	void exitAppGracefully() {
		System.exit(0);
	}

	class RunningScript {
		String scriptName;
		Frame mainFrame;

		Dialog runningProcessDialog;

		TextArea stdoutTextArea;
		TextArea erroutTextArea;
		Panel stdoutTextPanel, erroutTextPanel, dialogButtonPanel;
		Button stopButton, returnButton;

		Label stdoutTextLabel, erroutTextLabel;

		StdoutMonitorThread stdoutMonitorThread;
		ErroutMonitorThread erroutMonitorThread;

		Process scriptProcess;
		BufferedReader stdOutput, stdError;

		Panel stdoutTextLabelPanel;
		Panel erroutTextLabelPanel;


		RunningScript(String scr, Frame main) throws Exception {
			scriptName = scr;
			mainFrame = main;

			buildDialog();

			setDialogListeners();
		}

		void buildDialog() {

			stdoutTextPanel = new Panel(new BorderLayout());
			stdoutTextLabelPanel = new Panel(new FlowLayout());
			stdoutTextLabel = new Label("Display of the standard out and error");
			stdoutTextLabelPanel.add(stdoutTextLabel);
			stdoutTextArea = new TextArea(2, 10);
			stdoutTextPanel.add(stdoutTextLabelPanel, BorderLayout.NORTH);
			stdoutTextPanel.add(stdoutTextArea, BorderLayout.CENTER);

			//erroutTextPanel = new Panel(new BorderLayout());
			//erroutTextLabelPanel = new Panel(new FlowLayout());
			//erroutTextLabel = new Label("Display of the standrad error out");
			//erroutTextLabelPanel.add(erroutTextLabel);
			//erroutTextArea = new TextArea(2, 10);
			//erroutTextPanel.add(erroutTextLabelPanel, BorderLayout.NORTH);
			//erroutTextPanel.add(erroutTextArea, BorderLayout.CENTER);

			stopButton = new Button("Terminate");
			returnButton = new Button("Return");
			dialogButtonPanel = new Panel();
			dialogButtonPanel.setLayout(new FlowLayout());
			dialogButtonPanel.add(stopButton);
			dialogButtonPanel.add(returnButton);

			runningProcessDialog = new Dialog(mainFrame, "Running " + scriptName, true);
			runningProcessDialog.setLayout(new BorderLayout());
			//runningProcessDialog.add(erroutTextPanel, BorderLayout.NORTH);
			runningProcessDialog.add(stdoutTextPanel, BorderLayout.CENTER);
			runningProcessDialog.add(dialogButtonPanel, BorderLayout.SOUTH);

			runningProcessDialog.setBounds(mainFrame.getBounds().x + 1,
							mainFrame.getBounds().y + 10,
							mainFrame.getBounds().width - 2,
							mainFrame.getBounds().height - 20);
		}

		public void setDialogListeners() {

			stopButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					scriptProcess.destroy();
					currentProcessList.remove(scriptName);
					runningScriptList.remove(scriptName);
					runningProcessDialog.hide();
				}
			});

			returnButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					runningProcessDialog.hide();
				}
			});

			runningProcessDialog.addWindowListener(new WindowAdapter() {
				public void windowClosing(WindowEvent e) {
					runningProcessDialog.hide();
				}
			});
		}

		void startScript() throws Exception {
                	scriptProcess = Runtime.getRuntime().exec(scriptName);

			stdError = new BufferedReader(new InputStreamReader(scriptProcess.getErrorStream()));
			stdOutput = new BufferedReader(new InputStreamReader(scriptProcess.getInputStream()));

			stdoutMonitorThread = new StdoutMonitorThread(this);
			stdoutMonitorThread.start();

			erroutMonitorThread = new ErroutMonitorThread(this);
			erroutMonitorThread.start();
			showDialog();
		}

		void showDialog() {
			runningProcessDialog.show();
		}

		synchronized void setTextArea(String str) {
			stdoutTextArea.append(str);
			if(runningProcessDialog.isShowing()) {
				stdoutTextArea.setCaretPosition(10000);
			}
		}
	}

	class StdoutMonitorThread extends Thread {
		RunningScript runningScript;

		StdoutMonitorThread(RunningScript rs) {
			runningScript = rs;
		}

		public void run() {
			String str;

			try {
				runningScript.setTextArea("Started...");
				runningScript.setTextArea("\n\n");

				while((str = runningScript.stdOutput.readLine()) != null) {
					runningScript.setTextArea(str);
					runningScript.setTextArea("\n");
				}
				runningScript.setTextArea("\n");
				runningScript.setTextArea("Completed.");
				runningScript.setTextArea("\n");
			} catch(Exception e) {
				runningScript.setTextArea("Exception triggered (std) : " + e);
				runningScript.setTextArea("\n");
			}
		}
	}

	class ErroutMonitorThread extends Thread {
		RunningScript runningScript;

		ErroutMonitorThread(RunningScript rs) {
			runningScript = rs;
		}

		public void run() {
			String str;

			try {
				while((str = runningScript.stdError.readLine()) != null) {
					runningScript.setTextArea(str);
					runningScript.setTextArea("\n");
				}
			} catch(Exception e) {
				runningScript.setTextArea("Exception triggerred (err) : " + e);
				runningScript.setTextArea("\n");
			}
		}
	}

	public static void main(String args[]) {

		new ScriptRunner(args);
	}

}
