/*---------------------------------------------------------------------------
File:         			MultipleInputWindow.java
Package:                        JFLAP Version 3.0
Author:			        Eric Gramond 
                                
Description of Contents:	Contains class MultipleInputWindow.
				
--------------------------------------------------------------------------*/

/* 
 * Susan H. Rodger, Magda Procopiuc, Octavian Procopiuc, Eric Gramond
 * Computer Science Department
 * Duke University
 * June 1998
 * Supported by National Science Foundation DUE-9596002 and DUE-9555084.
 *
 * Copyright (c) 1998
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the author.  The name of the author may not be used to
 * endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
package flap;

import java.awt.*;
import java.util.*;
import java.net.*;
import java.awt.event.*;
import java.io.*;


/**
 * This is a window used for entering multiple inputs to a machine
 * and testig them all at once.
 */

public class  MultipleInputWindow extends Frame implements ActionListener {


    protected Environment myParent;
    protected Vector myInputFields;
    protected Vector myLabels;
    protected int myNumRows;
    protected GridLayout myGrid;

    protected Button myTestButton;
    protected Button myClearButton;
    protected Panel myScrollPanel;

  
    /**
     * constructor 
     */

    public MultipleInputWindow(Environment parent, Color background) {
	
	myParent = parent;
	myNumRows = 10;
	myInputFields = new Vector();
	myLabels = new Vector();
 
	setBackground(background);
	setMenuBar();
	setTitle("Multiple Input Tester");
	setResizable(false);

        buildWindow();

	//separator
	Panel p = new Panel();
	Separator sep = new Separator();	
        p.add(sep, "Center");
	sep.setSize(250,2);
        p.getInsets().top = 20;
	p.getInsets().bottom = 20;
	add(p, "Center");

	//bottom buttons
	Panel buttonPanel = new Panel(new FlowLayout());
	myTestButton = new Button("Test Inputs");
	myTestButton.addActionListener(this);
	buttonPanel.add(myTestButton);
	myClearButton = new Button("Clear");
	myClearButton.addActionListener(this);
	buttonPanel.add(myClearButton);
	add(buttonPanel, "South");	

	addWindowListener(  new WindowAdapter() {
	    public void windowClosing(WindowEvent ev) {
		setVisible(false);
	    }
	} );
	
	pack();
    }

    protected void buildWindow() {

	TextField t;
	Label l;
	ScrollPane topScroll = new ScrollPane();
	topScroll.setSize(250, 450);
	add(topScroll, "North");
       
	myScrollPanel = new Panel();
	myScrollPanel.setLayout(myGrid = new GridLayout(myNumRows+1,1));
	Panel p = new Panel(new FlowLayout());
	int j = 0;
        p.add(new Label("               Input"));
	p.add(new Label("           Result"));
	myScrollPanel.add(p, j++);
	for(int i = 0; i < myNumRows; i++) {
	    t = new TextField(15);
	    l = new Label("            ");
	    myInputFields.addElement(t);
	    myLabels.addElement(l);
	    p = new Panel(new FlowLayout());
	    p.add(t);
	    p.add(l);
	    myScrollPanel.add(p, j++);
	}
	topScroll.add(myScrollPanel);

    }

    /**
     * adds the MenuBar after filling it up
     */
    protected void setMenuBar() {
	MenuBar 	mb = new MenuBar();
	Menu	m;
	MenuItem	item;
	
	mb.setFont(Params._m_font);

	m = new Menu("File");
	m.add(item = new MenuItem("Close", new MenuShortcut('c')));
	item.addActionListener(this);
	mb.add(m);

	m = new Menu("Options");
	m.add(item = new MenuItem("Step Run", new MenuShortcut('s')));
	item.addActionListener(this);
	m.add(item = new MenuItem("Add Inputs", new MenuShortcut('a')));
	item.addActionListener(this);
	mb.add(m);

	m = new Menu("Help");
	m.add(item = new MenuItem("Help HTML", new MenuShortcut('h')));
	item.addActionListener(this);
	m.add(item = new MenuItem("Help Text", new MenuShortcut('t')));
	item.addActionListener(this);
	mb.setHelpMenu(m);

	setMenuBar(mb);
    }


    /**
     * Handle all the events by passing them to the proper function
     */
    public void actionPerformed(ActionEvent e) {

	if(e.getActionCommand().equals("Close")) 
	    close();
	else if(e.getActionCommand().equals("Step Run"))
	    stepRun();
	else if(e.getActionCommand().equals("Add Inputs"))
	    addInputs();
	else if(e.getActionCommand().equals("Help HTML"))
	    helpHTML();
	else if(e.getActionCommand().equals("Help Text"))
	    helpText();
	else if(e.getActionCommand().equals("Clear"))
	    clear();
	else if(e.getActionCommand().equals("Test Inputs")) 
          startThread("testInputs");
	else 
	    System.out.println("Invalid ActionEvent Received in Multiple Input Window");
    }


    /**
     *  clean up, then hide the window for later use
     */
    protected void close() {
	clear();
	this.setVisible(false);
    }

    /**
     * call stepRun on the highLighted textArea's input
     */
    protected void stepRun() {
	
	if(this.getFocusOwner() instanceof TextField) {
	    String aString = myParent.inputField.getText();
	    myParent.inputField.setText( ((TextField) this.getFocusOwner()).getText());
	    myParent.stepRun();
	    myParent.inputField.setText(aString);
	}
    }
    
    /** 
     * add 4 more inputs to the window if 10 wasn't enough...
     */
    protected void addInputs() {
	TextField t;
	Label l;
	myNumRows += 4;
	Panel p;
	myGrid.setRows(myNumRows+1);
	for(int i = 0; i < 4; i++) {
	    t = new TextField(15);
	    l = new Label("            ");
	    p = new Panel(new FlowLayout());
	    myInputFields.addElement(t);
	    myLabels.addElement(l);
	    p.add(t);
	    p.add(l);
	    myScrollPanel.add(p);
	}
	myScrollPanel.validate();
	pack();
    }

    /**
     * Shows the help dialog HTML
     */
    public void helpHTML()
    {
      if(myParent.mainmenu.myHelpWindow == null || !myParent.mainmenu.myHelpWindow.getType().equals("HTML"))
      {
	 try
         {
            myParent.mainmenu.myHelpWindow = new HelpWindowHTML("JFLAP", Params._e_backcolor, myParent.mainmenu.isApplet);
         }
         catch(Exception e)
         {
            OKDialog dg = new OKDialog(e.getMessage(), this, "Error");
            dg.show();
            return;
         }
      }
      myParent.mainmenu.myHelpWindow.setCurrentTopic("Multiple Run");
      myParent.mainmenu.myHelpWindow.setVisible(true);
      myParent.mainmenu.myHelpWindow.toFront();
    }

    /**
     * Shows the help dialog.TEXT
     */
    public void helpText()
    {
      if(myParent.mainmenu.myHelpWindow == null || !myParent.mainmenu.myHelpWindow.getType().equals("Text"))
	 myParent.mainmenu.myHelpWindow = new HelpWindowText("JFLAP", Params._e_backcolor, myParent.mainmenu.isApplet); 
      myParent.mainmenu.myHelpWindow.setCurrentTopic("Multiple Run");
      myParent.mainmenu.myHelpWindow.setVisible(true);
      myParent.mainmenu.myHelpWindow.toFront();
    }

    /**
     * clear all input fields and labels
     */
    protected void clear() {
	for(int i=0; i < myNumRows; i++) {
	    ((Label) myLabels.elementAt(i)).setText("");
	    ((TextField) myInputFields.elementAt(i)).setText("");
	}
    }
    
    /**
     * test all the inputs. The ultimate purpose of the window
     */
    public void testInputs() {	
	String	error = myParent.a.checkMachine();
	String input, pushed;
	Label theLabel;
	TextDialog dg;
	Thread dt;
	String[] str = {"Yes", "No"};

	myParent.setEnabled(false);

	if(error!= null) {
	    OKDialog ok = new OKDialog(error, this, "Error");
	    ok.findResult();
	    myParent.setEnabled(true);
	    return;
	}

	for(int i = 0; i<myNumRows; i++) {
	    theLabel = (Label) myLabels.elementAt(i);    
	    input = ((TextField) myInputFields.elementAt(i)).getText();
	    
	    myParent.a.setInput(input);
	    myParent.a.init();
	    myParent.a.d.initialState.ss = State.NORMAL;
	loop:	while (true) {
	    switch (myParent.a.fastRun()) {
	    case Machine.NO_FINAL_STATE_MSG:
		theLabel.setText("Rejected");
		theLabel.setForeground(Color.red);
		break loop;
	    case Machine.MAXNCONFIGS_MSG:
		if (myParent.a.maxNConfigs < myParent.a.capacity) {
		    dg = new TextDialog("More than "+myParent.a.maxNConfigs
			     +" configurations\n have been generated and the input is\n"
			     +"not accepted yet. Continue?", str,
			     "Input " + i + " warning");  
		    pushed = dg.findResult();
		    if (pushed.equals("Yes")) 
			myParent.a.maxNConfigs *= 2;   
		    if(pushed.equals("No")) {
			theLabel.setText("Overflow");
			theLabel.setForeground(Color.black);
			break loop;	
		    }
		} else {
		    theLabel.setText("Overflow");
		    theLabel.setForeground(Color.black);
		    break loop;
		}
		break; 
	    case Machine.ACCEPTED_MSG:
		theLabel.setText("Accepted");   
		theLabel.setForeground(Color.blue);
		break loop;
	    case Machine.NO_MORE_CONFIGS_MSG:
		theLabel.setText("Rejected");
		theLabel.setForeground(Color.red);
		break loop;
	    }  // end switch
	} // end while
	    myParent.a.d.repaint();	
	}
	myParent.setEnabled(true);
    }



    
    /* 
     * starts a function thread with the given function inside
     */
    public void  startThread(String functionName) {
	FunctionThread ft;
	Class source;
	try {
	    source = this.getClass();
	    ft = new FunctionThread(source.getMethod(functionName, new Class[0]), this, new Object[0]);
	    ft.start();
	}
	catch(NoSuchMethodException h) {
	    System.out.println("no " + functionName + " method found.");
	}
    }

}
