package com.jscape.util.net.socket;

import com.jscape.util.Time;

import java.net.DatagramSocket;
import java.net.Socket;
import java.net.SocketException;

/**
 * @author Alex Usun
 */
public class SocketParameters {

    public final boolean reuseAddress;
    public final Integer receiveBufferSize;
    public final Integer sendBufferSize;
    public final Integer trafficClass;
    public final Boolean tcpNoDelay;
    public final Boolean keepAlive;
    public final Time lingerTime;
    public final Time soTimeout;

    public static SocketParameters defaultParameters() {
        return new SocketParameters(true, null, null, null, true, null, null, null);
    }

    public SocketParameters(boolean reuseAddress,
                            Integer receiveBufferSize,
                            Integer sendBufferSize,
                            Integer trafficClass,
                            Boolean tcpNoDelay,
                            Boolean keepAlive,
                            Time lingerTime,
                            Time soTimeout) {
        this.reuseAddress = reuseAddress;
        this.receiveBufferSize = receiveBufferSize;
        this.sendBufferSize = sendBufferSize;
        this.trafficClass = trafficClass;
        this.tcpNoDelay = tcpNoDelay;
        this.keepAlive = keepAlive;
        this.lingerTime = lingerTime;
        this.soTimeout = soTimeout;
    }

    public Socket applyTo(Socket socket)
            throws SocketException {
        if (this.reuseAddress) {
            socket.setReuseAddress(true);
        }

        if (this.receiveBufferSize != null) {
            socket.setReceiveBufferSize(this.receiveBufferSize);
        }

        if (this.sendBufferSize != null) {
            socket.setSendBufferSize(this.sendBufferSize);
        }

        if (this.trafficClass != null) {
            socket.setTrafficClass(this.trafficClass);
        }

        if (this.tcpNoDelay != null) {
            socket.setTcpNoDelay(this.tcpNoDelay);
        }

        if (this.keepAlive != null) {
            socket.setKeepAlive(this.keepAlive);
        }

        if (this.lingerTime != null) {
            socket.setSoLinger(true, (int) this.lingerTime.toSeconds());
        }

        if (this.soTimeout != null) {
            socket.setSoTimeout((int) this.soTimeout.toMillis());
        }

        return socket;
    }

    public DatagramSocket applyTo(DatagramSocket socket)
            throws SocketException {
        if (this.reuseAddress) {
            socket.setReuseAddress(true);
        }

        if (this.receiveBufferSize != null) {
            socket.setReceiveBufferSize(this.receiveBufferSize);
        }

        if (this.sendBufferSize != null) {
            socket.setSendBufferSize(this.sendBufferSize);
        }

        if (this.trafficClass != null) {
            socket.setTrafficClass(this.trafficClass);
        }

        if (this.soTimeout != null) {
            socket.setSoTimeout((int) this.soTimeout.toMillis());
        }

        return socket;
    }

    @Override
    public String toString() {
        return "SocketParameters {"
               + "reuseAddress=" + this.reuseAddress
               + ", receiveBufferSize=" + this.receiveBufferSize
               + ", sendBufferSize=" + this.sendBufferSize
               + ", trafficClass=" + this.trafficClass
               + ", tcpNoDelay=" + this.tcpNoDelay
               + ", keepAlive=" + this.keepAlive
               + ", lingerTime=" + this.lingerTime
               + ", soTimeout=" + this.soTimeout
               + '}';
    }
}
