import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;

/**
 * The main class, from which configuration, mail checking, and message
 * viewing functions can be accessed.
 *
 * @author      Simon Pollard
 */

public class PopF implements ActionListener, PopFetcherListener, ConfigProperties
{
  private JLabel conStatus, msgStatus;
  private JButton cfgButton, chkButton, msgButton;
  private PopFetcher fetchThread = null;
  private JFrame cfgFrame;

  private Properties serverProperties;
  private String[] propertyOrder;

  /**
   * Sets up the initial configuration of the mail system and creates
   * the main window from where all operations are accessed.
   *
   * @param     mainFra the frame to draw the main window in
   */
  public PopF(JFrame mainFra) {
    FileInputStream configFile;
    boolean autoConfig = false;

    serverProperties = new Properties();

    // try to read from config file
    try {
      configFile = new FileInputStream("PopF.cfg");
      serverProperties.load(configFile);
      configFile.close();
    } catch (Exception e) {
      // file probably doesn't exist - pop up config. window automatically
      autoConfig = true;
    }

    // set defaults if not loaded
    PopProperties.setPopDefaults(serverProperties);

    // and the order they should be in
    propertyOrder = new String[4];
    propertyOrder[0] = PopProperties.SERVER;
    propertyOrder[1] = PopProperties.USERNAME;
    propertyOrder[2] = PopProperties.PASSWORD;
    propertyOrder[3] = PopProperties.FETCHTIME;

    // buttons
    cfgButton = new JButton("Configure");
    cfgButton.setMnemonic('C');
    cfgButton.addActionListener(this);

    chkButton = new JButton("Check Now");
    chkButton.setMnemonic('K');
    chkButton.addActionListener(this);

    JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 5, 5));
    buttonPanel.add(cfgButton);
    buttonPanel.add(chkButton);

    Box boundingBox = new Box(BoxLayout.Y_AXIS);
    boundingBox.add(Box.createVerticalStrut(5));
    boundingBox.add(buttonPanel);
    boundingBox.add(Box.createVerticalStrut(20));

    // default labels so the box isn't made too small
    conStatus = new JLabel("Nothing", SwingConstants.CENTER);

    msgStatus = new JLabel("Unknown", SwingConstants.CENTER);
    msgButton = new JButton("Show Msgs");
    msgButton.setMnemonic('M');
    msgButton.addActionListener(this);
    JPanel msgPanel = new JPanel(new GridLayout(1, 2, 5, 5));
    msgPanel.add(msgStatus);
    msgPanel.add(msgButton);

    JPanel statusBox = new JPanel(new BorderLayout());
    statusBox.add(BorderLayout.NORTH, conStatus);
    statusBox.add(BorderLayout.CENTER, new JSeparator());
    statusBox.add(BorderLayout.SOUTH, msgPanel);

    // and make the frame
    mainFra.getContentPane().setLayout(new BorderLayout());
    mainFra.getContentPane().add(BorderLayout.NORTH, boundingBox);
    mainFra.getContentPane().add(BorderLayout.CENTER, new JSeparator());
    mainFra.getContentPane().add(BorderLayout.SOUTH, statusBox);

    mainFra.pack();
    mainFra.setVisible(true);

    // show config. window if necessary
    if(autoConfig) {
      CfgWindow confWin = new CfgWindow(serverProperties, propertyOrder, this);
    }

    // start the fetching thread and timer
    fetchThread = new PopFetcher(serverProperties);
    fetchThread.addPopFetcherListener(this);
    fetchThread.start();
  }

  /**
   * The 'main' function.  Draws a splash screen, then creates the frame
   * for the rest of the program to run in.
   *
   * @param     args Any arguments passed to the program (ignored)
   */
  public static void main(String args[]) {

    JWindow splashWin = new JWindow();
    splashWin.getContentPane().add(new JLabel(new ImageIcon("pop3logo.gif")));
    splashWin.pack();
    splashWin.setLocation(new Point(300,200));
    splashWin.setVisible(true);
    try {
      Thread.sleep(1000 * 3);
    } catch(Exception e) {
      // It's not going to get interrupted anyway
    }
    splashWin.dispose();

    JFrame f = new JFrame("POP fetcher");

    f.addWindowListener(new PopFAdapter());

    PopF pan = new PopF(f);
  }

  /**
   * Called when one of the buttons on the main window has been clicked,
   * and opens the configuration window, checks for mail, or shows the
   * message list as appropriate.
   *
   * @param     e the ActionEvent that has occurred
   * @see       java.awt.event.ActionListener
   */
  public void actionPerformed(ActionEvent e) {

    if(e.getSource() == cfgButton) {
      // open the configuration window
      CfgWindow confWin = new CfgWindow(serverProperties, propertyOrder, this);
    } else {
      if(fetchThread.getBusyFlag() == false) { // not already doing something else
        if(e.getSource() == chkButton) {
          // interrupt the thread to cause it to check for mail
          fetchThread.setCheckFlag(PopFetcher.FORCECHECK);
          fetchThread.interrupt();
        }

        if(e.getSource() == msgButton) {
          fetchThread.setCheckFlag(PopFetcher.SHOWMESSAGES);
          fetchThread.interrupt();
        }
      } else
        JOptionPane.showMessageDialog(null, "Please wait - system busy");
    }
  }

  /**
   * Called when a PopFetcherEvent has occurred - either a status event
   * or an error event.  Errors events will pop up an error dialog, status
   * events will update the status label.
   *
   * @param     e the PopFetcherEvent that has occurred
   * @see       PopFetcherEvent
   */
  public void popFetcherEvent(PopFetcherEvent e) {
    if(e.getEventNum() == PopFetcherEvent.PFEMESSAGES) { // number of messages updated
      msgStatus.setText(e.getNumMessages() + " messages");
    } else if(e.getEventNum() > 100) { // an error
      JOptionPane.showMessageDialog(null, e.getMessage(), "PopFetcher Error", JOptionPane.ERROR_MESSAGE);
    } else { // just a status message
      conStatus.setText(e.getMessage());
    }
  }

  /**
   * Returns the current set of properties for the program.
   *
   * @return    the current set of Properties
   * @see       ConfigProperties
   * @see       java.util.Properties
   */
  public Properties queryCfgProperties() { return serverProperties; }

  /**
   * Sets a new set of properties for the program.
   *
   * @param     newProperties the new set of Properties to be applied
   * @see       ConfigProperties
   * @see       java.util.Properties
   */
  public void setCfgProperties(Properties newProperties) {
    FileOutputStream configFile;

    serverProperties.clear();
    serverProperties.putAll(newProperties);

    try {
      configFile = new FileOutputStream("PopF.cfg");
      serverProperties.store(configFile, "PopF Config File");
      configFile.close();
    } catch (Exception e) {
      JOptionPane.showMessageDialog(null, "Warning - couldn't write to config file - " + e.getMessage());
    }

    if(fetchThread != null) fetchThread.updateProperties(serverProperties);
  }
}

class PopFAdapter extends WindowAdapter {
   public void windowClosing(WindowEvent e)
   {
      System.exit(0); 
   }
}
