
package uk.co.wingpath.modsnmp;

import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import org.snmp4j.smi.*;
import uk.co.wingpath.event.*;
import uk.co.wingpath.event.Event;
import uk.co.wingpath.util.*;
import uk.co.wingpath.util.Variable;
import uk.co.wingpath.snmp.*;
import uk.co.wingpath.gui.*;
import uk.co.wingpath.modbusgui.*;

public class DeviceEdit
    implements TreeCard
{
    private final Frontend frontend;
    private final Devices devices;
    private final DeviceTypes deviceTypes;
    private final ModbusSettings modbusSettings;
    private final WComponent<Device> entrySelector;
    private final WTextField nameField;
    private final WTextArea descriptionField;
    private final WComponent<DeviceType> deviceTypeSelector;
    private final WComponent<ModbusInterface> interfaceSelector;
    private final WComponent<Integer> slaveIdField;
/* FUTURE: view-based access
    private final WComponent<String> userField;
*/
    private final JButton applyButton;
    private final JButton resetButton;
    private final JPanel outerPanel;
    private final StatusBar statusBar;
    private final ValueListener modelListener;
    private final Variable<Device> selectionVariable;
    private Device device;
    private final ValueEventSource statusListeners;

    public DeviceEdit (Frontend frontend, Devices devices,
        DeviceTypes deviceTypes, ModbusSettings modbusSettings)
    {
        Event.checkIsEventDispatchThread ();
        this.frontend = frontend;
        this.devices = devices;
        this.deviceTypes = deviceTypes;
        this.modbusSettings = modbusSettings;
        statusListeners = new ValueEventSource ();

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

        outerPanel = new JPanel ();
        outerPanel.setLayout (new BorderLayout ());
        JLabel heading = Gui.createDialogHeading ("Edit Device");
        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);

        selectionVariable = devices.getSelectionVariable ();
        device = null;

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

        entrySelector = new WSelector<Device> (
            "Select Device", devices.getSelectionVariable ());
        entrySelector.setToolTipText ("Select device");
        entrySelector.setMnemonic (KeyEvent.VK_E, 7);
        entrySelector.setWidthChars (20);
        entrySelector.setEnabled (false);
        panel.addComponent (entrySelector);

        nameField = new WTextField (statusBar, "Name");
        nameField.setToolTipText ("Name of device");
        nameField.setMnemonic (KeyEvent.VK_N);
        nameField.setWidthChars (35);
        nameField.setVerifier (new SnmpNameVerifier ("Name", statusBar));
        panel.addComponent (nameField);

        descriptionField = new WTextArea (statusBar, "Description");
        descriptionField.setToolTipText ("Description of device");
        descriptionField.setMnemonic (KeyEvent.VK_D);
        descriptionField.setRows (5);
        descriptionField.setWidthChars (40);
        panel.addComponent (descriptionField);

        deviceTypeSelector = new WSelector<DeviceType> ("Device Type",
            deviceTypes, false);
        deviceTypeSelector.setToolTipText ("Name of device type");
        deviceTypeSelector.setMnemonic (KeyEvent.VK_T);
        deviceTypeSelector.setWidthChars (20);
        panel.addComponent (deviceTypeSelector);

        interfaceSelector = new WSelector<ModbusInterface> ("Interface",
            modbusSettings, false);
        interfaceSelector.setToolTipText ("Name of interface");
        interfaceSelector.setMnemonic (KeyEvent.VK_I);
        interfaceSelector.setWidthChars (20);
        panel.addComponent (interfaceSelector);

        slaveIdField = new WIntegerField (statusBar, "Slave ID", 1, 255, 1);
        slaveIdField.setToolTipText ("Modbus slave identifier");
        slaveIdField.setMnemonic (KeyEvent.VK_S);
        slaveIdField.setWidthChars (10);
        panel.addComponent (slaveIdField);

/* FUTURE: view-based access
        userField = new WTextField (statusBar, "User");
        userField.setToolTipText ("Name of user allowed access");
        userField.setMnemonic (KeyEvent.VK_U);
        userField.setWidthChars (20);
        panel.addComponent (userField);
*/

        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 ());

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

        nameField.addValueListener (guiListener);
        descriptionField.addValueListener (guiListener);
        deviceTypeSelector.addValueListener (guiListener);
        interfaceSelector.addValueListener (guiListener);
        slaveIdField.addValueListener (guiListener);
/* FUTURE: view-based access
        userField.addValueListener (guiListener);
*/

        modelListener = new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    getValuesFromModel ();
                    setEnabled ();
                }
            };

        selectionVariable.addValueListener (new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    selectEntry ();
                }
            });

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

        devices.addListDataListener (
            new ListValueListener (statusBar.getClearListener ("re1")));
    }

    public JPanel getPanel ()
    {
        return outerPanel;
    }

    public String getTag ()
    {
        return "device.edit";
    }

    public String getName ()
    {
        return "Edit Device";
    }

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

    public JButton getDefaultButton ()
    {
        return applyButton;
    }

    public String getToolTipText ()
    {
        return null;
    }

    private void selectEntry ()
    {
        Device e = selectionVariable.getValue ();
        if (e != device)
        {
            device = e;
            if (device != null)
                getValuesFromModel ();
            setEnabled ();
        }
    }

    private void setEnabled ()
    {
        boolean en = device != null && frontend.isStopped ();
        entrySelector.setEnabled (en && devices.getSize () != 0);
        nameField.setEnabled (en);
        descriptionField.setEnabled (en);
        deviceTypeSelector.setEnabled (en);
        interfaceSelector.setEnabled (en);
        slaveIdField.setEnabled (en);
/* FUTURE: view-based access
        userField.setEnabled (en);
*/
    }

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

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

    public boolean hasUnappliedChanges ()
    {
        if (device == null)
            return false;
        boolean changed = false;
        if (nameField.hasValueChanged (device.getName ()))
            changed = true;
        if (descriptionField.hasValueChanged (device.getDescription ()))
            changed = true;
        if (deviceTypeSelector.hasValueChanged (device.getDeviceType ()))
            changed = true;
        if (interfaceSelector.hasValueChanged (device.getModbusInterface ()))
            changed = true;
        if (slaveIdField.hasValueChanged (device.getSlaveId ()))
            changed = true;
/* FUTURE: view-based access
        userField.hasValueChanged (device.getUser ()))
            changed = true;
*/
        return changed;
    }

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

    private boolean checkValues ()
    {
        return
            nameField.checkValue () &&
            descriptionField.checkValue () &&
            slaveIdField.checkValue ();
/* FUTURE: view-based access
            userField.checkValue ();
*/
    }

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

    private void getValuesFromModel ()
    {
        statusBar.clear ("re2");
        if (device != null)
        {
            nameField.setValue (device.getName ());
            descriptionField.setValue (device.getDescription ());
            deviceTypeSelector.setValue (device.getDeviceType ());
            interfaceSelector.setValue (device.getModbusInterface ());
            slaveIdField.setValue (device.getSlaveId ());
/* FUTURE: view-based access
            userField.setValue (device.getUser ());
*/
        }
        setButtonsEnabled (false);
    }

    private void putValuesToModel ()
    {
        if (device != null)
        {
            device.setDescription (descriptionField.getValue ());
            device.setDeviceType (deviceTypeSelector.getValue ());
            device.setModbusInterface (interfaceSelector.getValue ());
            device.setSlaveId (slaveIdField.getValue ());
/* FUTURE: view-based access
            device.setUser (userField.getValue ());
*/
        }
        setButtonsEnabled (false);
    }

    private class ApplyButtonListener implements ActionListener
    {
        public void actionPerformed (ActionEvent e)
        {
            Event.checkIsEventDispatchThread ();

            if (device == null)
                return;
            if (!checkValues ())
                return;
            String name = nameField.getValue ();
            if (name.equals (""))
            {
                statusBar.showError ("Name missing");
                return;
            }
            if (!name.equals (device.getName ()) &&
                devices.getDevice (name) != null)
            {
                statusBar.showError (
                    "There is already a device with name " + name);
                return;
            }
            try
            {
                Device.checkDescription (descriptionField.getValue (),
                    "Description");
            }
            catch (ValueException ex)
            {
                statusBar.showException (ex);
                return;
            }
            putValuesToModel ();
            statusBar.clear ("re3");
        }
    }

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

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

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

