
package uk.co.wingpath.modbusgui;

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

public class BigValueSettingsPanel
    implements TreeCard
{
    private final Registers registers;
    private final FileRegisters fileRegisters;
    private final Frontend frontend;
    private final BigValueSettings bigValueSettings;

    private final ValueEventSource statusListeners;

    private final WComponent<Boolean> endianCheckbox;
    private final WComponent<Boolean> wordRegCheckbox;
    private final WComponent<Boolean> wordCountCheckbox;
    private final JButton applyButton;
    private final JButton resetButton;
    private final JPanel outerPanel;
    private final StatusBar statusBar;

    public BigValueSettingsPanel (Frontend frontend,
        BigValueSettings bigValueSettings, final Registers registers,
        final FileRegisters fileRegisters)
    {
        Event.checkIsEventDispatchThread ();

        this.frontend = frontend;
        this.bigValueSettings = bigValueSettings;
        this.registers = registers;
        this.fileRegisters = fileRegisters;
        statusListeners = new ValueEventSource ();

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

        outerPanel = new JPanel ();
        outerPanel.setLayout (new BorderLayout ());
        JLabel heading = Gui.createDialogHeading ("32/64-bit Values");
        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);

        ValueListener valueListener = new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    statusBar.clear ("bvf3");
                    setButtonsEnabled (hasUnappliedChanges ());
                }
            };

        GridBagPanel panel = new GridBagPanel ();
        mainPanel.add (panel, BorderLayout.CENTER);
        endianCheckbox = new WCheckBox ("Little-endian", false);
        endianCheckbox.setToolTipText (
            "<html>Whether least-significant word (16 bit)<br>" +
            "of 32 and 64 bit values is sent first</html>");
        endianCheckbox.setMnemonic (KeyEvent.VK_L);
        panel.addComponent (endianCheckbox);
        endianCheckbox.addValueListener (valueListener);

        wordRegCheckbox = new WCheckBox ("Word Registers", false);
        wordRegCheckbox.setToolTipText (
            "<html>Whether each 16-bit word of a value has its " +
            "own address (selected)<br>" +
            "or a single address is used for the " +
            "whole value (unselected)</html>");
        wordRegCheckbox.setMnemonic (KeyEvent.VK_W);
        panel.addComponent (wordRegCheckbox);
        wordRegCheckbox.addValueListener (valueListener);

        wordCountCheckbox = new WCheckBox ("Word Count", false);
        wordCountCheckbox.setToolTipText (
            "<html>Whether count in packet is number of 16-bit " +
            "words (selected)<br>" +
            "or values (unselected)</html>");
        wordCountCheckbox.setMnemonic (KeyEvent.VK_C);
        panel.addComponent (wordCountCheckbox);
        wordCountCheckbox.addValueListener (valueListener);

        applyButton = buttonPanel.addButton ("Apply", null,
            new ActionListener ()
            {
                public void actionPerformed (ActionEvent e)
                {
                    try
                    {
                        statusBar.clear ("bvf4");
                        BigValueFlags bvf = buildBigValueFlags ();
                        if (registers != null)
                            registers.checkBigValueFlags (bvf);
                        if (fileRegisters != null)
                            fileRegisters.checkRegisters (bvf);
                        putValuesToModel ();
                    }
                    catch (ValueException ex)
                    {
                        statusBar.showException (ex);
                    }
                }
            });

        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)
                {
                    boolean en = state.isStopped;
                    endianCheckbox.setEnabled (en);
                    wordRegCheckbox.setEnabled (en);
                    wordCountCheckbox.setEnabled (en);
                    setButtonsEnabled (en && hasUnappliedChanges ());
                }
            });

        // If settings get loaded from file, update the display.
        bigValueSettings.addValueListener (new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    getValuesFromModel ();
                }
            });

        if (registers != null)
            registers.addValueListener (statusBar.getClearListener ("bvf1"));
        if (fileRegisters != null)
            fileRegisters.addValueListener (statusBar.getClearListener ("bvf5"));

        getValuesFromModel ();
    }

    public JPanel getPanel ()
    {
        return outerPanel;
    }

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

    public String getName ()
    {
        return "32/64-bit Values";
    }

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

    public JButton getDefaultButton ()
    {
        return applyButton;
    }

    public String getToolTipText ()
    {
        return null;
    }

    @Override
    public void selected ()
    {
    }

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

    public boolean hasUnappliedChanges ()
    {
        boolean changed = false;
        BigValueFlags flags = bigValueSettings.getValue ();
        if (endianCheckbox.hasValueChanged (flags.getLittleEndian ()))
            changed = true;
        if (wordRegCheckbox.hasValueChanged (flags.getWordRegisters ()))
            changed = true;
        if (wordCountCheckbox.hasValueChanged (flags.getWordCount ()))
            changed = true;
        return changed;
    }

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

    private void setButtonsEnabled (boolean enabled)
    {
        Gui.setEnabled (applyButton, enabled);
        Gui.setEnabled (resetButton, enabled);
        fireStatusChanged ();
    }

    private void getValuesFromModel ()
    {
        statusBar.clear ("bvf2");
        BigValueFlags flags = bigValueSettings.getValue ();
        endianCheckbox.setValue (flags.getLittleEndian ());
        wordRegCheckbox.setValue (flags.getWordRegisters ());
        wordCountCheckbox.setValue (flags.getWordCount ());
        setButtonsEnabled (false);
    }

    private void putValuesToModel ()
    {
        bigValueSettings.setValue (buildBigValueFlags ());
        setButtonsEnabled (false);
    }

    private BigValueFlags buildBigValueFlags ()
    {
        return new BigValueFlags (
            endianCheckbox.getValue (),
            wordRegCheckbox.getValue (),
            wordCountCheckbox.getValue ());
    }

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

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

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


