package com.ibm.able.examples.ablebean;

//====================================================================
//
// Licensed Materials - Property of IBM
//
// "Restricted Materials of IBM"
//
// Product: com.ibm.able.examples.ablebean
//
// (C) Copyright IBM Corp. 2000 All Rights Reserved.
//
// US Government Users Restricted Rights - Use, duplication or
// disclosure restricted by GSA ADP Schedule Contract with
// IBM Corp.
//
//
//                             DISCLAIMER
//                             ----------
//
// This material contains programming source code for your consideration.
// These examples have not been thoroughly tested under all conditions.
// IBM, therefore, cannot guarantee or imply reliability, serviceability,
// performance or function of these programs.  All programs contained
// herein are provided to you "AS IS".  THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
// DISCLAIMED.
//
//====================================================================

//====================================================================
// Imports
//====================================================================
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.net.URL;
import java.rmi.RemoteException;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import com.ibm.able.Able;
import com.ibm.able.AbleCustomizerPanel;
import com.ibm.able.AbleHelp;
import com.ibm.able.AblePanelHelper;
import com.ibm.able.AbleProperty;
import com.ibm.able.editor.AbleGridBagConstraints;

/**
 * This class provides the panel for the File Watcher Agent.
 *
 * @see AbleFileWatcherCustomizer
 *
 * @version  $Revision: 1.4 $, $Date: 2001/09/17 21:52:01 $
 *
 * @author   Joe Bigus
 */
public class AbleFileWatcherPanel
   extends JPanel
   implements AbleCustomizerPanel {

   //-----------------------------------------------------------------
   // Class variables
   //-----------------------------------------------------------------

   //-----------------------------------------------------------------
   // Member variables
   //-----------------------------------------------------------------
   private AbleFileWatcher myFileWatcher = null;
   private AbleFileWatcherCustomizer myCustomizer = null;

   private String myFileName = null;
   private JTextField myFileNameTextField = null;
   private JRadioButton myConditionModifiedRadioButton = null;
   private JRadioButton myConditionDeletedRadioButton = null;
   private JRadioButton myConditionThresholdRadioButton = null;
   private JTextField myThresholdTextField = null;
   private JLabel myFileSizeLabel = null;
   private JRadioButton myActionNoneRadioButton = null;
   private JRadioButton myActionAlertRadioButton = null;
   private JRadioButton myActionExecuteRadioButton = null;
   private JTextField myCommandTextField = null;
   private JRadioButton myActionNotifyRadioButton = null;
   private JButton myInitializeButton = null;

   private TextListener myTextListener = null;

   //-----------------------------------------------------------------
   // Constructors
   //-----------------------------------------------------------------
   /**
    *  No default constructor allowed.
    */
   private AbleFileWatcherPanel() {
   }

   /**
    * Construct the panel for the customizer.
    */
   public AbleFileWatcherPanel(AbleFileWatcherCustomizer theCustomizer) {
      super();
      myCustomizer = theCustomizer;
      initializePanel();
      addPropertyListeners();
   }

   //-----------------------------------------------------------------
   // Member methods
   //-----------------------------------------------------------------

   /**
    * Save a reference to the agent that is being customized.
    * Get the data from the bean and set the panel components.
    *
    * @param     theObject
    *            The AbleImport bean that is to be changed.
    * @exception RemoteException is thrown when data cannot be retrieved
    *            from a bean.
    */
   public void getDataFromBean(Object theObject) throws RemoteException {
      if (myFileWatcher == null) {
         myFileWatcher = (AbleFileWatcher) theObject;
      }
      myFileNameTextField.setText(myFileWatcher.getWatchFileName());
      switch (myFileWatcher.getCondition()) {
         case AbleFileWatcher.FILE_MODIFIED :
            myConditionModifiedRadioButton.setSelected(true);
            break;
         case AbleFileWatcher.FILE_DELETED :
            myConditionDeletedRadioButton.setSelected(true);
            break;
         case AbleFileWatcher.FILE_THRESHOLD :
            myConditionThresholdRadioButton.setSelected(true);
            break;
         default :
            }
      myThresholdTextField.setText(
         String.valueOf(myFileWatcher.getThreshold()));
      myFileSizeLabel.setText("current length: " + myFileWatcher.length());
      switch (myFileWatcher.getAction()) {
         case AbleFileWatcher.ACTION_ALERT :
            myActionAlertRadioButton.setSelected(true);
            break;
         case AbleFileWatcher.ACTION_EXECUTE :
            myActionExecuteRadioButton.setSelected(true);
            break;
         case AbleFileWatcher.ACTION_EVENT :
            myActionNotifyRadioButton.setSelected(true);
            break;
         case AbleFileWatcher.ACTION_NONE :
            myActionNoneRadioButton.setSelected(true);
            break;
         default :
            }
      myCommandTextField.setText(myFileWatcher.getCommand());
      setButtonStates();
   }

   /**
    * Update the bean that is being customized.
    *
    * @exception RemoteException is thrown when data cannot be set
    *            on a remote bean.
    */
   public void setDataOnBean() throws RemoteException {
      try {
         myFileWatcher.setWatchFileName(myFileNameTextField.getText().trim());

         if (myConditionModifiedRadioButton.isSelected())
            myFileWatcher.setCondition(AbleFileWatcher.FILE_MODIFIED);
         else if (myConditionDeletedRadioButton.isSelected())
            myFileWatcher.setCondition(AbleFileWatcher.FILE_DELETED);
         else if (myConditionThresholdRadioButton.isSelected())
            myFileWatcher.setCondition(AbleFileWatcher.FILE_THRESHOLD);

         myFileWatcher.setThreshold(
            Long.parseLong(myThresholdTextField.getText().trim()));

         if (myActionAlertRadioButton.isSelected())
            myFileWatcher.setAction(AbleFileWatcher.ACTION_ALERT);
         else if (myActionExecuteRadioButton.isSelected())
            myFileWatcher.setAction(AbleFileWatcher.ACTION_EXECUTE);
         else if (myActionNotifyRadioButton.isSelected())
            myFileWatcher.setAction(AbleFileWatcher.ACTION_EVENT);
         else
            myFileWatcher.setAction(AbleFileWatcher.ACTION_NONE);

         myFileWatcher.setCommand(myCommandTextField.getText().trim());

      } catch (NumberFormatException e) {
         throw new RemoteException(
            "Non-numeric input provided on File Watcher panel."
               + Able.LS
               + e.toString());
      } catch (NullPointerException e2) {
         throw new RemoteException(
            "Blank input provided on File Watcher panel."
               + Able.LS
               + e2.toString());
      }
   }

   /**
    * Initialize the panel.
    *
    */
   private void initializePanel() {
      this.setLayout(new GridBagLayout());
      int row = 0;
      add(
         (new JLabel("File Name:")),
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(10, 10, 10, 0),
            0,
            0));

      myFileNameTextField = new JTextField();
      myFileNameTextField.setToolTipText("Path and name of file to watch");
      add(
         myFileNameTextField,
         new AbleGridBagConstraints(
            1,
            row,
            2,
            1,
            0.5,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(10, 10, 10, 10),
            0,
            0));

      JButton browseButton = new JButton("Browse...");
      browseButton.setToolTipText("Select a file or directory to watch");
      browseButton.addActionListener((new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            BrowseFileButton_actionPerformed(e);
         }
      }));
      add(
         browseButton,
         new AbleGridBagConstraints(
            3,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(10, 10, 10, 10),
            0,
            0));

      row++;

      myTextListener = new TextListener();
      myFileNameTextField.getDocument().addDocumentListener(myTextListener);

      myInitializeButton = new JButton("Initialize");
      myInitializeButton.setToolTipText("Initialize the bean");
      myInitializeButton.addActionListener((new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            InitializeButton_actionPerformed(e);
         }
      }));
      row++;
      add(
         myInitializeButton,
         new AbleGridBagConstraints(
            1,
            row,
            2,
            1,
            0.0,
            0.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.NONE,
            new Insets(0, 50, 10, 50),
            100,
            0));

      row++;
      add(
         getWatchPanel(),
         new AbleGridBagConstraints(
            0,
            row,
            4,
            4,
            0.5,
            0.5,
            GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(10, 5, 10, 5),
            0,
            0));

      row = row + 4;
      add(
         getActionPanel(),
         new AbleGridBagConstraints(
            0,
            row,
            4,
            4,
            0.5,
            0.5,
            GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(10, 5, 10, 5),
            0,
            0));
   }

   /**
    *  Create and populate the controls related to the conditions to watch.
    *  @return A JPanel containing the appropriate controls.
    */
   private JPanel getWatchPanel() {
      JPanel watchPanel = new JPanel();
      watchPanel.setLayout(new GridBagLayout());
      watchPanel.setBorder(new TitledBorder("Watch condition"));

      ButtonGroup watchGroup = new ButtonGroup();
      int row = -1;

      myConditionModifiedRadioButton = new JRadioButton("Modified");
      row++;
      watchPanel.add(
         myConditionModifiedRadioButton,
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            50,
            0));
      watchGroup.add(myConditionModifiedRadioButton);

      myConditionDeletedRadioButton = new JRadioButton("Deleted");
      row++;
      watchPanel.add(
         myConditionDeletedRadioButton,
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            50,
            0));
      watchGroup.add(myConditionDeletedRadioButton);

      myConditionThresholdRadioButton = new JRadioButton("Size threshold");
      row++;
      watchPanel.add(
         myConditionThresholdRadioButton,
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            50,
            0));
      watchGroup.add(myConditionThresholdRadioButton);
      myThresholdTextField = new JTextField();
      watchPanel.add(
         myThresholdTextField,
         new AbleGridBagConstraints(
            1,
            row,
            1,
            1,
            0.5,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0, 0, 0, 5),
            70,
            0));
      myConditionThresholdRadioButton.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
            setButtonStates();
         }
      });
      myFileSizeLabel = new JLabel();
      watchPanel.add(
         myFileSizeLabel,
         new AbleGridBagConstraints(
            2,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            70,
            0));

      return watchPanel;

   }

   /**
    *  Create and populate the controls related to the actions to take.
    *  @return A JPanel containing the appropriate controls.
    */
   private JPanel getActionPanel() {
      JPanel actionPanel = new JPanel();
      actionPanel.setLayout(new GridBagLayout());
      actionPanel.setBorder(new TitledBorder("Action"));

      ButtonGroup actionGroup = new ButtonGroup();

      int row = -1;

      myActionNotifyRadioButton = new JRadioButton("Notify listeners");
      row++;
      actionPanel.add(
         myActionNotifyRadioButton,
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            0,
            0));
      actionGroup.add(myActionNotifyRadioButton);

      myActionAlertRadioButton = new JRadioButton("Show alert dialog");
      row++;
      actionPanel.add(
         myActionAlertRadioButton,
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            0,
            0));
      actionGroup.add(myActionAlertRadioButton);

      myActionExecuteRadioButton = new JRadioButton("Execute command");
      row++;
      actionPanel.add(
         myActionExecuteRadioButton,
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            0,
            0));
      actionGroup.add(myActionExecuteRadioButton);
      myCommandTextField = new JTextField();
      actionPanel.add(
         myCommandTextField,
         new AbleGridBagConstraints(
            1,
            row,
            2,
            1,
            0.5,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0, 0, 0, 5),
            0,
            0));

      myActionNoneRadioButton = new JRadioButton("None");
      row++;
      actionPanel.add(
         myActionNoneRadioButton,
         new AbleGridBagConstraints(
            0,
            row,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0, 10, 0, 5),
            0,
            0));
      actionGroup.add(myActionNoneRadioButton);

      return actionPanel;

   }

   /**
    *  Anytime another application or another panel changes the AbleEventProcessingEnabled
    *  property, refresh this panel.  This also occurs as a side effect of pressing the
    *  Initialize button on this panel since the init method sets this property.
    *
    */
   private void addPropertyListeners() {
      myCustomizer.addPropertyChangeMethod(
         AbleProperty.AbleEventProcessingEnabled,
         this,
         "refreshPanel");
   }

   /**
    *  Enable disable button states based on screen content and object state.
    *
    */
   private void setButtonStates() {
      boolean initAble = myFileNameTextField.getText().trim().length() > 0;
      myInitializeButton.setEnabled(initAble);
   }

   //------------------------------------------------------------------
   // Actions
   //------------------------------------------------------------------
   /**
    *  Browse directory to locate definition file.
    */
   private void BrowseFileButton_actionPerformed(ActionEvent theEvent) {
      String newDir =
         AblePanelHelper.setTextFieldFromFileDialog(
            myFileNameTextField,
            myCustomizer.getWorkingDirectory());
      if (newDir != null) {
         myCustomizer.setWorkingDirectory(newDir);
      }
   }

   /**
    * User pressed Initialize button.
    *
    * @param theEvent the button pressed event.
    */
   private void InitializeButton_actionPerformed(ActionEvent e) {
      try {

         myCustomizer.updateProperties();
         myCustomizer.setIgnoreAnyPropertyChanges(true);
         myFileWatcher.init();
         myCustomizer.setIgnoreAnyPropertyChanges(false);
         myCustomizer.setObject(myFileWatcher);
         // refresh from underlying object

      } catch (Exception exc) {
         JOptionPane.showMessageDialog(this, // Parent
         exc.toString(), // Msg
         "AbleFileWatcherPanel Error: InitializeButton()", // Title
         JOptionPane.ERROR_MESSAGE // Severity
         );
      }
   }

   /**
    * Reset the network weights.
    * @param theEvent the button pressed event.
    */
   private void ResetButton_actionPerformed(ActionEvent theEvent) {
      try {
         myCustomizer.updateProperties();
         myFileWatcher.reset(); // reset the network
         myCustomizer.setObject(myFileWatcher);
      } catch (Exception e) {
         JOptionPane.showMessageDialog(this, // Parent
         e.toString(), // Msg
         "AbleFileWatcherPanel Error: ResetButton()", // Title
         JOptionPane.ERROR_MESSAGE // Severity
         );
      }
   }

   //-----------------------------------------------------------------
   // Listener methods
   //-----------------------------------------------------------------
   /**
    *  Refresh the panel on specific property change events.
    *
    *  @param theEvent is the event issued when an agent's property changes.
    */
   public void refreshPanel(PropertyChangeEvent theEvent) {
      try {
         getDataFromBean(myFileWatcher);
      } catch (RemoteException e) {
         JOptionPane.showMessageDialog(myCustomizer, // Parent
         "Panel values for training changed, but were not updated."
            + Able.LS
            + e.toString(),
         // Msg
         "AbleFileWatcherPanel Warning: refreshPanel()", // Title
         JOptionPane.WARNING_MESSAGE // Severity
         );
      }
   }

   //------------------------------------------------------------------
   // Required by AbleCustomizerPanel interface
   //------------------------------------------------------------------

   /**
    * Get the html file name to be displayed.
    *
    * @return A String containing the html file to display in the browser.
    */
   public String getHelpFileName() {
      return AbleHelp.helpFilesPath
         + "examples/ablebean/doc-files/AbleFileWatcherHelp.html";
   }

   /**
    * Get the URL file context to be displayed. Able.HomeUrl is the
    * Able context.
    *
    * @see Able
    *
    * @return A URL containing the html file to display in the browser.
    */
   public URL getHelpContext() {
      return Able.HomeUrl;
   }

   //-----------------------------------------------------------------
   // Inner Classes
   //-----------------------------------------------------------------
   /**
    * This class changes the button states when a text field changes.
    */
   class TextListener implements DocumentListener {
      public void changedUpdate(DocumentEvent e) {
         setButtonStates();
      }
      public void insertUpdate(DocumentEvent e) {
         setButtonStates();
      }
      public void removeUpdate(DocumentEvent e) {
         setButtonStates();
      }
   }

   /**
    * Determine the copyright of this class.
    *
    * @return    A String containing this class's copyright statement.
    *            <p>
    */
   private static String Copyright() {
      return Able.Copyright;
   }

}
