
package uk.co.wingpath.modbusgui;

import java.io.*;
import java.lang.ref.*;
import uk.co.wingpath.event.*;
import uk.co.wingpath.xml.*;
import uk.co.wingpath.io.*;
import uk.co.wingpath.util.*;

public class SerialSettings
    implements Xml.Savable
{
    private static final String [] PARITY_TAGS = { "none", "odd", "even" };
    private static final String [] DATA_BITS_TAGS = { "7", "8" };
    private static final String [] STOP_BITS_TAGS = { "1", "2" };
    private static final String [] RTS_TAGS = { "high", "flow", "rs485" };

    private String portName;
    private int speed;
    private String parity;
    private int databits;
    private int stopbits;
    private String rts;
    private final ValueEventSource listeners;
    private WeakReference<SerialConnection> connection;

    public SerialSettings ()
    {
        listeners = new ValueEventSource ();
        portName = "";
        speed = 9600;
        parity = "none";
        databits = 8;
        stopbits = 1;
        rts = "high";
        connection = new WeakReference<SerialConnection> (null);
    }

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

    public String getPortName ()
    {
        return portName;
    }

    public void setPortName (String portName)
    {
        if (!portName.equals (this.portName))
        {
            this.portName = portName;
            // Caller should call fireValueChanged after setting all values
            // listeners.fireValueChanged (this);
        }
    }

    public int getSpeed ()
    {
        return speed;
    }

    public void setSpeed (int speed)
    {
        if (speed != this.speed)
        {
            this.speed = speed;
            // Caller should call fireValueChanged after setting all values
            // listeners.fireValueChanged (this);
        }
    }

    public int getDataBits ()
    {
        return databits;
    }

    public void setDataBits (int databits)
    {
        if (databits != this.databits)
        {
            this.databits = databits;
            // Caller should call fireValueChanged after setting all values
            // listeners.fireValueChanged (this);
        }
    }

    public int getStopBits ()
    {
        return stopbits;
    }

    public void setStopBits (int stopbits)
    {
        if (stopbits != this.stopbits)
        {
            this.stopbits = stopbits;
            // Caller should call fireValueChanged after setting all values
            // listeners.fireValueChanged (this);
        }
    }

    public String getParity ()
    {
        return parity;
    }

    public void setParity (String parity)
    {
        if (parity != this.parity)
        {
            this.parity = parity;
            // Caller should call fireValueChanged after setting all values
            // listeners.fireValueChanged (this);
        }
    }

    public String getRts ()
    {
        return rts;
    }

    public void setRts (String rts)
    {
        if (rts != this.rts)
        {
            this.rts = rts;
            // Caller should call fireValueChanged after setting all values
            // listeners.fireValueChanged (this);
        }
    }

    public SerialConnection createConnection (Reporter reporter)
        throws IOException
    {
        if (portName.equals (""))
            throw new HIOException ("I119", "No serial port specified");

        SerialConnection c = new SerialConnection (portName, reporter);
        c.setSerialPortParams (speed, databits, stopbits, parity);
        c.setRtsControl (rts);
        connection = new WeakReference<SerialConnection> (c);
        return c;
    }

    public void addValueListener (ValueListener l)
    {
        listeners.addListener (l);
    }

    public void removeValueListener (ValueListener l)
    {
        listeners.removeListener (l);
    }

    public void fireValueChanged ()
    {
        listeners.fireValueChanged (this);
        SerialConnection c = connection.get ();
        if (c != null)
        {
            try
            {
                c.setSerialPortParams (speed, databits, stopbits, parity);
                c.setRtsControl (rts);
            }
            catch (IOException e)
            {
            }
        }
    }

    public void save (Xml.Saver saver)
        throws IOException
    {
        saver.saveValue ("port", portName);
        saver.saveValue ("speed", speed);
        saver.saveValue ("parity", parity);
        saver.saveValue ("databits", databits);
        saver.saveValue ("stopbits", stopbits);
        saver.saveValue ("rts", rts);
    }

    public Xml.Loader getXmlLoader ()
    {
        return new XmlLoader ();
    }

    private class XmlLoader
        extends Xml.AbstractLoader
    {
        XmlLoader ()
        {
        }

        @Override
        public Xml.Loader startChild (String tag)
        {
            if (tag.equalsIgnoreCase ("port"))
            {
                return new Xml.StringLoader (
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                        {
                            portName = value;
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("speed"))
            {
                return new Xml.IntegerLoader (0, Integer.MAX_VALUE,
                    new Xml.Receiver<Integer> ()
                    {
                        public void receive (Integer value)
                        {
                            speed = value;
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("parity"))
            {
                return new Xml.StringLoader (
                    PARITY_TAGS,
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                        {
                            parity = value;
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("databits"))
            {
                return new Xml.StringLoader (
                    DATA_BITS_TAGS,
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                        {
                            databits = Integer.parseInt (value);
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("stopbits"))
            {
                return new Xml.StringLoader (
                    STOP_BITS_TAGS,
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                        {
                            stopbits = Integer.parseInt (value);
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("rts"))
            {
                return new Xml.StringLoader (
                    RTS_TAGS,
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                        {
                            rts = value;
                        }
                    });
            }

            return null;
        }

        @Override
        public void cleanup ()
        {
            fireValueChanged ();
        }
    }
}

