package be.iminds.ilabt.jfed.lowlevel.authority;

import be.iminds.ilabt.jfed.lowlevel.TestbedInfoSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
   Example https://www.emulab.net/protogeni/authorities/salist.txt:

   urn:publicid:IDN+uml.emulab.net+authority+sa https://boss.uml.emulab.net/protogeni/xmlrpc/sa
   urn:publicid:IDN+emulab.larc.usp.br+authority+sa https://www.emulab.larc.usp.br:12369/protogeni/xmlrpc/sa
   urn:publicid:IDN+emulab.net+authority+sa https://www.emulab.net:12369/protogeni/xmlrpc/sa
....
   urn:publicid:IDN+wall3.test.ibbt.be+authority+sa https://www.wall3.test.ibbt.be:12369/protogeni/xmlrpc/sa
 */

/**
 * Read jFed compatible XML representation of authorities
 * <p/>
 * URL:  https://flsmonitor.fed4fire.eu/testbeds.xml
 */
public class Fed4FireAuthorityList {
    public static class OfflineException extends Exception {
        public OfflineException() {
        }

        public OfflineException(String message) {
            super(message);
        }

        public OfflineException(String message, Throwable cause) {
            super(message, cause);
        }

        public OfflineException(Throwable cause) {
            super(cause);
        }

        public OfflineException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
        }
    }

    private static final Logger LOG = LoggerFactory.getLogger(Fed4FireAuthorityList.class);

    private static final String FED4FIRE_TESTBED_DIRECTORY_URL = "https://flsmonitor.fed4fire.eu/testbeds.xml";

    private static final String FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_OLD = "-----BEGIN CERTIFICATE-----\n" +
            "MIICwjCCAaqgAwIBAgIJAOE0tjy49mo/MA0GCSqGSIb3DQEBBQUAMBkxFzAVBgNV\n" +
            "BAMTDmFydGVtaXM2NS50ZXN0MB4XDTEzMDUzMTEzNDU1NFoXDTIzMDUyOTEzNDU1\n" +
            "NFowGTEXMBUGA1UEAxMOYXJ0ZW1pczY1LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUA\n" +
            "A4IBDwAwggEKAoIBAQCqnqUQyHM6cFSe0pngvKMWRrHyJg9rpz1yH7bPeUvyQ+QR\n" +
            "67XHw0eO8tBRzdz0k2JiCdTHBL/zayD9TWdg03iFZ6ctRmSu/zqS7anEpGeFfRoW\n" +
            "Ofrs8m+cwG4VR2p9IUOXEVFAhdptr0BI4zWxrmuj7QK2Xav+2sOdZ3XrZSkT462O\n" +
            "FhunuITWS7SBjrH09cPqrjSDHA4pmdSTziRSS+DR+Nr1zW7UVE0Iz7QWk216kugy\n" +
            "x+o4uVWMrOwKM6GK+EiBsV3ov0lfA56JRsCk93l2cuzbelsr3vRbe3h5e0IPHKyv\n" +
            "LQlBMbzOZiuNPCzxPNk9W7ehSB14GfUVsjwUuSibAgMBAAGjDTALMAkGA1UdEwQC\n" +
            "MAAwDQYJKoZIhvcNAQEFBQADggEBAIx9t64rhBMcpGuB8oQqvIOK4Zka3x5phTXn\n" +
            "FBhgQdSYWU1BFGGZ1u69aD9QMgT3+gNNpvybEpsHwPBxjXhIkQgz7Zrm0GvGLyOr\n" +
            "7/xDgMbnvDae9/2VycfIXzSVt3KJIlC0gHJ3uyDXHgpYkK62XnDZa9kszJPQGGL4\n" +
            "4QmHniH7ZR23lnWCpCijerueg+bjoZuMLW8kJikstAeJ6Wtqc6PeHp1FU7CnFBkM\n" +
            "sWOwDjISeCIK0YRGmXH7VHgPueWuiQq9XMvO2r321CwRnYTtja/zAbB6hAGrfjB0\n" +
            "mQl6oeKERad87dSPo07CJKep9/IbO8Db9BxXaNEjz/jN+vpIVJI=\n" +
            "-----END CERTIFICATE-----";

    public static final String FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n" +
            "MIIEejCCA2KgAwIBAgIRAMF/gNNjf5XZQCAyxIk1wqYwDQYJKoZIhvcNAQEFBQAw\n" +
            "NjELMAkGA1UEBhMCTkwxDzANBgNVBAoTBlRFUkVOQTEWMBQGA1UEAxMNVEVSRU5B\n" +
            "IFNTTCBDQTAeFw0xMzA2MTkwMDAwMDBaFw0xNjA2MTgyMzU5NTlaMEQxITAfBgNV\n" +
            "BAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEfMB0GA1UEAxMWZmxzbW9uaXRv\n" +
            "ci5mZWQ0ZmlyZS5ldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFC\n" +
            "gP9yBJYFC1voSKm2bC/afP5yvlhltKuZd9/+u2zQm6AxugTaFQ/KWL+7MWp3NM5V\n" +
            "JC4zVVrONpoyq+k+0B6geCSfpoQjAvkE0DUz6M+QmltXjPxrKkOADY0O9jYh0/Ny\n" +
            "gV5k6luk2O0GJ0Vs3iXbwGamrNfr1rSEVxhBzXZOoBGfJQNnm2EJ5B6J/LAQpClg\n" +
            "a3fK/rvn7bM5fJOODNcWVkEheuKPUAC5wSOcxQJYb0V/wxokErFT06AYkVvoACmE\n" +
            "k9pdLt8NV73tI4gOJebkIXAT+bRifzW55khVvVC79BptTuiR5sC/pCqJBD9OIbbR\n" +
            "mu1/Qkl/m7pJYS1GfSECAwEAAaOCAXMwggFvMB8GA1UdIwQYMBaAFAy9k2gM896r\n" +
            "o0lrKzdXR+qQ47ntMB0GA1UdDgQWBBQkOXnA6GsTQ5GnRCExm18y1VJVZjAOBgNV\n" +
            "HQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI\n" +
            "KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICHTAIBgZngQwBAgEwOgYD\n" +
            "VR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC50Y3MudGVyZW5hLm9yZy9URVJFTkFT\n" +
            "U0xDQS5jcmwwbQYIKwYBBQUHAQEEYTBfMDUGCCsGAQUFBzAChilodHRwOi8vY3J0\n" +
            "LnRjcy50ZXJlbmEub3JnL1RFUkVOQVNTTENBLmNydDAmBggrBgEFBQcwAYYaaHR0\n" +
            "cDovL29jc3AudGNzLnRlcmVuYS5vcmcwIQYDVR0RBBowGIIWZmxzbW9uaXRvci5m\n" +
            "ZWQ0ZmlyZS5ldTANBgkqhkiG9w0BAQUFAAOCAQEAsgQMjszwaEwYVnmO9K2Uv7X/\n" +
            "zV61G9DLDWNh9SqUmModrk9gPOW25h7o5pfFw71BlGnwlc+OFGh4C+d8oXgvcm0j\n" +
            "A1aQXU7qoxU92Pj5U5rTWX0AC5QATrjWUHeQoszkcTbujU9ue6fcNcq/tzI6ncoM\n" +
            "XEAvG+luno1oBfPLxhDYWlaZoLhzKZvSwvZPkSc8p4NyYpZ3ConOcBkPZEhP4mMp\n" +
            "3y3LYNCOE7zDfaR9nSWlrQRUQNuDzSls2DoNrpcNmRMzj6nh6ILB0wMG/R9KhGCS\n" +
            "rp+hUYnyFiQntjDKVju1WKshjzMZlRcXexd18k3QR4a0dwVrxq3kBH5faT+71w==\n" +
            "-----END CERTIFICATE-----";

    private static final String FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_ALLOWED_ALIAS_OLD = "artemis65.test";
    public static final String FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_ALLOWED_ALIAS = "flsmonitor.fed4fire.eu";

    private Fed4FireAuthorityList() {
    }

    /* returns whether successful or not */
    public static boolean load(TestbedInfoSource testbedInfoSource) throws OfflineException {
        return load(testbedInfoSource, FED4FIRE_TESTBED_DIRECTORY_URL);
    }
    public static boolean load(TestbedInfoSource testbedInfoSource, String testbedXmlUrl) throws OfflineException {
        throw new RuntimeException("not yet reimplemented");
//        HttpParams params = new BasicHttpParams();
//        params.setParameter(CoreConnectionPNames.SO_TIMEOUT, 5000); //read timeout in ms (default: 0 = infinite)
//        params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000); //connection timeout in ms (default: 0 = infinite)
//
//        DefaultHttpClient httpClient = new DefaultHttpClient(params);
//        X509Certificate cert = KeyUtil.pemToX509Certificate(FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE);
//        X509Certificate certOld = KeyUtil.pemToX509Certificate(FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_OLD);
//        KeyStore trustStore = null;
//        try {
//            final URL serverUrl = new URL(testbedXmlUrl);
//
//            //start from empty
////            trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
////            trustStore.load(null, "any_pass".toCharArray());
//
//            //start from system trust store
//            trustStore = new JFedTrustStore().getTrustStore();
//
//            trustStore.setCertificateEntry("singleCert", cert);
//
//            trustStore.setCertificateEntry("singleCertOld", certOld);
//
//            String algo = SSLSocketFactory.TLS;
//            java.security.SecureRandom random = new SecureRandom();
//            org.apache.http.conn.ssl.X509HostnameVerifier hostnameVerifier =
//                    new org.apache.http.conn.ssl.AbstractVerifier() {
//                        private BrowserCompatHostnameVerifier base = new BrowserCompatHostnameVerifier();
//
//                        /**
//                         * @param host the hostname of the url to check.
//                         * @param cns the CN's of the certificate
//                         * @param subjectAlts the aliases fot the CN's that the certificate allows
//                         * @throws javax.net.ssl.SSLException
//                         */
//                        public final void verify(java.lang.String host, String[] cns, String[] subjectAlts) throws javax.net.ssl.SSLException {
//                            List<String> modifiedSubjectAlts = new ArrayList<String>();
//                            if (subjectAlts != null)
//                                for (String subjectAlt : subjectAlts)
//                                    modifiedSubjectAlts.add(subjectAlt);
//                            List<String> modifiedCns = new ArrayList<String>();
//                            if (cns != null)
//                                for (String cn : cns)
//                                    modifiedCns.add(cn);
//
//                            //force add of host itself, this makes any certificate we have stored match
//                            if (modifiedCns.contains(FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_ALLOWED_ALIAS) ||
//                                    modifiedCns.contains(FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_ALLOWED_ALIAS_OLD) ||
//                                    modifiedSubjectAlts.contains(FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_ALLOWED_ALIAS) ||
//                                    modifiedSubjectAlts.contains(FED4FIRE_TESTBED_DIRECTORY_SELFSIGNED_CERTIFICATE_ALLOWED_ALIAS_OLD)
//                                    ) {
//                                modifiedSubjectAlts.add(serverUrl.getHost());
//                            }
//                            String[] newSubjectAlts = new String[modifiedSubjectAlts.size()];
//                            for (int i = 0; i < modifiedSubjectAlts.size(); i++)
//                                newSubjectAlts[i] = modifiedSubjectAlts.get(i);
//                            base.verify(host, cns, newSubjectAlts);
//                        }
//                    };
//            SSLSocketFactory socketFactory =
//                    new SSLSocketFactory(algo, null, null, trustStore, random, hostnameVerifier);
//            Scheme sch1 = new Scheme("https", 443, socketFactory); //port is the default port for the given protocol
//            httpClient.getConnectionManager().getSchemeRegistry().register(sch1);
//        } catch (Exception e) {
//            trustStore = null;
//            LOG.error("Could not create httpClient for Fed4FireAuthorityList: " + e, e);
//            throw new RuntimeException("Could not create httpClient for Fed4FireAuthorityList: " + e, e);
////            return false;
//        }
//
//
//        try {
//            URL startUrl = new URL(testbedXmlUrl);
//            HttpGet httpget = new HttpGet(startUrl.toExternalForm());
//            HttpResponse response = httpClient.execute(httpget);
//
//            if (response.getStatusLine() == null)
//                throw new RuntimeException("Error getting url \"" + testbedXmlUrl + "\" => " + response);
//            if (response.getStatusLine().getStatusCode() != 200)
//                throw new RuntimeException("Error getting url \"" + testbedXmlUrl + "\" (" + response.getStatusLine().getStatusCode() + ") => " + response.getStatusLine() + " => " + response);
//
//            HttpEntity entity = response.getEntity();
//            StoredTestbedInfo.LoadResult loadResult =  StoredTestbedInfo.load(entity.getContent(), testbedInfoSource);
//
//            for (String extraFile : loadResult.getExtraFiles()) {
//                URL url = new URL(startUrl, extraFile);
//                HttpGet httpget2 = new HttpGet(url.toURI());
//                LOG.trace("Loading extra file referenced from testbeds.xml: "+url.toExternalForm());
//                HttpResponse response2 = httpClient.execute(httpget2);
//
//                if (response2.getStatusLine() == null)
//                    throw new RuntimeException("Error getting url \"" + url + "\" => " + response2);
//                if (response2.getStatusLine().getStatusCode() != 200)
//                    throw new RuntimeException("Error getting url \"" + url + "\" (" + response2.getStatusLine().getStatusCode() + ") => " + response2.getStatusLine() + " => " + response2);
//
//                HttpEntity entity2 = response2.getEntity();
//                StoredTestbedInfo.LoadResult loadResult2 =  StoredTestbedInfo.load(entity2.getContent(), testbedInfoSource);
//                if (!loadResult2.isSuccess())
//                    loadResult = loadResult2;
//                if (!loadResult2.getExtraFiles().isEmpty())
//                    LOG.warn("Recursive extra files not supported (see "+url.toExternalForm()+")");
//            }
//
//            //TODO: this does not exist anymore:  testbedInfoSource.fireChange();
//            return loadResult.isSuccess();
//        } catch (javax.net.ssl.SSLPeerUnverifiedException ex) {
//            LOG.error("Fed4FireAuthorityList ERROR: SSLPeerUnverifiedException, The server certificate could not be verified.", ex);
//            return false;
//        } catch (ClientProtocolException e) {
//            LOG.error("Fed4FireAuthorityList ClientProtocolException: " + e.getMessage(), e);
//            return false;
//        } catch (HttpHostConnectException e) {
//            LOG.error("Fed4FireAuthorityList HttpHostConnectException: " + e.getMessage(), e);
//            throw new OfflineException(e);
//            //return false;
//        } catch (UnknownHostException e) {
//            LOG.error("Fed4FireAuthorityList UnknownHostException: " + e.getMessage(), e);
//            throw new OfflineException(e);
//            //return false;
//        } catch (ConnectException e) {
//            LOG.error("Fed4FireAuthorityList ConnectException: " + e.getMessage(), e);
//            throw new OfflineException(e);
//            //return false;
//        } catch (SocketException e) {
//            LOG.error("Fed4FireAuthorityList SocketException: " + e.getMessage(), e);
//            return false;
//        } catch (IOException e) {
//            LOG.error("Fed4FireAuthorityList IOException: " + e.getMessage(), e);
//            return false;
//        } catch (URISyntaxException e) {
//            LOG.error("Fed4FireAuthorityList URISyntaxException: " + e.getMessage(), e);
//            return false;
//        }
    }
}
