
package uk.co.wingpath.modbusgui;

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

public class LogSettings
    implements Xml.Savable
{
    public static final int MAX_FILE_SIZE = 1024;

    private Variable<Reporter.Level> terminalLevel;
    private Variable<Reporter.Level> fileLevel;
    private Variable<Integer> fileSize;
    private String fileName;
    private Reporter.Level syslogLevel;
    private Reporter.Level windowsLevel;
    private final ValueEventSource listeners;
    private final boolean debugging;

    public LogSettings (boolean debugging)
    {
        this.debugging = debugging;
        terminalLevel = new SimpleVariable<Reporter.Level> (Reporter.Level.TRACE);
        fileLevel = new SimpleVariable<Reporter.Level> (Reporter.Level.NONE);
        fileSize = new SimpleVariable<Integer> (10);
        fileName = "";
        syslogLevel = Reporter.Level.NONE;
        windowsLevel = Reporter.Level.NONE;
        listeners = new ValueEventSource ();
    }

    public Variable<Reporter.Level> getTerminalLevel ()
    {
        return terminalLevel;
    }

    public Variable<Reporter.Level> getFileLevel ()
    {
        return fileLevel;
    }

    public Variable<Integer> getFileSize ()
    {
        return fileSize;
    }

    public String getFileName ()
    {
        return fileName;
    }

    public void setFileName (String fileName)
    {
        this.fileName = fileName;
    }

    public Reporter.Level getSyslogLevel ()
    {
        return syslogLevel;
    }

    public void setSyslogLevel (Reporter.Level syslogLevel)
    {
        this.syslogLevel = syslogLevel;
    }

    public Reporter.Level getWindowsLevel ()
    {
        return windowsLevel;
    }

    public void setWindowsLevel (Reporter.Level windowsLevel)
    {
        this.windowsLevel = windowsLevel;
    }

    public void valuesUpdated ()
    {
        listeners.fireValueChanged (this);
    }

    public void save (Xml.Saver saver)
        throws IOException
    {
        saver.saveValue ("terminallevel", terminalLevel.getValue ());
        saver.saveValue ("filelevel", fileLevel.getValue ());
        saver.saveValue ("filesize", fileSize.getValue ());
        saver.saveValue ("filename", fileName);
        if (syslogLevel != Reporter.Level.NONE)
            saver.saveValue ("sysloglevel", syslogLevel);
        if (windowsLevel != Reporter.Level.NONE)
            saver.saveValue ("windowslevel", windowsLevel);
    }

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

    private Reporter.Level convertLevel (String value)
        throws ValueException
    {
        Reporter.Level level;
        try
        {
            level = Reporter.Level.valueOf (value);
        }
        catch (IllegalArgumentException e)
        {
            // Backwards compatibilty: WARN used to be
            // WARNING.
            if (value.equals ("WARNING"))
            {
                level = Reporter.Level.WARN;
            }
            else
            {
                throw new ValueException (
                    value + ": Invalid value");
            }
        }
        if (!debugging && level == Reporter.Level.DEBUG)
            level = Reporter.Level.TRACE;
        return level;
    }

    private class XmlLoader
        extends Xml.AbstractLoader
    {
        @Override
        public Xml.Loader startChild (String tag)
        {
            if (tag.equalsIgnoreCase ("terminallevel"))
            {
                return new Xml.StringLoader (
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                            throws ValueException
                        {
                            terminalLevel.setValue (convertLevel (value));
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("filelevel"))
            {
                return new Xml.StringLoader (
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                            throws ValueException
                        {
                            fileLevel.setValue (convertLevel (value));
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("filesize"))
            {
                return new Xml.IntegerLoader (
                    0, MAX_FILE_SIZE,
                    new Xml.Receiver<Integer> ()
                    {
                        public void receive (Integer value)
                        {
                            fileSize.setValue (value);
                        }
                    });
            }

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

            if (tag.equalsIgnoreCase ("sysloglevel"))
            {
                return new Xml.StringLoader (
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                            throws ValueException
                        {
                            syslogLevel = convertLevel (value);
                        }
                    });
            }

            if (tag.equalsIgnoreCase ("windowslevel"))
            {
                return new Xml.StringLoader (
                    new Xml.Receiver<String> ()
                    {
                        public void receive (String value)
                            throws ValueException
                        {
                            windowsLevel = convertLevel (value);
                        }
                    });
            }

            return null;
        }

        @Override
        public void cleanup ()
        {
            if (fileName.equals (""))
                fileLevel.setValue (Reporter.Level.NONE);
            listeners.fireValueChanged (this);
        }
    }

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

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

