package be.iminds.ilabt.jfed.connectivity_tester;

import be.iminds.ilabt.jfed.fedmon.webapi.service.json.Proxy;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.Server;
import be.iminds.ilabt.jfed.lowlevel.ApiInfo;
import be.iminds.ilabt.jfed.lowlevel.GeniUser;
import be.iminds.ilabt.jfed.lowlevel.GeniUserProvider;
import be.iminds.ilabt.jfed.lowlevel.TestbedInfoSource;
import be.iminds.ilabt.jfed.lowlevel.connection.JFedConnection;
import be.iminds.ilabt.jfed.lowlevel.ssh_key_info.SshKeyInfo;
import be.iminds.ilabt.jfed.lowlevel.ssh_key_info.SshKeyInfoFactory;
import be.iminds.ilabt.jfed.lowlevel.stitching.VlanRange;
import be.iminds.ilabt.jfed.preferences.JFedGuiPreferences;

import javax.inject.Inject;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * User: twalcari
 * Date: 1/7/14
 * Time: 2:28 PM
 */
public class ProxyTestGenerator implements TestsGenerator {

    private static final String WALL2_URN = "urn:publicid:IDN+wall2.ilabt.iminds.be+authority+cm";
    private final GeniUserProvider geniUserProvider;
    private final TestbedInfoSource testbedInfoSource;
    private final ConnectivityTestFactory connectivityTestFactory;
    private final JFedGuiPreferences jFedPreferences;

    @Inject
    public ProxyTestGenerator(GeniUserProvider geniUserProvider, TestbedInfoSource testbedInfoSource, ConnectivityTestFactory connectivityTestFactory, JFedGuiPreferences jFedPreferences) {
        this.geniUserProvider = geniUserProvider;
        this.testbedInfoSource = testbedInfoSource;
        this.connectivityTestFactory = connectivityTestFactory;
        this.jFedPreferences = jFedPreferences;
    }


    @Override
    public Collection<ConnectivityTest> generateTests() {

        List<ConnectivityTest> tests = new ArrayList<>();

        List<Server> authorities = testbedInfoSource.getServers();

        for (Server auth : authorities) {
            if (auth.getTestbed() == null || auth.getTestbed().getProxies() == null)
                continue;
            for (Proxy proxyInfo : auth.getTestbed().getProxies()) {
                VlanRange portRange = new VlanRange(proxyInfo.getPortRange());
                Integer port = portRange.getFirst();

                //add test of proxy usage if there is a user logged in and this is his authority
                if (port != null && geniUserProvider != null &&
                        geniUserProvider.isUserLoggedIn() &&
                        Objects.equals(geniUserProvider.getLoggedInGeniUser().getUserAuthorityServer(), auth)) {
                    GeniUser user = geniUserProvider.getLoggedInGeniUser();
                    assert user != null;

                    String username = user.getUserUrn().getEncodedResourceName();

                    SshKeyInfo userSshKeyInfo = SshKeyInfoFactory.createGeniUserSshKeyInfo(user);

                    JFedConnection.SshProxyInfo conProxyInfo = new JFedConnection.SshProxyInfo(
                            proxyInfo.getHostname(),
                            port,
                            username,
                            userSshKeyInfo,
                            proxyInfo.getHostKey(),
                            true /*limitName*/);

                    //TODO handle if 1st port is not reachable, but others are (login and GetVersion test should pick another port in that case)
                    //test login on first port
                    SSHLoginTest proxyLoginTest = new SSHLoginTest(
                            proxyInfo.getHostname(), port,
                            conProxyInfo.getUsername() /*don't use username directly: SshProxyInfo constructor shortens it if needed*/,
                            userSshKeyInfo, //use proxy key!
                            null /*no proxy: this is a login to the proxy itself*/,
                            geniUserProvider,
                            jFedPreferences);
                    tests.add(proxyLoginTest);

                    URL amUrl = ApiInfo.findUrl(auth, ApiInfo.ApiName.GENI_AM, 3);
                    int version = 3;
                    if (amUrl == null && ApiInfo.findUrl(auth, ApiInfo.ApiName.GENI_AM, 2) != null) {
                        amUrl = ApiInfo.findUrl(auth, ApiInfo.ApiName.GENI_AM, 2);
                        version = 2;
                    }
                    //fall back to to wall2 AMv3
                    if (amUrl == null) {
                        auth =
                                testbedInfoSource.getByUrnExact(WALL2_URN);
                        if (auth != null) {
                            amUrl = ApiInfo.findUrl(auth, ApiInfo.ApiName.GENI_AM, 3);
                            version = 3;
                        }
                    }
                    if (amUrl != null) {
                        GetVersionTest getVersionTest =
                                connectivityTestFactory.createGetVersionTest(auth, conProxyInfo, version);
                        tests.add(getVersionTest);
                    }
                }

                //test maximum 10 ports for the same proxy
                int maxTests = 10;
                for (Integer curPort : portRange) {
                    if (maxTests-- <= 0)
                        break;


                    final HostAndPortTest proxyTest = new HostAndPortTest(proxyInfo.getHostname(), curPort,
                            "Proxy " + proxyInfo.getHostname() + ":" + curPort, "Proxy"/*category*/);

                    if (!tests.contains(proxyTest))
                        tests.add(proxyTest);
                }

            }
        }
        return tests;
    }

}
