package net.i2p.data.i2cp;

/*
 * free (adj.): unencumbered; not under the control of others
 * Written by jrandom in 2003 and released into the public domain 
 * with no warranty of any kind, either expressed or implied.  
 * It probably won't make your computer catch on fire, or eat 
 * your children, but it might.  Use at your own risk.
 *
 */

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;

import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.util.ByteArrayStream;
import net.i2p.util.OrderedProperties;

/**
 * Request the other side to send us what they think the current time is.
 * Only supported from client to router.
 *
 * Since 0.8.7, optionally include a version string.
 * Since 0.9.11, optionally include options.
 */
public class GetDateMessage extends I2CPMessageImpl {
    public final static int MESSAGE_TYPE = 32;
    private String _version;
    private Properties _options;

    public GetDateMessage() {
        super();
    }

    /**
     *  @param version the client's version String to be sent to the router; may be null
     *  @since 0.8.7
     */
    public GetDateMessage(String version) {
        super();
        _version = version;
    }

    /**
     *  Defaults in GetDateMessage options are, in general, NOT honored.
     *  Defaults are not serialized out-of-JVM, and the router does not recognize defaults in-JVM.
     *  Client side must promote defaults to the primary map.
     *
     *  @param version the client's version String to be sent to the router; may be null;
     *                 must be non-null if options is non-null and non-empty.
     *  @param options Client options to be sent to the router; primarily for authentication; may be null;
     *                 keys and values 255 bytes (not chars) max each
     *  @since 0.9.11
     */
    public GetDateMessage(String version, Properties options) {
        super();
        if (version == null && options != null && !options.isEmpty())
            throw new IllegalArgumentException();
        _version = version;
        _options = options;
    }

    /**
     *  @return may be null
     *  @since 0.8.7
     */
    public String getVersion() {
        return _version;
    }

    /**
     *  Retrieve any configuration options for the connection.
     *  Primarily for authentication.
     *
     *  @return may be null
     *  @since 0.9.11
     */
    public Properties getOptions() {
        return _options;
    }

    @Override
    protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException {
        if (size > 0) {
            try {
                _version = DataHelper.readString(in);
                if (size > 1 + _version.length())  // assume ascii
                    _options = DataHelper.readProperties(in);
            } catch (DataFormatException dfe) {
                throw new I2CPMessageException("Bad version string", dfe);
            }
        }
    }

    @Override
    protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
        if (_version == null)
            return new byte[0];
        ByteArrayStream os = new ByteArrayStream(_options != null ? 128 : (1 + 6));
        try {
            DataHelper.writeString(os, _version);
            if (_options != null && !_options.isEmpty())
                DataHelper.writeProperties(os, _options, true);  // UTF-8
        } catch (DataFormatException dfe) {
            throw new I2CPMessageException("Error writing out the message data", dfe);
        }
        return os.toByteArray();
    }

    public int getType() {
        return MESSAGE_TYPE;
    }

    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append("[GetDateMessage]");
        buf.append("\n\tVersion: ").append(_version);
        if (_options != null && !_options.isEmpty()) {
            buf.append("\n\tOptions: #: ").append(_options.size());
            Properties sorted = new OrderedProperties();
            sorted.putAll(_options);
            for (Map.Entry<Object, Object> e : sorted.entrySet()) {
                String key = (String) e.getKey();
                String val = (String) e.getValue();
                buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
            }
        }
        return buf.toString();
    }
}
