
package uk.co.wingpath.modsnmp;

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import uk.co.wingpath.event.*;
import uk.co.wingpath.event.Event;
import uk.co.wingpath.util.*;
import uk.co.wingpath.gui.*;
import uk.co.wingpath.modbusgui.*;
import uk.co.wingpath.modbus.*;

public class ModbusServerPanel
    implements TreeCard
{
    private final ModbusServerSettings settings;

    private final ValueEventSource statusListeners;

    private final WComponent<Boolean> enabledField;
    private final WComponent<String> hostField;
    private final WComponent<Integer> portField;
    private final WComponent<Integer> eomTimeoutField;
    private WComponent<Integer> idleTimeoutField;

    private final JButton applyButton;
    private final JButton resetButton;
    private final JPanel outerPanel;
    private final ModSnmpFrontend frontend;
    private final StatusBar statusBar;

    public ModbusServerPanel (final ModSnmpFrontend frontend,
        final ModbusServerSettings settings)
    {
        this.frontend = frontend;
        this.settings = settings;
        statusListeners = new ValueEventSource ();

        statusBar = new StatusBar ("snmp-interface", frontend.getHelpViewer ());
        statusBar.addStatusListener (
            new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    fireStatusChanged ();
                }
            });

        outerPanel = new JPanel ();
        outerPanel.setLayout (new BorderLayout ());
        JLabel heading = Gui.createDialogHeading ("Modbus Server");
        outerPanel.add (heading, BorderLayout.NORTH);
        outerPanel.add (statusBar, BorderLayout.SOUTH);

        JPanel mainPanel = new JPanel ();
        outerPanel.add (mainPanel, BorderLayout.CENTER);
        mainPanel.setLayout (new BorderLayout ());
        ButtonPanel buttonPanel = new ButtonPanel ();
        mainPanel.add (buttonPanel, BorderLayout.SOUTH);

        GridBagPanel panel = new GridBagPanel ();
        mainPanel.add (panel, BorderLayout.CENTER);

        ValueListener guiListener = new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    statusBar.clear ();
                    setButtonsEnabled ();
                }
            };

        enabledField = new WCheckBox ("Enabled", true);
        enabledField.setToolTipText ("Whether to start the Modbus server");
        enabledField.setMnemonic (KeyEvent.VK_E);
        panel.addComponent (enabledField);
        enabledField.addValueListener (guiListener);

        hostField = new WTextField (statusBar, "Host");
        hostField.setToolTipText (
            "<html>Host name or IP address on which to accept connections<br>" +
            "Leave empty for any address");
        hostField.setMnemonic (KeyEvent.VK_O);
        hostField.setWidthChars (25);
        panel.addComponent (hostField);
        hostField.addValueListener (guiListener);

        portField = new WIntegerField (statusBar, "Port",
            ModbusServerSettings.MIN_PORT, ModbusServerSettings.MAX_PORT, 502);
        portField.setToolTipText ("Port on which to listen for connections");
        portField.setMnemonic (KeyEvent.VK_P);
        portField.setWidthChars (10);
        panel.addComponent (portField);
        portField.addValueListener (guiListener);

        eomTimeoutField = new WIntegerField (statusBar, "EOM Timeout",
            ModbusServerSettings.MIN_EOM_TIMEOUT,
            ModbusServerSettings.MAX_EOM_TIMEOUT,
            ModbusServerSettings.MIN_EOM_TIMEOUT);
        eomTimeoutField.setToolTipText (
            "Timeout for end-of-message (in milliseconds)");
        eomTimeoutField.setMnemonic (KeyEvent.VK_E);
        eomTimeoutField.setWidthChars (10);
        panel.addComponent (eomTimeoutField);
        eomTimeoutField.addValueListener (guiListener);

        idleTimeoutField = new WIntegerField (statusBar, "Idle timeout",
            0, ModbusServerSettings.MAX_IDLE_TIMEOUT, 0);
        idleTimeoutField.setToolTipText (
            "<html>Period in seconds after which a connection will be " +
            "closed if idle.<br>" +
            "A value of 0 will disable the timeout.");
        idleTimeoutField.setMnemonic (KeyEvent.VK_I);
        idleTimeoutField.setWidthChars (10);
        panel.addComponent (idleTimeoutField);
        idleTimeoutField.addValueListener (guiListener);

        applyButton = buttonPanel.addButton ("Apply", null,
            new ApplyButtonListener ());

        resetButton = buttonPanel.addButton ("Reset", null,
            new ActionListener ()
            {
                public void actionPerformed (ActionEvent e)
                {
                    reset ();
                }
            });
        resetButton.setMnemonic (KeyEvent.VK_R);

        buttonPanel.addButton (getHelpAction ());

        frontend.addBackendStateListener (new BackendState.Listener ()
            {
                public void stateChanged (BackendState state)
                {
                    setEnabled ();
                    setButtonsEnabled ();
                }
            });

        settings.addValueListener (
            new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    getValuesFromModel ();
                }
            });
        getValuesFromModel ();
    }

    public JPanel getPanel ()
    {
        return outerPanel;
    }

    public String getTag ()
    {
        return "modbus_server";
    }

    public String getName ()
    {
        return "Modbus Server";
    }

    public Action getHelpAction ()
    {
        return frontend.getHelpAction ("mbserver");
    }

    public JButton getDefaultButton ()
    {
        return applyButton;
    }

    public String getToolTipText ()
    {
        return null;
    }

    @Override
    public void selected ()
    {
        setButtonsEnabled ();
    }

    @Override
    public void reset ()
    {
        getValuesFromModel ();
    }

    private void setEnabled ()
    {
        boolean en = frontend.isStopped ();
        enabledField.setEnabled (en);
        hostField.setEnabled (en);
        portField.setEnabled (en);
        eomTimeoutField.setEnabled (en);
        idleTimeoutField.setEnabled (en);
    }

    public boolean isEnabled ()
    {
        return frontend.isStopped ();
    }

    public boolean hasUnappliedChanges ()
    {
        boolean changed = false;
        if (enabledField.hasValueChanged (settings.isEnabled ()))
            changed = true;
        if (hostField.hasValueChanged (settings.getHost ()))
            changed = true;
        if (portField.hasValueChanged (settings.getPort ()))
            changed = true;
        if (eomTimeoutField.hasValueChanged (settings.getEomTimeout ()))
            changed = true;
        if (idleTimeoutField.hasValueChanged (settings.getIdleTimeout ()))
            changed = true;
        return changed;
    }

    public boolean hasError ()
    {
        return statusBar.hasError ();
    }

    private boolean checkValues ()
    {
        return 
            enabledField.checkValue () &&
            hostField.checkValue () &&
            portField.checkValue () &&
            eomTimeoutField.checkValue () &&
            idleTimeoutField.checkValue ();
    }

    private void setButtonsEnabled ()
    {
        boolean enabled = frontend.isStopped () && hasUnappliedChanges ();
        Gui.setEnabled (applyButton, enabled);
        Gui.setEnabled (resetButton, enabled);
        fireStatusChanged ();
    }

    private void getValuesFromModel ()
    {
        statusBar.clear ();
        enabledField.setValue (settings.isEnabled ());
        hostField.setValue (settings.getHost ());
        portField.setValue (settings.getPort ());
        eomTimeoutField.setValue (settings.getEomTimeout ());
        idleTimeoutField.setValue (settings.getIdleTimeout ());
        setButtonsEnabled ();
    }

    private void putValuesToModel ()
    {
        settings.setEnabled (enabledField.getValue ());
        settings.setHost (hostField.getValue ());
        settings.setPort (portField.getValue ());
        settings.setEomTimeout (eomTimeoutField.getValue ());
        settings.setIdleTimeout (idleTimeoutField.getValue ());
        settings.fireValueChanged ();
        setButtonsEnabled ();
    }

    private class ApplyButtonListener
        implements ActionListener
    {
        public void actionPerformed (ActionEvent e)
        {
            Event.checkIsEventDispatchThread ();
            if (!checkValues ())
                return;
            putValuesToModel ();
            statusBar.clear ();
        }
    }

    private void fireStatusChanged ()
    {
        statusListeners.fireValueChanged (this);
    }

    public void addStatusListener (ValueListener l)
    {
        statusListeners.addListener (l);
    }

    public void removeStatusListener (ValueListener l)
    {
        statusListeners.removeListener (l);
    }
}


