/* ---------------------------------------------------------------
 File:               ContMaskTableWindow.java
 Initial Developer:  Yana Ong
 Description	 :  This class contains the window used to enter
 the controllability/masking information.
 User always has to at least specify controll-
 ability info. If masking is to be entered, 
 it will ask for #of supervisors. The events 
 label is provided automatically from reading
 the FSM data file, or from the graph machine.
 ---------------------------------------------------------------*/

package flap; 


import java.awt.*; 
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import java.io.*;


public class ContMaskTableWindow extends JFrame {

	static final long serialVersionUID = 1L;
    Frame parentFrame = null;
    StringBuffer filename = new StringBuffer();
    LinkedList Supervisorlist = new LinkedList();   
    Vector theEventsVect; // to store the parsed transitions vector.
    int NoOfSupervisor = 1; 
 
    Vector theComponents = new Vector(); // to store the JCheckBox(es) and JTextFields that contain the controllability and masking information.

    Panel upanel, bpanel, cpanel;

    /* this constructor is called if cont/mask table is
     *opened from fsm analyzer frame.
     */
    public ContMaskTableWindow(Frame pFrame, String fName, int noOfSupervisor, Machine mach) {
        super(fName + "_events");
        parentFrame = pFrame;
        filename.append(fName + "_events");
        NoOfSupervisor = noOfSupervisor;
  
        if (mach == null) {
            try {
                MyFileReader fileReader = new MyFileReader();

                fileReader.read(fName);
                if (fileReader.a != null) { // just in case...
                    parseEventVector(fileReader.a.d.theTransitions);
                }
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
                System.exit(0);
            }
        } else {
            parseEventVector(mach.d.theTransitions);
        }

        initializeFrame(false);
    
    }
    //added for reading table
    public ContMaskTableWindow(Frame pFrame, String fName)
    {

    	super(fName + "_events");
        parentFrame = pFrame;
        filename.append(fName + "_events");
  
            try {
                MyFileReader fileReader = new MyFileReader();

                fileReader.read(fName);
                if (fileReader.a != null) { // just in case...
                    parseEventVector(fileReader.a.d.theTransitions);
                }
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
                System.exit(0);
            }

        File file = new File(fName+ "_events"); 
        BufferedReader inFile = null;
        String line = null;
        StringTokenizer st = null;
        int noofevents = 0;
    	//moved to larger scope LinkedList Supervisorlist = new LinkedList();        
        String event_name = null;
        int contvalue = 2;
        String maskvalue = null;
        
        if (file.exists()) { 
            try {
                inFile = new BufferedReader(new java.io.FileReader(file));
            } catch (java.io.FileNotFoundException exp) {
                exp.printStackTrace();
            }

            try { //not the most efficient way to read file
                line = inFile.readLine();
                st = new StringTokenizer(line);
                NoOfSupervisor = Integer.valueOf(st.nextToken()).intValue();
                noofevents = Integer.valueOf(st.nextToken()).intValue();
                inFile.mark(1000000); //readAheadLimit needs adjustment..limits filesize
                
                for(int s = 0; s < NoOfSupervisor; s++){    
                	inFile.reset();
                	LinkedList link = new LinkedList();
  
                	for(int e = 0; e < noofevents; e++){
                        
                        do{
                            do{               
                                line = inFile.readLine();
                            }while((line != null) &&(line.equals(""))); //ignore blank lines
                        
                		    st = new StringTokenizer(line, ": \t\n\r\f");
                    	
                        }while(!st.hasMoreTokens()); //ignore lines that have just blanks, tabs, etc.
                        
                        event_name = st.nextToken(); //extract event name
                    	
                    	for(int adv = 0; adv < s*2; adv++)
                    	{st.nextToken();}  //skip past other supervisor info
                    	
                		contvalue = Integer.valueOf(st.nextToken()).intValue();
                		maskvalue = st.nextToken();
                		EventInfo toadd =new EventInfo(event_name, contvalue, maskvalue); 
                		link.add(toadd);
                	}
                	Supervisorlist.add(link);
                }
               
            } catch (java.io.IOException exp) {
              System.out.println("Error reading controllability/masking information");  
              exp.printStackTrace();
            }

	
            try {
                inFile.close();
            } catch (java.io.IOException exp) {
                exp.printStackTrace();
            }
        }
        initializeFrame(true);
    }
    protected void initializeFrame(boolean fileread) {
        bpanel = new Panel();
        bpanel.setLayout(new GridLayout(1, 3));
        this.getContentPane().add("South", bpanel);
        JButton saveButton = new JButton("Save");
        JButton cancelButton = new JButton("Cancel"); 

        saveButton.addActionListener(new ButtonListener());
        cancelButton.addActionListener(new ButtonListener());
        bpanel.add(saveButton);
        bpanel.add(cancelButton);
  
        setEventTable(fileread);

        setBounds(parentFrame.getX() + 20, parentFrame.getY() + 20,
                parentFrame.getWidth(), parentFrame.getHeight());
  
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
 
        pack();
        setVisible(true);
        parentFrame.setEnabled(false);
    }

    /* this helper method is used to set the event input table according to the user specification.
     * according to no. of events/transitions, whether or not masking info is provided, and no. 
     * of supervisors, the table changes.
     */
    protected void setEventTable(boolean fileread) {
        int noOfColumns = 4;

        theComponents.removeAllElements(); // reset everytime this method is called- to keep the components updated.

        cpanel = new Panel();  
        this.getContentPane().add("Center", cpanel);
 
        cpanel.setLayout(new GridLayout(theEventsVect.size() + 2, 1));
  
        noOfColumns = NoOfSupervisor * 3 + 1;
   
        /* labeling panels */
        Panel ctpanel1 = new Panel();

        ctpanel1.setLayout(new GridLayout(1, NoOfSupervisor));
        JLabel dummylbl = new JLabel("Event Name");

        ctpanel1.add(dummylbl);
        for (int j = 1; j <= NoOfSupervisor; j++) {
            dummylbl = new JLabel("Supervisor" + j);
            ctpanel1.add(dummylbl);
        }
        cpanel.add(ctpanel1);
    
        Panel ctpanel2 = new Panel();

        ctpanel2.setLayout(new GridLayout(1, noOfColumns)); 
        dummylbl = new JLabel("");
        ctpanel2.add(dummylbl);
        for (int j = 0; j < NoOfSupervisor; j++) {
            dummylbl = new JLabel("UnControllable? ");
            ctpanel2.add(dummylbl);
            dummylbl = new JLabel("Mask: Id?");
            ctpanel2.add(dummylbl);
            dummylbl = new JLabel("Value?");
            ctpanel2.add(dummylbl);
        }
        cpanel.add(ctpanel2);  

        /* inputs panel */
        for (int i = 0; i < theEventsVect.size(); i++) {
            Panel cbpanel = new Panel();

            cbpanel.setLayout(new GridLayout(1, noOfColumns));
            JLabel label = new JLabel(theEventsVect.elementAt(i).toString());

            cbpanel.add(label);
            for (int j = 0; j < NoOfSupervisor; j++) {
                JCheckBox jcb = new JCheckBox(); // controllability info
                
                LinkedList elist = null;
            	boolean b = false;
            	String maskval = null;	
                //added
                if(fileread)
                {
                	elist = (LinkedList)Supervisorlist.get(j);
                	for(int z = 0; z < theEventsVect.size(); z++)
                	{
                	EventInfo einfo = (EventInfo)elist.get(z);
                	if(einfo.get_eventname().equals(theEventsVect.elementAt(i).toString()))
                	{
                		b =(einfo.get_cont()!=0); //convert int to bool
                		maskval = einfo.get_maskname();
                		jcb.setSelected(!b); //checked if 0
                		break;
                	}

                }//done with update for cont info from file
                }
                
                theComponents.addElement(jcb);
                cbpanel.add(jcb);
                JCheckBox cb = new JCheckBox(); // masking info
                
                //added
                if(fileread){
                if(maskval.equals(theEventsVect.elementAt(i).toString()))
                	cb.setSelected(true);
                //done update mask from file
                }
                
                cb.addItemListener(new CheckBoxListener());
                theComponents.addElement(cb);
                cbpanel.add(cb);
                JTextField jtf = new JTextField();

                //added
                if(fileread){
                jtf.setText(maskval);
                }
                
                theComponents.addElement(jtf);
                cbpanel.add(jtf);
            }   
            cpanel.add(cbpanel);
        }
    }// end of setEventTable

    /* this helper method is used to parse parameter vector such that theEventsVect vector contains unique
     * event/transition found in parameter vector, origVect.
     */
    protected void parseEventVector(Vector origVect) {
        theEventsVect = new Vector(origVect.size(), 1);

        for (Enumeration et = origVect.elements(); et.hasMoreElements();) {
            Transition t = (Transition) et.nextElement();
	
            if (!theEventsVect.contains(new String(t.label))) {
                theEventsVect.addElement(new String(t.label));
            }
        }
    }

    protected void close() {
        this.dispose();
    }
 
    class CheckBoxListener implements ItemListener {
        public void itemStateChanged(ItemEvent ie) {
            Object source = ie.getItemSelectable();
            int idx = theComponents.indexOf(source);
            int eventIdx = idx / (NoOfSupervisor * 3);
   
            if (ie.getStateChange() == ItemEvent.SELECTED) { // user wants identity mask
                ((JTextField) theComponents.elementAt(idx + 1)).setText(
                        theEventsVect.elementAt(eventIdx).toString()); // sets mask value to be identical of event label
            } else { 
                ((JTextField) theComponents.elementAt(idx + 1)).setText("");
            }// if deselect, mask value should be reset to null	  
        }
    }// end of CheckBoxListener class
      
    
    class ButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent ae) {
            String buttonLabel = ae.getActionCommand();

            if (buttonLabel.equals("Save")) { // saving the cont/mask info in a "FSMfilename.ext_events" file.

                try {
                    FileOutputStream out = new FileOutputStream(
                            filename.toString());
                    PrintStream ps = new PrintStream(out);
		
                    // file should start with "#ofSupervisors #ofEvents" ...
                    ps.println(NoOfSupervisor + " " + theEventsVect.size());
     
                    int theComponentIdx = 0;

                    for (int i = 0; i < theEventsVect.size(); i++) {
                        String event = theEventsVect.elementAt(i).toString();

                        ps.println();
                        ps.print(event);
      
                        for (int j = 0; j < NoOfSupervisor; j++) {
                            // Controllability information is expected...(checked means event is not controllable, and vice versa)
                            Object ob = theComponents.elementAt(
                                    theComponentIdx++);

                            if (ob instanceof JCheckBox) { // control info
                                ps.print(" ");
                                if (((JCheckBox) ob).isSelected()) {
                                    ps.print("0");
                                } else {
                                    ps.print("1");
                                }
                            } else {
                                System.out.println(
                                        "Error1: component received is not the expected JCheckBox");
                                return;
                            }

                            // Masking Id checkbox is expected
                            ob = theComponents.elementAt(theComponentIdx++);
                            if (!(ob instanceof JCheckBox)) {
                                System.out.println(
                                        "Error2: component received is not expected mask id checkbox");
                                return;
                            }

                            // JTextField containing masking value is expected
                            ob = theComponents.elementAt(theComponentIdx++);
                            if (ob instanceof JTextField) { // masking info
                                ps.print("::");
                                String inputStr = ((JTextField) ob).getText();

                                if ((inputStr == null)
                                        || (inputStr.trim().equals(""))) {
                                    JOptionPane.showMessageDialog(null,
                                            "Please make sure the masking value for each event and supervisor"
                                            + " is entered.",
                                            "Incomplete inputs",
                                            JOptionPane.ERROR_MESSAGE);
                                    ps.close();
                                    out.close();
                                    // deleting the incomplete file...
                                    File thisfile = new File(filename.toString());

                                    thisfile.delete();
                                    return;
                                } else {
                                    ps.print(inputStr + "\t");
                                }
                            } else {
                                System.out.println(
                                        "Error3: component received is not the expected JTextField");
                                return;
                            }

                        }// end of NoOfSupervisor loop
                    }// end of theEventsVect.size loop

                    ps.close();
                    out.close();
                    close();
                    parentFrame.setEnabled(true);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
  
            } else if (buttonLabel.equals("Cancel")) {
                close();
                parentFrame.setEnabled(true);
            }
        }
    }// end of ButtonListener class..

}// end of ContMaskTableWindow class.

//added to collect cont/mask info
class EventInfo {
	private String eventname;
	private int cont;
	private String maskname;

public EventInfo(String ein, int contin, String maskin)
{
	this.eventname = ein;
	this.cont = contin;
	this.maskname = maskin;

}
public String get_eventname(){ return eventname; }
public int get_cont() { return cont; }
public String get_maskname() { return maskname; }

public void set_eventname(String ein) {this.eventname = ein; }
public void set_cont(int contin) { this.cont = contin; }
public void set_maskname(String maskin) { this.maskname = maskin; }
}
