// bergmark - August 1999 - telephony project

// EditMyEntry is a java program that retrieves and displays the
// directory entry for the authorized user, and then allows the
// user to update the entry on the screen and in the database.

// A login dialog is used to get user credentials

// Requirements: Java 1.2 or later for Iterator
//    on hoho, put /usr/local/jdk1.2.1/src.jar in your CLASSPATH
//             put /usr/local/jdk1.2.1/bin at front of your PATH

// TBD: add ability to change custom location
// TBD: implement allowing adm to change other users
// TBD: get around the requirement to hit ENTER in order to have
//      a textfield change be noticed

import java.awt.*;            // for Frame 
import cnrg.itx.ds.*;         // for ITX Directory Service
import java.awt.event.*;      // for mouse and window listeners
import java.util.*;           // for Vector, Iterator

public class EditMyEntry extends Frame {

   private DirectoryService myDS = null;

   // Data about ourselves
   private String myExtension;
   private Vector myDefaultLocationList = null;
   private boolean haveDefaultLocation = false;
   private int nDFs = 0;      // number of Default Locations
   private Iterator myIter = null;

   // contents of our GUI
   private int PASS;
   private int DF_LIST;
   private int CUSTMSG; private String newCustomMessage;
   private Panel p3 = new Panel ( new FlowLayout() ); 
   private Button b1 = new Button ("Commit");
   private Button b2 = new Button ("Exit");
   private Button b3 = new Button ("Change Password");

   // This keeps track of what changed before Commit is pressed
   private boolean changed[] = new boolean[20]; // initially false
   private TextField[] fields = new TextField[20]; // initially null
   private int nfields = 0;   // index of next entry in textfield list

   // These are our login credentials (can be changed by login dialog)
   private String uidStr="guest";
   private String pwStr = "guest";
   private UserID uid = new UserID(uidStr);
   private Password pw = new Password(pwStr);

   // This is the main entry point - instantiate and go
   public static void main (String[] args) {
      EditMyEntry myself = new EditMyEntry (args);
   }

   // Constructor
   public EditMyEntry ( String[] args ) {
      super("EditMyEntry");
      new Login( this );                  // get uid and pw
      openDirectory();
      init();
   }

   // Authenticate with Directory Service (exit if something goes wrong)
   private void openDirectory() {
      try {
	 myDS = new DirectoryService();
	 myDS.declareIdentity ( uid, pw );
	 System.out.println ("Logged in as user " + uid );
      } catch ( Exception e ) { 
	 System.out.println ("Failed to open directory because " + e);
	 System.exit(0);
      }
      System.out.println ("We have a valid directory.");
      try {
	 myExtension = (myDS.getExtension()).toString();
      } catch (Exception e){
	 System.out.println("Could not get the extension number");
	 myExtension = "No Extension Found";
      }
      try {
	 myDefaultLocationList = 
	    myDS.getDefaultLocationByExtension ( myDS.getExtension());
	 haveDefaultLocation = ! myDefaultLocationList.isEmpty();
	 nDFs = myDefaultLocationList.size();
	 myIter = (Iterator)myDefaultLocationList.iterator();
      } catch (Exception e) {
	 System.out.println ("No Default Locations");
      }
   }

   // Called by GUI to write changed fields back to the database
   private int updateDirectory() {

      int nupdates=0;

      for ( int i = 0; i<nfields; i++ ) {
	 if ( changed[i] ) {
	    if ( i == PASS ) {
		  System.out.println ("Changing the password");
		  /*  Maybe use the dialog in the future
		  PasswordDialog pd = new PasswordDialog(this,pwStr);
		  String p = pd.getNewPassword();
		  */
		  try {
		     Password newPassword = 
			new Password(fields[PASS].getText());
		     myDS.setPIN ( uid, pw, newPassword );
		     pw = newPassword;
		     nupdates++;
		  } catch (Exception e) {System.out.println("failed"); }
	    } else if (i == DF_LIST) { 
		  System.out.println ("Changing the default location list");
		  try { myDS.setDefaultLocation(fields[DF_LIST].getText()); 
			nupdates++; 
		  } catch (Exception e){System.out.println("failed");} 
	    } else if (i == CUSTMSG ) {
		  System.out.println ("Changing the custom message to:" +
		     fields[CUSTMSG].getText() );
		  try { myDS.setCustomMessage(fields[CUSTMSG].getText()); 
			nupdates++; 
		  } catch (Exception e){System.out.println("failed");} 
	    } else // default:
	       System.out.println("unknown field");
	    changed[i] = false;
	 }
      }

      return nupdates;
   }

   // Called by GUI to return the next string in a vector of
   // Default Locations 
   private String getNextDefaultLocation () {
      if (haveDefaultLocation) {
	 Location loc = (Location)myIter.next(); myIter.remove();
	 haveDefaultLocation = myIter.hasNext();
	 return  loc.toString();
      } else return "None";
   }

   // sets up the GUI and makes it visible
   public void init() {

      // Userid and Extension
      Panel p = new Panel( new FlowLayout() );
      p.add ( new Label 
	 ("Logged in as: " + uid + "  (extension "+myExtension+")" ) );
      Panel p1 = new Panel ( new FlowLayout( FlowLayout.CENTER,0,0) );
      p1.add ( new Label
	 ("Note: to change userid or extension, you must ") );
      p1.add ( new Label
	 ("get an ITX administrator to delete-add user" ) );

      // Password change
      PASS = nfields;
      Panel pwPanel = setupTextField("Password:", pwStr);

      // Default Locations
      DF_LIST = nfields;
      Panel[] df = new Panel[nDFs];
      int numberOfLocs = 0;
      df[numberOfLocs++] =
	 setupTextField("Default Location(s):",getNextDefaultLocation());
      // Add the rest, without a label
      while ( haveDefaultLocation ) {
	 df[numberOfLocs++]=setupTextField("", getNextDefaultLocation() );
      }

      // Define Panel for the Custom Message
      CUSTMSG = nfields; String msg;
      try { msg = myDS.getCustomMessage(); }
      catch (Exception e) 
	 { System.out.println("Could not get Custom Message because " + e);
	   msg = ""; }
      Panel cm = setupTextField("Custom Message:", msg );

      // Define a button for committing the changes
      b1.setBackground(Color.blue);
      b1.addActionListener ( new CommitButtonWatcher() );
      p3.add(b1);

      // Define a button for exiting the application
      p3.setForeground(Color.white);
      b2.setBackground(Color.blue);
      p3.add(b2);
      b2.addActionListener ( new ExitButtonWatcher(this) );
      int nrows = nfields+3;

      // Using Grid layout, many rows, 1 column
      setLayout ( new GridLayout(nrows, 1) );
      add (pwPanel); // password
      for (int i = 0; i<nDFs; i++) add(df[i]); // default locations
      add (cm); // Custom Message
      add (p3); // buttons
      add (p);  // userid and extension
      add (p1); // cautionary note
    
      // resize GUI so that it doesn't take up the whole screen
      setSize ( new Dimension (570,400) );
      setVisible ( true );

   } 

   // Set up a TextField with a label and an observer.
   // "l" is the label for the TextField, and "t" is its initial
   // contents.  Use "nrows" as the index into the field.  Return
   // this as a new Panel.

   // Note: the label and text field seem to hang around, having
   // been added to the panel.  They don't get garbage collected
   protected Panel setupTextField (String l, String t ) {
      //fields[nfields] = new TextField ( t, 40 );
      TextField tf = new TextField ( t, 40 );
      Panel p = new Panel( new FlowLayout() );
      p.setForeground(Color.black);  
      p.add( new Label (l) );
      //p.add ( fields[nfields] );
      p.add ( tf );
      //fields[nfields].addActionListener ( new TextFieldWatcher(nfields) );
      tf.addActionListener ( new TextFieldWatcher(nfields) );
      nfields++;
      return p;
   }

   // Called by the Login dialog to set the userid and password
   public void setUid ( String id, String p ) {
      if ( !id.equals(uid) ) {
	 uidStr = id;
	 uid = new UserID ( id );
      }
      if ( ! p.equals(pwStr) ) {
	 pwStr = p;
	 pw = new Password(p);
      }
      System.out.println ("Userid is " + id );
      System.out.println ("Password is " + p.toString() );
   }

   // some handlers

   // Inner class to watch the indicated textfield and update the
   // changed status if the text is retyped.  New objects are instantiated
   // only for text fields that are changed for the first time.
   private class TextFieldWatcher implements ActionListener {

      private int myTextFieldIndex;

      // Constructor - saves which of the "nrows" TextFields we are watching
      protected TextFieldWatcher(int i) {
	 myTextFieldIndex = i;
      }

      // User hit return key in textfield.  So it may have been changed.
      public void actionPerformed (ActionEvent e) {
      /*
	 System.out.println ("TextFieldWatcher for field " + 
	   myTextFieldIndex + " was invoked ");
	 System.out.println ("The text will be changed to " +
	     e.getActionCommand() );
	 System.out.println ("(Current contents is: " + fields[myTextFieldIndex]+")");
      */
	 changed[myTextFieldIndex] = true; 
	 TextField tf = fields[myTextFieldIndex];
	 if ( tf != null ) {
	    System.out.println ("The object we are changing is: " +
	       tf.hashCode() );
	    fields[myTextFieldIndex].setText ( e.getActionCommand() );
	 }
	 else {
	    fields[myTextFieldIndex] = 
	       new TextField ( e.getActionCommand(), 40 );
	 }
      }

   } // ends TextFieldWatcher

   // Event handler for the "commit" button - make updates to the directory
   private class CommitButtonWatcher implements ActionListener {

      public CommitButtonWatcher () {
	 super();
      }

      public void actionPerformed (ActionEvent e) {
	 System.out.println ("Made " + updateDirectory() + 
	    " updates to the Directory");
      }

   } // ends CommitButtonWatcher

   // Event handler for the "exit" button - clean up and leave
   private class ExitButtonWatcher implements ActionListener {

      private EditMyEntry parent = null;  

      public ExitButtonWatcher ( EditMyEntry parent_ ) {
	 super();
	 parent=parent_;
      }

      // User clicked the Exit button.  Give warning if there are
      // outstanding changes to be made.  Then cleanup and exit.
      public void actionPerformed (ActionEvent e) {
	 for (int i=0; i<nfields; i++)
	    if ( changed[i] ) { 
	       if ( (new ExitWarning( parent )).isYes() ) 
		  parent.updateDirectory();
	       break; 
	    }
	 System.out.println ("EditMyEntry finishes");
	 System.exit(0);
      }

   } // ends ExitButtonWatcher


   // ExitWarning - an inner class which when instantiated pops
   // up a warning dialogue box, collects a response from the user,
   // and returns it as a boolean
   public class ExitWarning extends Dialog {
     
      protected boolean clickedYes = false;
      private Button b1 = new Button ("Yes");
      private Button b2 = new Button ("No");
      private Panel p1 = new Panel();
      private Panel p2 = new Panel();

      // note: BorderLayout is the default for Dialogs

      public ExitWarning( Frame f ) {
	 super ( f, "ExitWarning", true );
	 setBackground ( Color.yellow );
	 b1.addActionListener ( new ButtonWatcher(this) );
	 b2.addActionListener ( new ButtonWatcher (this) );
	 p2.add (b1);
	 p2.add (b2);
	 add ("Center", 
	    new Label ("Changes have been made - update directory?") );
	 add ("South",p2);
	 setSize( new Dimension(300, 80) );
	 setVisible ( true );
      }

      public boolean isYes() { return clickedYes; }

   } // ends ExitWarning

   // These classes handle events posted by the ExitWarning dialog box
   private class ButtonWatcher implements ActionListener {

      ExitWarning p = null;     // who has our "clickedYes" flag

      public ButtonWatcher ( ExitWarning ew ) {
	 super();
	 p = ew;
      }

      public void actionPerformed (ActionEvent e) {
	 String which = e.getActionCommand();
	 System.out.println ("The " + which + " Button was clicked");
	 if ( which.equals("Yes") ) p.clickedYes = true;
	 p.setVisible ( false );
      }
   } // ends ButtonWatcher

   // Login - a dialog box to capture user's id and password
   protected class Login extends Dialog {

      private EditMyEntry p;  // Our EditMyEntry object

      private Panel panel1 = new Panel();
      private Panel panel2 = new Panel();
      private Panel panel3 = new Panel();
      private TextField t1 = new TextField( uidStr, 30 );
      private TextField t2 = new TextField( pwStr, 30 );
      private Button b1 = new Button ("OK")  ;
      private Button b2 = new Button ("Clear")  ;

      public Login ( Frame f ) {
	 super ( f, "Login", true ); // make it modal
	 setTitle ("Login Dialog");    
	 setBackground ( Color.yellow );
	 p = (EditMyEntry)f;

	 panel1.add ( new Label ("userid:") );
	 panel1.add ( t1 );
	 add ("North", panel1);      // userid

	 panel2.add ( new Label ("password:") );
	 panel2.add ( t2 );
	 add ("Center", panel2);      // password

	 b1.setBackground (Color.pink);
	 b2.setBackground (Color.pink);
	 panel3.add ( b1 );
	 panel3.add ( b2 );
	 add ("South", panel3);      // OK, Clear and Exit buttons
	 b1.addActionListener ( new LoginListener (this) );
	 b2.addActionListener ( new LoginListener (this) );

	 setSize ( new Dimension ( 450, 140 ) );
	 setVisible ( true );
      }


      // Called by LoginListener after the OK button has been clicked
      protected void setUid ( ) {
	 p.setUid ( t1.getText(),  t2.getText() );
      }

      // Called by LoginListener to clear the text fields
      protected void clearFields () {
	 t1.setText("");
	 t2.setText("");
      }

   } // ends Login

   protected class LoginListener implements ActionListener {

      Login parent;

      public LoginListener ( Login p ) {
	 parent = p;
      }

      // "action" is the label of a Button if a button is clicked.  
      public void actionPerformed (ActionEvent e) {
	 String action = e.getActionCommand();
	 if (action.equals("OK") ) {
	    parent.setUid();  // save the userid and password
	    parent.setVisible(false);
	 } else if ( action.equals("Clear") ) {
	    parent.clearFields();
	 }
      }
   } // ends LoginListener

   // inner class to collect a new password
   protected class PasswordDialog extends Dialog {

      protected String newPassword;
      private TextField t2 = new TextField ( "", 30 );
      private TextField t3 = new TextField ( "", 30 );

      public PasswordDialog ( Frame f, String oldPassword ) {
	 super ( f, "PasswordDialog", true );
	 Panel p1 = new Panel();
	 Panel p2 = new Panel();
	 Panel p3 = new Panel();
	 p1.add ( new Label ("Enter current password:") );
	 p1.add ( new TextField ("", 30) );
	 p2.add ( new Label ("Enter new password:") );
	 p2.add ( t2 );
	 p3.add ( new Label ("New password, again:") );
	 p3.add ( t3 );
	 Button b = new Button ("OK");
	 b.addActionListener( new PasswordListener(this) );
	 add(p1); add(p2); add(p3); add(b);
	 setSize ( new Dimension ( 475, 140 ) );
	 setVisible ( true );
      }

      // method called by PasswordListener when user hits OK button
      protected void updatePassword () {
	 if ( t2.getText().equals(t3.getText() ) ) {
	    newPassword = t3.getText();
	    System.out.println ("New password is " + newPassword);
	    setVisible ( false );
	 } else {
	    System.out.println ("New password not typed the same way twice; "
	       + " try again" );
	    t2.setText("");
	    t3.setText("");
	 }
      }

      // method called by main GUI when Change Password button is pressed
      protected String getNewPassword() {
	 return newPassword;
      }


   } // ends PasswordDialog

   protected class PasswordListener implements ActionListener {

      private PasswordDialog parent = null;

      public PasswordListener (PasswordDialog pd) {
	 parent = pd;
      }

      // The user has pushed the OK button
      public void actionPerformed (ActionEvent e) {
	 System.out.println ("update the password");
	 parent.updatePassword();
      }

   } // ends PasswordListener

} // ends EditMyEntry
