import java.applet.Applet;
import GoodFrame;
import java.awt.*;
import java.lang.Integer;
import java.io.InputStream;
import java.io.DataInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;

// Control Panel for generating queries.
class CtrlPanel extends GoodFrame {
	/*	The Risq class object reference is passed to provide
		our Applet reference to getAppletContext(), which executes
		the Perl script on the server to process the query.
	*/
	private Risq RisqInstance;

	MenuBar	menubar;					// The menu bar
	Menu	scope, view, help;				// Menu panes
	Button	queryReset;					// Buttons
	List	list;						// A list of choices
	static	TextArea	taxText;		// Taxonomy Query

	TextField		consoleAddr;		// Console address

	static	int queryCount = 0;			// Number of queries in queryLog
	TextField		querySelect;		// User input of query to select
	TextArea		queryLog;			// Retain prior queries
	Button	queryLogButton;				// Save process query in queryLog
	String	queryEntry;					// User specified query log entry

	String	taxString = "";
	int	i;

	// Query panel fields
	static	final String RootKeyword =
							"!![a-z]*[A-M]*[N-Z]*[A-M]*[N-Z]*[A-M]*[N-Z]*!!";

	static	TextField	textQuery;		// User typein query text
	static	int	textQueryLn;			// Length of salutation of text query.
	static	Choice	artifactQuery;		// Artifact query

	Button	renderQuery;

	// Sub-containers for control panel
	Panel	queryLogPanel, taxonomyPanel;
	Panel	imagePanel;

	ImagePanel	risqTaxonomy;			// RISQ Taxonomy image display

	// The layout manager for each of the containers.
	GridBagLayout	gridbag = new GridBagLayout();

	CtrlPanel(String title, Risq thisInstance) {
		super(title);	// Call this class's superclass constructor (Frame)

		RisqInstance = thisInstance;

		int cursorType = Frame.HAND_CURSOR;
		setCursor(cursorType);

		// Create the menu bar.  Tell the frame about it.
		menubar = new MenuBar();
		this.setMenuBar(menubar);

		// Create menu for scope of this project.
		scope = new Menu("Project's Scope");
		scope.add(new MenuItem("HHRF"));
		scope.add(new MenuItem("RISQ"));
		menubar.add(scope);

		// Create menu for view (window configuration support)
		view = new Menu("                    View");
		view.add(new MenuItem("Reduce RISQ window size 10%"));
		view.add(new MenuItem("Increase RISQ window size 10%"));
		menubar.add(view);

		// Create Help menu; add an item; add to menu bar
		help = new Menu("Help");
		help.add(new MenuItem("Taxonomy Query"));
		help.add(new MenuItem("Artifact Query"));
		help.add(new MenuItem("Text Query"));
		menubar.add(help);
		menubar.setHelpMenu(help);	// Display help menu in a reserved place.

		// create a one-line text field, and multiline text area.
		consoleAddr = new TextField(15);
		queryLog = new TextArea(3, 35);
		queryLog.setEditable(false);

		/*
		  class GridBagConstraints
			container, component,
			x - X grid position of component (GridBagConstraints.RELATIVE
				specifies position to the right of previous component)
			y - Y grid position of component (GridBagConstraints.RELATIVE
				specifies position below the previous component)
			gridwidth -  width of component in grid cells
			gridheight - height of component in grid cells
			fill -	Which dimension of a component should grow when the
					space available is larger than its default size.
					(Values: NONE, BOTH, HORIZONTAL, VERTICAL)
					GridBagConstraints.BOTH fills display area entirely.
			anchor -	How component should be displayed within its allotted
						grid cells when it is smaller than those cells.
						(Values: CENTER, compass points)
			weightx -	Distribution of extra X space in container.
						Larger weights specify that a component should
						receive a proportionately larger amount of extra space.
						A zero weight specifies that the component receives
						no extra weight.
			weighty -	...
			insets  -	Object margins to appear on all sides of the component.
						top margin, left margin, bottom margin, right margin
		*/

		// Create a panel for the RISQ Taxonomy image for the center.
		imagePanel = new Panel();
		imagePanel.setLayout(new BorderLayout());
		risqTaxonomy = new ImagePanel(thisInstance);	// RISQ Taxonomy image
		imagePanel.add("Center", risqTaxonomy);
		imagePanel.setForeground(Color.red);
		imagePanel.add("South", new Label("* Taxonomy contributed by SEI"));

		// Create a Panel to contain the Query specification. 
		taxonomyPanel = new Panel();
		taxonomyPanel.setBackground(Color.green);
		taxonomyPanel.setForeground(Color.red);
		taxonomyPanel.setLayout(gridbag);

		Label labelQuery = new Label("Query:");
		Font fontQuery = new Font("TimesRoman", Font.PLAIN, 20);
		labelQuery.setFont(fontQuery);
		labelQuery.setForeground(Color.red);
		constrain(taxonomyPanel, labelQuery, 0,0,1,1);

		constrain(taxonomyPanel, new Label("Console Address:"), 2,0,1,1);
		constrain(taxonomyPanel, consoleAddr, 3,0,1,1);

		// Taxonomy Query
		Label taxLabel = new Label("Taxonomy Query: ");
		constrain(taxonomyPanel, taxLabel, 1,1,3,1);

		taxText = new TextArea(5, 50);
		for (i=0; i<4; i++) {
			//if(risqWindow[i].selections.getText().length() > 0) {
				taxText.appendText(Risq.TAX_TITLES[i] + ": "
							+ Risq.risqWindow[i].selections.getText() + "\n");
			//}
		}
		constrain(taxonomyPanel, taxText, 1,2,4,1);

		// Generate choices for Artifact Query.
		Label artifactLabel = new Label("Artifact Query: ");
		constrain(taxonomyPanel, artifactLabel, 1,3,1,1);
		artifactQuery = new Choice();
		artifactQuery.addItem("");
		artifactQuery.addItem("abstract");
		artifactQuery.addItem("Audio");
		artifactQuery.addItem("code");
		artifactQuery.addItem("data");
		artifactQuery.addItem("Design");
		artifactQuery.addItem("dOcument");
		artifactQuery.addItem("image");
		artifactQuery.addItem("movie");
		artifactQuery.addItem("requirement");
		artifactQuery.addItem("Resource");
		artifactQuery.addItem("taxonomy");
		artifactQuery.addItem("Test");
		artifactQuery.addItem("tooL");
		artifactQuery.addItem("tUtorial");
		//Font fontArt = new Font("TimesRoman", Font.BOLD + Font.ITALIC, 12);
		Font fontArt = new Font("TimesRoman", Font.BOLD + Font.ITALIC, 10);
		artifactQuery.setBackground(Color.pink);
		artifactQuery.setForeground(Color.yellow);
		artifactQuery.setFont(fontQuery);
		constrain(taxonomyPanel, artifactQuery, 2,3,1,1);

		textQuery = new TextField("Text Query: ", 40);
		textQueryLn = textQuery.getText().length();
		textQuery.setEditable(true);
		constrain(taxonomyPanel, textQuery, 1,4,4,1);

		renderQuery = new Button("Process Specified Query");
		Font renderFont = new Font("TimesRoman", Font.BOLD, 20);
		renderQuery.setFont(renderFont);
		renderQuery.setForeground(Color.black);
		constrain(taxonomyPanel, renderQuery, 1,5,2,2);

		queryReset = new Button("Reset Queries");
		//constrain(taxonomyPanel, queryReset, 3,5,1,1);
		constrain(taxonomyPanel, queryReset, 3,5,1,1, GridBagConstraints.NONE,
								GridBagConstraints.EAST, 0, 0, 0, 0, 0, 0);

		// Create a panel for the items along the right size.
		// Use a GridBagLayout and arrange items with constrain(), as above.
		queryLogPanel = new Panel();
		queryLogPanel.setBackground(Color.yellow);
		queryLogPanel.setForeground(Color.black);
		queryLogPanel.setLayout(gridbag);

		//	Establish queryLog panel
		querySelect = new TextField(2);
		constrain(queryLogPanel, new Label("Prior queries:"), 0,0,2,1);
		queryLogButton = new Button("Process Query #");
		//constrain(queryLogPanel, queryLogButton, 3,0,1,1,
		constrain(queryLogPanel, queryLogButton, 3,0,GridBagConstraints.RELATIVE,1,
										GridBagConstraints.NONE,
										GridBagConstraints.EAST, 0.0, 0.0,
																	0,0,0,0);
		//constrain(queryLogPanel, querySelect, 4,0,1,1,
		constrain(queryLogPanel, querySelect, 4,0,GridBagConstraints.REMAINDER,1,
										GridBagConstraints.NONE,
										GridBagConstraints.WEST, 0.0, 0.0,
																	0,0,0,0);
		constrain(queryLogPanel, queryLog, 0,1,5,3,
										GridBagConstraints.HORIZONTAL,
										GridBagConstraints.NORTH, 1.0, 1.0,
																	0,0,0,0);

		// Use a GridBagLayout to arrange the panels themselves.
		this.setLayout(gridbag);
		constrain(this, imagePanel,    0,0,1,1,
										GridBagConstraints.BOTH,
										GridBagConstraints.CENTER, 0, 0,
																	1,1,1,1);
		constrain(this, taxonomyPanel, 0,1,1,1,
										GridBagConstraints.BOTH,
										GridBagConstraints.CENTER, 0, 0,
																	10,1,1,1);
		constrain(this, queryLogPanel,        0,2,1,1,
										GridBagConstraints.BOTH,
										GridBagConstraints.CENTER, 0, 0,
																	10,1,1,1);
	}

	// This is the main constrain() method.
	// Ih has arguments for all constraints.
	public void constrain(
					Container container, Component component,
					int grid_x, int grid_y, int grid_width, int grid_height,
					int fill, int anchor, double weight_x, double weight_y,
					int top, int left, int bottom, int right) {

		GridBagConstraints c = new GridBagConstraints();
		c.gridx = grid_x;
		c.gridy = grid_y;
		c.gridwidth = grid_width;
		c.gridheight = grid_height;
		c.fill = fill;
		c.anchor = anchor;
		c.weightx = weight_x;
		c.weighty = weight_y;
		if((top + bottom + left +right) > 0)
			c.insets = new Insets(top, left, bottom, right);
		
		((GridBagLayout)container.getLayout()).setConstraints(component, c);
		container.add(component);
	}

	// This version of constrain() specifies the position of a component
	// that does not grow and does not have margins.
	public void constrain(
					Container container, Component component,
					int grid_x, int grid_y, int grid_width, int grid_height) {

		constrain(container, component, grid_x, grid_y,
					grid_width, grid_height, GridBagConstraints.NONE,
					GridBagConstraints.NORTHWEST, 0.0, 0.0, 0,0,0,0);
	}

	// This version of constrain() position a component
	// that does not grow, but does have margins.
	public void constrain(
					Container container, Component component,
					int grid_x, int grid_y, int grid_width, int grid_height,
					int top, int left, int bottom, int right) {

		constrain(container, component, grid_x, grid_y,
					grid_width, grid_height, GridBagConstraints.NONE,
					GridBagConstraints.NORTHWEST, 0.0, 0.0,
					top, left, bottom, right);
	}

	public boolean handleEvent(Event event) {
	switch(event.id) {
		// Most components generate ACTION_EVENT
		// We test the target field to find out which component.
System.out.println("Event.target: " + event.target + "\n");
		case Event.ACTION_EVENT:
			if(event.target == queryReset) {
				resetAllQueries();
				return true;
			}
			else if(event.target == renderQuery) {
				procQuery();
				return true;
			}
			else if(event.target == queryLogButton) {
				setToQueryLog();
				return true;
			}
			else if(event.target instanceof MenuItem) {
				// Since we didn't save references to each of the menu objects,
				// we check which one was pressed by comparing labels.
				// Respond to selected menu by popping up dialog boxes.
				if(((String)event.arg).equals("HHRF")) {
					InfoDialog d;
					d = new InfoDialog(this, "HHRF Scope",
						"HHRF (Hypertext Resource Facility) addresses the\n" +
						"problem of enabling industry to become aware of\n" +
						"current technology.  The HHRF is evolving from a\n" +
						"research effort to design and implement a WWW\n" +
						"server to provide industry a guided search of\n" +
						"relevant reference information.\n");
					d.show();
					return true;
				}
				else if(((String)event.arg).equals("RISQ")) {
					InfoDialog d;
					d = new InfoDialog(this, "RISQ Scope",
						"This specific implementation of HHRF is \n" +
						"RISQ (Reference Information for Software Quality)\n" +
						"which produces information about software\n" +
						"techniques and tools.\n");
					d.show();
					return true;
				}
				else if(((String)event.arg).equals("Taxonomy Query")) {
					InfoDialog d;
					d = new InfoDialog(this, "Taxonomy Query Documentation",
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						".... .... .....\n");
					d.show();
					return true;
				}
				else if(((String)event.arg).equals("Artifact Query")) {
					InfoDialog d;
					d = new InfoDialog(this, "Artifact Query Documentation",
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						".... .... .....\n");
					d.show();
					return true;
				}
				else if(((String)event.arg).equals("Text Query")) {
					InfoDialog d;
					d = new InfoDialog(this, "Text Query Documentation",
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						" ....   .....       ......      ..... \n" +
						".... .... .....\n");
					d.show();
					return true;
				}
			}
			break;

		// These are some events pertaining to the window itself.
/*
		case Event.WINDOW_DESTROY:
			//textarea.setText("Window destroy\n");
			RisqInstance.stop();
			RisqInstance.destroy();
			return true;
*/
		case Event.WINDOW_MOVED:
			break;
		
		default:
			break;
		}
		return false;		//	Allow other handlers to handle this event.
	}

	/*	After the Risq query has been obtained, execute the Perl script
		on the server to process the query and render the results.
	*/
	public void procQuery() {
		String	taxQueryKwd = "";
		URL theURL1 = null;
		String	cgi_url = Risq.URL_SERVER_EXEC + "ProcQuery.pl.cgi";
		String	Pick = "High+Integrity";
		String	ArtType = artifactQuery.getSelectedItem();;

		//	Use StringBuffer class to manipulate only the user inputted
		//	text of "textQuery".
		StringBuffer encodedTQ = new StringBuffer();
		encodedTQ.append(textQuery.getText().substring(CtrlPanel.textQueryLn));
		encodeURL(encodedTQ);

		//	Format "Selection" for processing by _____ 
		taxQueryKwd = getSelection();

		// ROOT specified?
		NOT_ROOT: {
			for(int j=0; j<Risq.NumbLocations; j++) {
				if(Risq.risqWindow[j].keywords.compareTo(
										Risq.risqWindow[j].tax_kwd[0]) != 0)
				break NOT_ROOT;
			}
			//taxQueryKwd = "!![a-z]*[A-M]*[N-Z]*[A-M]*[N-Z]*[A-M]*[N-Z]*!!";
			taxQueryKwd = RootKeyword;
		}

		// Generate URL with needed arguments
		try { theURL1 = new URL(cgi_url +
				"?Pick=" + Pick +
				"&ArtType=" + ArtType +
				"&query=" + encodedTQ.toString() +
				"&CONSOLE_ADDR=" + consoleAddr.getText() +
				"&Selection=" + taxQueryKwd);
		}
		catch( MalformedURLException e) {
			System.out.println("Bad URL: " + theURL1);
		}

		// Object instance required for reference to getAppletContext()
		// Have the AppletContext process the Perl routine.
		RisqInstance.getAppletContext().showDocument(theURL1);

		Risq.window.toBack();

		// Add processed query to queryLog
		queryEntry = ((queryCount == 0) ? "" : "\n") +
								++queryCount + ":";
		for(int i=0; i<Risq.NumbLocations; i++) {
			// KKKK needs code to compute proper length
			if(Risq.risqWindow[i].selections.getText().length() > 1)
				queryEntry += " " + Risq.TAX_TITLES[i] + ": " +
								Risq.risqWindow[i].selections.getText() + ";";
		}	

		if(ArtType.length() > 0)
			queryEntry += " Artifact: " + ArtType + ";";
		if(textQuery.getText().substring(CtrlPanel.textQueryLn).length() > 0)
			queryEntry += " Text Query: " +
						textQuery.getText().substring(CtrlPanel.textQueryLn) +
						";";
		queryLog.appendText(queryEntry);
	}

	//	Get current accumulated Taxonomy Query from RisqWindow "keywords".
	public String getSelection() {
		int	numb = 0;
		int	kwdBeg, kwdEnd;
		String	result = new String("");
		String	taxQuery = new String("");

		for(int i=0; i < Risq.NumbLocations; i++) {
			taxQuery += Risq.risqWindow[i].keywords;
		}

		for(	kwdBeg = 0;
				(kwdEnd = taxQuery.indexOf("!!", kwdBeg +2)) >= 0;
				kwdBeg = kwdEnd +1) {
			kwdEnd += 1;
			if(numb > 0)
				//result.concat(" AND ");
				result += "+AND+";			// Encoded for URL parameter passing
			result += taxQuery.substring(kwdBeg, kwdEnd +1);
			numb++;
		}
		return result;
	}

	// Encode data for URL parameter passing.
	public void encodeURL(StringBuffer data) {
		for (int i=0; i<data.length(); i++) {
			switch(data.charAt(i)) {
				case '"':
					data.setCharAt(i, '%');
					data.insert(i +1, "22");
					i +=2;
					break;
		/*	These characters are never present in the parameters
				case '=':
					data.setCharAt(i, '%');
					data.insert(i +1, "3d");
					i +=2;
					break;
				case '&':
					data.setCharAt(i, '%');
					data.insert(i +1, "26");
					i +=2;
					break;
				case '%':
					data.setCharAt(i, '%');
					data.insert(i +1, "25");
					i +=2;
					break;
		*/
				case ' ':
					data.setCharAt(i, '+');
					break;
				default:					// non-special character.
					break;
			}
		}
	}

	// Reset all queries
	static	public void resetAllQueries() {
		// Reset Taxonomy Query text in Control Panel
		CtrlPanel.taxText.setText(Risq.TAX_TITLES[0] + ": " + "\n");
		for(int i=1; i<Risq.NumbLocations; i++) {
			CtrlPanel.taxText.appendText(	Risq.TAX_TITLES[i] + ": " + "\n");
		}

		// Reset taxonomy query text and keywords in each RisqWindow.
		for( int i=0; i<Risq.NumbLocations; i++) {
			Risq.risqWindow[i].selections.setText("");
			Risq.risqWindow[i].keywords = "";
		}

		// Reset Artifact query
		artifactQuery.select("");

		// reset text query
		textQuery.setText("Text Query: ");
	}

	// set ROOT Taxonomy Query
	static	public void setRootTaxQuery() {
		// Set Taxonomy Query text in Control Panel
		CtrlPanel.taxText.setText(Risq.TAX_TITLES[0] + ": " +
											Risq.TAX_TITLES[0] + "\n");
		for(int i=1; i<Risq.NumbLocations; i++) {
			CtrlPanel.taxText.appendText(	Risq.TAX_TITLES[i] + ": " +
											Risq.TAX_TITLES[i] + "\n");
		}

		// Update taxonomy query text and keywords in each RisqWindow.
		for( int i=0; i<Risq.NumbLocations; i++) {
			Risq.risqWindow[i].selections.setText(Risq.TAX_TITLES[i]);
			Risq.risqWindow[i].keywords = Risq.risqWindow[i].tax_kwd[0];
		}
	}

	//	Set query based on selected queryLog.
	public	void setToQueryLog() {
		String	allEntries = queryLog.getText();
		String	procEntry;
		int		indx, indxEnd;
		int		count = 0;

		RisqInstance.showStatus("");		// Clear status

		//	Validate user inputted query value.
		try {
			count = Integer.parseInt(querySelect.getText());
		}
		catch(NumberFormatException e) {
			RisqInstance.showStatus("Value of " + count + " invalid; " +
									"Query log range is 1 thru " + queryCount);
			return;
		}
		if((count < 1) || (count > queryCount)) {
			RisqInstance.showStatus("Value of " + count + " invalid; " +
									"Query log range is 1 thru " + queryCount);
			return;
		}

		// Get user selected query entry from query log.
		for(indx=0; indx < count -1; ) {
			indx = allEntries.indexOf("\n", indx);
		}
		indxEnd = allEntries.indexOf("\n", indx);
		if(indxEnd < 0)
			indxEnd = allEntries.length();
		procEntry = allEntries.substring(indx, indxEnd);

		// Set Artifact query
		if((indx = procEntry.indexOf("Artifact: ")) != -1) {
			indxEnd = procEntry.indexOf(";", indx);
			artifactQuery.select(procEntry.substring(indx, indxEnd));
		}
		else
			artifactQuery.select("");

		// Set text query
		if((indx = procEntry.indexOf("Text Query: ")) != -1) {
			indxEnd = procEntry.indexOf(";", indx);
			textQuery.setText(procEntry.substring(indx, indxEnd));
		}
		else
			textQuery.setText("Text Query: ");

		// Reset Taxonomy query in Control Panel
		CtrlPanel.taxText.setText("");

		for(int i=0; i<Risq.NumbLocations; i++) {
			// Set Taxonomy Query text in Control Panel
			if((indx = procEntry.indexOf(Risq.TAX_TITLES[i] + ": ")) != -1) {
				indxEnd = procEntry.indexOf(";", indx);
				CtrlPanel.taxText.appendText(procEntry.substring(indx,indxEnd));
			}
			else {
				CtrlPanel.taxText.appendText(Risq.TAX_TITLES[i] + ": ");
			}
			CtrlPanel.taxText.appendText("\n");

			// Update taxonomy query text and keywords in each RisqWindow.
			Risq.risqWindow[i].selections.setText(
						procEntry.substring(indx +Risq.TAX_TITLES[i].length()
						+2, indxEnd));
/*
			//	Factor out individual subjects
			String	subject = "";

			subject = procEntry.substring(indx +Risq.TAX_TITLES[i].length()
						+": ".length(), indxEnd);
*/
/*
			for(int indx=0; indx < subject.length(); {
				if(indxEnd = subject.indexOf(",", indx)) == -1) {
					//  KKKK need code here
					;

				}
			}
*/

			//Risq.risqWindow[i].keywords = Risq.risqWindow[i].tax_kwd[0];

		}

		// Reset query log select field.
		querySelect.setText("");

		procQuery();		// Process query.
	}
}

class YesNoDialog extends Dialog{
	public static final int NO = 0;
	public static final int YES = 1;
	public static final int CANCEL = -1;

	protected Button yes = null, no = null, cancel = null;
	protected MultiLineLabel label;

	public	YesNoDialog(Frame parent, String title, String message, 
						String yes_label, String no_label,
						String cancel_label) {
		// Create the window.
		super(parent, title, true);		// Inhibit dialogs to other Frames

		// Specify a Layout Manager for it.
		this.setLayout(new BorderLayout(15, 15));

		// Put the message label in the middle of the window.
		label = new MultiLineLabel(message, 20, 20);
		this.add("Center", label);

		// Create a panel of buttons, center the row of buttons in
		// the panel, and put the pane at the bottom of the window.
		Panel	p = new Panel();
		p.setLayout(new FlowLayout(FlowLayout.CENTER, 15,15));
		if(yes_label != null)
			p.add(yes = new Button(yes_label));
		if(no_label != null)
			p.add(no = new Button(no_label));
		if(cancel_label != null)
			p.add(cancel = new Button(cancel_label));
		this.add("South", p);

		// set the window to its preferred size.
		//this.pack();
	}

	// Handle button events by calling the answer() method.
	// Pass the appropriate constant value, depending on the button.
	public	boolean action(Event e, Object arg) {
		if(e.target instanceof Button) {
			this.hide();
			this.dispose();
			if(e.target == yes) {
				answer(YES);
			}
			else
				if(e.target == no) {
					answer(NO);
				}
				else {
					answer(CANCEL);
				}
			return true;
		}
		else
			return false;
	}

	// Call yes(), no(), and cancel() methods depending on the button the 
	// user clicked.  Subclasses define how the answer is processed by
	// overriding this method or the yes(), no(), and cancel() methods.
	protected void answer(int answer) {
		switch(answer) {
			case YES:
				yes();
				break;
			case NO:
				no();
				break;
			case CANCEL:
				cancel();
				break;
		}
	}

	protected void yes() {};
	protected void no() {};
	protected void cancel() {};
}

class ReallyQuitDialog extends YesNoDialog{
	TextComponent status;

	// Create the kind of YesNoDialog we want
	// and store away a piece of information we need later.
	public ReallyQuitDialog(Frame parent, TextComponent status) {
		super(parent, "Really Quit?", "Really Quit?", "Yes", "No", null);
		this.status = status;
	}

	// Define these methods to handle the user's answer.
	public void yes() {
		System.exit(0);
	}

	public void no() {
		if(status != null) 
			status.setText("Quit cancelled.");
	}
}

class InfoDialog extends Dialog {
	protected	Button button;
	protected	MultiLineLabel label;

	public	InfoDialog(Frame parent, String title, String message) {
		// Create dialog with the specified title
		super(parent, title, false);

		// Create and use a BorderLayout manager with specified margins.
		this.setLayout(new BorderLayout(15, 15));

		// Create the message component and add it to the window.
		label = new MultiLineLabel(message, 20, 20);
		this.add("Center", label);

		// Create an Okay button in a Panel; add the Panel to the window.
		// Use a FlowLayout to center the button and give it margins.
		button = new Button("Okay");
		Panel p = new Panel();
		p.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 15));
		p.add(button);
		this.add("South", p);

		// Resize the window to the preferred size of its components.
		this.pack();
	}

	// Pop down the window whewn the button is clicked.
	public	boolean action(Event e, Object arg) {
		if(e.target == button) {
			this.hide();
			this.dispose();
			return true;
		}
		else
			return false;
	}

	// When the window gets the keyboard focus, give it to the button.
	// This allows keyboard shortcuts to pop down the dialog.
	public	boolean gotFocus(Event e, Object arg) {
		button.requestFocus();
		return true;
	}
}