/*
 * AddressBookConfigurationForm.java
 *
 * Copyright 2011 John W Dawson
 *
 * This code is distributed under the terms of the GNU General Public License, version 3
 *
 * This class implements the configuration form for the program
 */
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
abstract class AddressBookConfigurationForm extends AddressBookWindow implements ActionListener
{

  protected AddressBookConfiguration configuration;
  protected ConfigurationRecord configurationRecord;
  private JPanel fieldPanel;
  private int numFields = 0;
  private int fieldWidth;
  private int trailingFieldWidth;
  static final int DEFAULT_FIELD_WIDTH = 24;

  public AddressBookConfigurationForm (String title, ConfigurationRecord configurationRecord, 
                                       AddressBookConfiguration configuration, JFrame opener) 
  {
    this (title, configurationRecord, configuration, opener, DEFAULT_FIELD_WIDTH, DEFAULT_FIELD_WIDTH);
  }

  public AddressBookConfigurationForm (String title, ConfigurationRecord configurationRecord, 
                                       AddressBookConfiguration configuration, JFrame opener, int fieldWidth) 
  {
    this (title, configurationRecord, configuration, opener, fieldWidth, DEFAULT_FIELD_WIDTH);
  }

  public AddressBookConfigurationForm (String title, ConfigurationRecord configurationRecord, 
                                       AddressBookConfiguration configuration, JFrame opener, int fieldWidth, int trailingFieldWidth) 
  {
    super (title, opener);
    this.configuration = configuration;
    this.configurationRecord = configurationRecord;
    this.fieldWidth = fieldWidth;
    this.trailingFieldWidth = trailingFieldWidth;
       
    // Create panel to display fields
    fieldPanel = new JPanel (new SpringLayout());

    // Define the fields
    defineFields ();    
    
    // Lay out panel as a packed grid
    SpringUtilities.makeCompactGrid (fieldPanel, numFields, 2, 5, 5, 5, 5);
    
    // Create panel for buttons
    JPanel butonPanel = new JPanel (new GridBagLayout ());
    
    // Create cancel button
    JButton cancelButton = new JButton ("Cancel");
    cancelButton.addActionListener (this);
    
    // Create OK button with double size font
    Font buttonFont = cancelButton.getFont ();
    JButton okButton = new JButton ("OK");
    okButton.setFont (buttonFont.deriveFont (buttonFont.getSize2D() * 2));
    okButton.addActionListener (this);
    
    // Position buttons on panel
    butonPanel.add (okButton, 
                    new GridBagConstraints (0, 0, 1, 1, 1, 1, 
                                            GridBagConstraints.CENTER, 
                                            GridBagConstraints.NONE, 
                                            new Insets (10, 0, 10, 0), 
                                            0, 0));
    
    butonPanel.add (cancelButton, 
                    new GridBagConstraints (1, 0, 1, 1, 1, 1, 
                                            GridBagConstraints.CENTER, 
                                            GridBagConstraints.NONE, 
                                            new Insets (10, 0, 10, 0), 
                                            0, 0));

 
    // Add panels to window
    Container content = getContentPane ();
    content.setLayout (new GridBagLayout ());
    content.add (fieldPanel,
                 new GridBagConstraints (0, 0, 1, 1, 0, 0, 
                                         GridBagConstraints.CENTER, 
                                         GridBagConstraints.HORIZONTAL, 
                                         new Insets (0, 0, 0, 0), 
                                         0, 0));
    content.add (butonPanel,
                 new GridBagConstraints (0, 1, 1, 1, 0, 0, 
                                         GridBagConstraints.CENTER, 
                                         GridBagConstraints.HORIZONTAL, 
                                         new Insets (0, 0, 0, 0), 
                                         0, 0));
    
    // Pack and make visible 
    this.pack ();
    this.setVisible (true);
  }
  
  protected abstract void defineFields ();
  
  protected void addField (String labelText, Component component)
  {
    // Add label
    JLabel label = new JLabel (labelText, JLabel.TRAILING);
    fieldPanel.add (label);
    
    // Associate label with field component
    label.setLabelFor (component);
    
    // Add component to panel
    fieldPanel.add (component);
    ++numFields;
  }
  
  protected JTextField addTextField (String labelText, String fieldName)
  {
    // Create field
    JTextField field = new JTextField (fieldWidth);
    
    // Get value from configuration and initialise field to this, or to empty string
    String value = configurationRecord != null ? configurationRecord.getElementValue (fieldName) : "";
    field.setText (value != null ? value : "");
    
    // Add to panel with label
    addField (labelText, field);
    
    return field;
  }
  
  protected JTextField addNameField (String labelText)
  {
    // Create field
    JTextField field = new JTextField (fieldWidth);
    
    // Get name from configuration and initialise field to this
    field.setText (configurationRecord != null ? configurationRecord.toString() : "");
    
    // Add to panel with label
    addField (labelText, field);
    
    return field;
  }
  
  protected JPasswordField addPasswordField (String labelText, String fieldName)
  {
    // Create field
    JPasswordField field = new JPasswordField (fieldWidth);
    
    // Get value from configuration and initialise field to this
    String value = configurationRecord != null ? configurationRecord.getEncryptedValue (fieldName) : "";
    field.setText (value != null ? value : "");
    
    // Add to panel with label
    addField (labelText, field);
    
    return field;
  }

  protected void addLabel (String labelText)
  {
    // Create field and make it invisible
    JTextField field = new JTextField (fieldWidth);
    field.setVisible (false);
        
    // Add to panel with label
    addField (labelText, field);
  }
  
  protected void addFieldTrailingLabel (String labelText, Component component)
  {
    // Add component to panel
    fieldPanel.add (component);
    
    // Add label
    JLabel label = new JLabel (labelText);
    fieldPanel.add (label);
    
    // Associate label with field component
    label.setLabelFor (component);

    ++numFields;
    
  }
  
  protected JTextField addTextFieldTrailingLabel (String labelText, String fieldName)
  {
    // Create field
    JTextField field = new JTextField (trailingFieldWidth);
    
    // Get value from configuration and initialise field to this, or to empty string
    String value = configurationRecord != null ? configurationRecord.getElementValue (fieldName) : "";
    field.setText (value != null ? value : "");
    
    // Add to panel with label
    addFieldTrailingLabel (labelText, field);
    
    return field;
  }
  

  protected boolean checkFieldEntry (JTextField field, String message)
  {
    // Check if field is empty
    if (field.getText().isEmpty())
    {
      // If so display warning and set focus
      JOptionPane.showMessageDialog (this, message, "Incomplete configuration data", JOptionPane.ERROR_MESSAGE);
      field.requestFocus ();
      return false;
    }
    else
    {
      return true;
    }
  }
  
  public void actionPerformed (ActionEvent event)
  {
    // Check which button was clicked
    AbstractButton source = (AbstractButton) event.getSource ();
    
    if (source.getText().equals ("Cancel"))
    {
      // Perform any form specific actions
      if (cancel ())
      {
      
        // Close the window
        closeWindow ();
      }
    }
    else if (source.getText().equals ("OK"))
    {
      // Validate and save data
      if (validateAndSave ())
      {
        // Close the window
        closeWindow ();
      }
    }
    else
    {
      otherAction (source);
    }
  }
  
  private void closeWindow ()
  {
    // Disable the handler for the close action (so default action doesn't take place)
    removeWindowListener (this);
    
    // Re-enable the previous window
    reEnablePreviousWindow ();
    
    // Dispose of this window
    dispose ();
  }
  
  protected Boolean cancel ()
  {
    return true;
  }
  
  protected abstract boolean validateAndSave ();
  
  protected abstract void otherAction (AbstractButton source);
            
}
