package be.iminds.ilabt.jfed.util;

import be.iminds.ilabt.jfed.lowlevel.connection.JFedConnection;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.protocol.HttpContext;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketImplFactory;

/**
 * SshProxyHelper:
 * uses some deprecated classes -> SSH proxy support is not an important feature, so not important if it breaks.
 */
public class SshServerProxyHelper {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(SshServerProxyHelper.class);

    private static class SshProxySocket extends Socket {
        public SshProxySocket(SocketImplFactory sshHSocketImplFactory) throws IOException {
            super(sshHSocketImplFactory.createSocketImpl());
            LOG.debug("Creating wrapping SshProxySocket");
        }
    }

    public static class SslOverSshProxySocketFactory extends SSLConnectionSocketFactory {
        private JFedConnection.SshProxyInfo sshProxyInfo;

        protected final String forcedCreateSocketHostname;
        protected final Integer forcedCreateSocketPort;

        public SslOverSshProxySocketFactory(SSLContext sslContext,
                                            HostnameVerifier hostnameVerifier,
                                            JFedConnection.SshProxyInfo sshProxyInfo,
                                            String forcedCreateSocketHostname,
                                            Integer forcedCreateSocketPort) {
            super(sslContext, hostnameVerifier);
            this.sshProxyInfo = sshProxyInfo;
            this.forcedCreateSocketHostname = forcedCreateSocketHostname;
            this.forcedCreateSocketPort = forcedCreateSocketPort;
        }

        public SslOverSshProxySocketFactory(SSLContext sslContext,
                                            HostnameVerifier hostnameVerifier,
                                            JFedConnection.SshProxyInfo sshProxyInfo) {
            this(sslContext, hostnameVerifier, sshProxyInfo, null, null);
        }


        @Override
        public Socket createSocket(HttpContext context) throws IOException {
            Socket socket;
            try {
                assert sshProxyInfo != null;

                SshProxySocketImplFactory sshHSocketImplFactory =
                        SshProxySocketImplFactory.getFactory(sshProxyInfo, forcedCreateSocketHostname, forcedCreateSocketPort);
                assert sshHSocketImplFactory != null;

                socket = new SshProxySocket(sshHSocketImplFactory);
            } catch (IOException e) {
                throw new RuntimeException("Error while creating SshProxySocket", e);
            }

            return socket;
        }
    }

    public static class PlainHttpOverSshProxySocketFactory extends PlainConnectionSocketFactory {
        private final JFedConnection.SshProxyInfo sshProxyInfo;
        protected final String forcedCreateSocketHostname;
        protected final Integer forcedCreateSocketPort;

        public PlainHttpOverSshProxySocketFactory(JFedConnection.SshProxyInfo sshProxyInfo) {
            this(sshProxyInfo, null, null);
        }

        public PlainHttpOverSshProxySocketFactory(JFedConnection.SshProxyInfo sshProxyInfo, String forcedCreateSocketHostname, Integer forcedCreateSocketPort) {
            super();
            this.sshProxyInfo = sshProxyInfo;
            this.forcedCreateSocketHostname = forcedCreateSocketHostname;
            this.forcedCreateSocketPort = forcedCreateSocketPort;
        }

        @Override
        public Socket createSocket(final HttpContext context) {
            Socket socket;
            try {
                SshProxySocketImplFactory sshHSocketImplFactory =
                        SshProxySocketImplFactory.getFactory(sshProxyInfo, forcedCreateSocketHostname, forcedCreateSocketPort);

                socket = new SshProxySocket(sshHSocketImplFactory);
            } catch (IOException e) {
                throw new RuntimeException("Error while creating SshProxySocket", e);
            }

            return socket;
        }
    }

}
