package com.jscape.inet.util;

import javax.net.ServerSocketFactory;
import java.net.InetSocketAddress;
import java.net.ServerSocket;

/**
 * Creates a ServerSocket which is going to listen a port from a FTP Server. The
 * port number available has to be between the port range of the dataPortStart
 * and the dataPortEnd arguments
 * <p/>
 * This class is used when the user is connecting to a FTP Server in Active
 * mode.
 *
 * @author Alvaro
 */
public class ServerSocketUtil {

    /**
     * Creates a server socket which is going to listen a port between the port
     * range from <code>dataPortStart</code> to <code>dataPortEnd<code>
     *
     * @param range data port range
     *
     * @return Returns a server socket which is listing a port between the port range
     *
     * @throws Exception Throws a exception if was not found a port available
     */
    public static ServerSocket createServerSocket(PortRange range)
            throws Exception {
        ServerSocket server = new ServerSocket();
        server.setReuseAddress(true);

        int initialPort = range.next();
        int port = initialPort;
        Exception error;

        do {
            try {
                server.bind(new InetSocketAddress(port));
                server.setReuseAddress(true);
                
                return server;
            } catch (Exception e) {
                error = e;
                port = range.next();
            }
        } while (port != initialPort);

        throw error;
    }


    /**
     * Creates a server socket which is going to listen a port between the port
     * range from <code>dataPortStart</code> to <code>dataPortEnd<code>.
     * The method uses a ServerSocketFatory <code>factory</code> to create the server
     * socket
     *
     * @param factory       The factory used to create a ServerSocket
     * @param range data port range
     *
     * @return Return a server socket which is listing a port between the port range
     *
     * @throws Exception Throws a exception if was not found a port available
     */
    public static ServerSocket createServerSocket(ServerSocketFactory factory, PortRange range)
            throws Exception {
        int initialPort = range.next();
        int port = initialPort;
        Exception error;

        do {
            try {
                ServerSocket server = factory.createServerSocket(port, 0);
                server.setReuseAddress(true);

                return server;
            } catch (Exception e) {
                error = e;
                port = range.next();
            }
        } while (port != initialPort);

        throw error;
    }

    private ServerSocketUtil() {
    }

    public static class PortRange {

        public final int start;
        public final int end;
        private int index;

        public PortRange(int start, int end) {
            this.start = start;
            this.end = end;
            this.index = this.start;
        }

        public int next() {
            int ret = this.index++;

            if (this.index > this.end) {
                this.index = this.start;
            }

            return ret;
        }

        @Override
        public String toString() {
            return "PortRange {"
                   + "start=" + this.start
                   + ", end=" + this.end
                   + ", index=" + this.index
                   + '}';
        }
    }
}
