#region Header

/*
 * Copyright (c) eHealth
 */

#endregion Header

/**
 * IntegrationTest for Registration Authority
 */
namespace be.fgov.ehealth.technicalconnector.ra
{


	using be.ehealth.technicalconnector.config;
	using be.ehealth.technicalconnector.utils;

	using java.util;
	using java.lang;
	using org.joda.time;

	using NUnit.Framework;
	
	using be.ehealth.technicalconnector.service.sts.security;
	using be.ehealth.technicalconnector.service.sts.security.impl;
	using be.fgov.ehealth.technicalconnector.ra.builders;
	using be.fgov.ehealth.technicalconnector.ra.domain;
	using be.fgov.ehealth.technicalconnector.ra.enumaration;
	using be.fgov.ehealth.technicalconnector.ra.service;
	using be.fgov.ehealth.technicalconnector.ra.utils;
	using be.fgov.ehealth.technicalconnector.ra.exceptions;
    using be.fgov.ehealth.certra.core.v2;
    using be.fgov.ehealth.certra.protocol.v2;
    using be.fgov.ehealth.technicalconnector.tests.utils.net;
    using be.fgov.ehealth.technicalconnector.tests.utils;
    using java.net;


	using java.security;
	using java.security.cert;
	

	[TestFixture]
	public class RaWalkThroughIntegrationTest
	{
		
		private static string KEYSTORE_LOCATION = ".\\P12\\acc\\";
	
        
        [Test]
        public void getActorQualities() {   
            AuthenticationCertificateRegistrationService certRA = ServiceFactory.getAuthenticationCertificateRegistrationService();
            
            try {
            	ActorQualities actorQualities = (ActorQualities) certRA.getActorQualities().getResult();
                Assert.NotNull(actorQualities);
            } catch (RaException e) {
                ArrayList errorCodes = (ArrayList) e.getErrorCodes();
                Assert.Fail(errorCodes.toString());
            }
        }
        
        
        [Test]
        public void listOrganization() {
			AuthenticationCertificateRegistrationService certRA = ServiceFactory.getAuthenticationCertificateRegistrationService();
    
			try {
	            GetGenericOrganizationTypesResponse response = (GetGenericOrganizationTypesResponse) certRA.getOrganizationList().getResult();
	            Assert.NotNull(response.getOrganizationTypes());
            } catch (RaException e) {
                ArrayList errorCodes = (ArrayList) e.getErrorCodes();
                Assert.Fail(errorCodes.toString());
            }
        }
    
        [Test]
        public void listApplicationIds() {
			AuthenticationCertificateRegistrationService certRA = ServiceFactory.getAuthenticationCertificateRegistrationService();
            Organization organization = new Organization("0809394427", IdentifierType.CBE, "EHP");
            
            try {
	            java.util.List applicationIdList = (java.util.List) certRA.getApplicationIdList(organization).getResult();
	            Assert.NotNull(applicationIdList);
             } catch (RaException e) {
                ArrayList errorCodes = (ArrayList) e.getErrorCodes();
                Assert.Fail(errorCodes.toString());
            }
        }
    
        [Test]
        public void walkEID() {      
            try {
                KeyPair authenticationKeyPair = CertificateUtils.generateKeyPair();
    
                // Generate contract
                ContractRequest generateContractRequest = BuilderFactory.newContractRequestBuilder().create()
                        .withEid()
                        .withContact(new ContactData(get("test.ra.private.phone"), get("test.ra.private.mail")))
                        .build();
                GeneratedContract generatedContract = (GeneratedContract) ServiceFactory.getAuthenticationCertificateRegistrationService().generateContract(generateContractRequest).getResult();
                
                // Contract must be viewed
                generatedContract.setContractViewed(true);
                
                walk(new NewCertificateContract(generatedContract, authenticationKeyPair, Arrays.asList(UsageType.TIME_STAMPING)),
                     authenticationKeyPair, new DistinguishedName());
            } catch (RaException e) {
                ArrayList errorCodes = (ArrayList) e.getErrorCodes();
                Assert.Fail(errorCodes.toString());
            }
        }
    
        [Test]
        public void walkOrganization() {    
            KeyPair authenticationKeyPair = CertificateUtils.generateKeyPair();
    
    
            // Generate contract
            string appplicationId = UUID.randomUUID().toString().Replace("-", "").Substring(0, 30);
            ContractRequest generateContractRequest = BuilderFactory.newContractRequestBuilder().create()
                    .forOrganization().withId(get("test.ra.organization.id"), IdentifierType.NIHII_LABO)
                    .withName(get("test.ra.organization.name"))
                    .withApplicationId(UUID.randomUUID().toString().Replace("-", "").Substring(0, 30))
                    .forContact()
                    .withPrivatePhone(get("test.ra.private.phone"))
                    .withPrivateEmail(get("test.ra.private.mail"))
                    .withGeneralPhone(get("test.ra.general.phone"))
                    .withGeneralEmail(get("test.ra.general.mail"))
                    .build();
    
            GeneratedContract generatedContract = (GeneratedContract) ServiceFactory.getAuthenticationCertificateRegistrationService().generateContract(generateContractRequest).getResult();

            // Contract must be viewed
            generatedContract.setContractViewed(true);
            
            // this dn object is just for the purpose of conveniently create the keystore filename used for this test.
            DistinguishedName distinguishedName = new DistinguishedName(new Organization(get("test.ra.organization.id"),  IdentifierType.NIHII_LABO, get("test.ra.organization.name")), appplicationId);
            walk(new NewCertificateContract(generatedContract, authenticationKeyPair, Arrays.asList(UsageType.TIME_STAMPING)),
                 authenticationKeyPair, distinguishedName);
        }
        
        [Test]
        public void walkOrganizationWithoutApplicationId() {    
            KeyPair authenticationKeyPair = CertificateUtils.generateKeyPair();
    
    
            // Generate contract
            string appplicationId = UUID.randomUUID().toString().Replace("-", "").Substring(0, 30);
            ContractRequest generateContractRequest = BuilderFactory.newContractRequestBuilder().create()
                    .forOrganization().withId(get("test.ra.organization.id"), IdentifierType.NIHII_PHARMACY)
                    .withName(get("test.ra.organization.name"))
                    .withApplicationId(UUID.randomUUID().toString().Replace("-", "").Substring(0, 30))
                    .withContact(new ContactData(get("test.ra.private.phone"), get("test.ra.private.mail")))
                    .build();
    
            GeneratedContract generatedContract = (GeneratedContract) ServiceFactory.getAuthenticationCertificateRegistrationService().generateContract(generateContractRequest).getResult();

            // Contract must be viewed
            generatedContract.setContractViewed(true);
            
            // this dn object is just for the purpose of conveniently create the keystore filename used for this test.
            DistinguishedName distinguishedName = new DistinguishedName(new Organization(get("test.ra.organization.id"),  IdentifierType.NIHII_LABO, get("test.ra.organization.name")), appplicationId);
            walk(new NewCertificateContract(generatedContract, authenticationKeyPair, Arrays.asList(UsageType.TIME_STAMPING)),
                 authenticationKeyPair, distinguishedName);
        }        
    
        [Test]
        public void replace() {

                    
            try {
        		ConfigFactory.getConfigValidator().getConfig().setProperty("KEYSTORE_DIR", ".\\P12\\acc\\");
                AuthenticationCertificateRegistrationService certRA = ServiceFactory.getAuthenticationCertificateRegistrationService();
                Credential credential = new KeyStoreCredential(
TestPropertiesNetLoader.getProperties("be.ehealth.technicalconnector.test.properties",".net").getProperty("test.keystore.location"), TestPropertiesNetLoader.getProperties("be.ehealth.technicalconnector.test.properties",".net").getProperty("test.keystore.alias") , TestPropertiesNetLoader.getProperties("be.ehealth.technicalconnector.test.properties",".net").getProperty("test.keystore.password"));
                CertificateInfoType certificateInfoType = (CertificateInfoType) certRA.getCertificateInfoForAuthenticationCertificate(credential).getResult();
                if (certificateInfoType.isReplaceable()) {
                    walkEID();
                    EncryptionTokenRegistrationService etkRA = ServiceFactory.getEncryptionTokenRegistrationService();
                    etkRA.activateToken(credential);
                }
            } catch (RaException e) {
                ArrayList errorCodes = (ArrayList) e.getErrorCodes();
                Assert.Fail(errorCodes.toString());
            }
    
        }
    
        [Test]
        public void revoke() {             
            try {
                AuthenticationCertificateRegistrationService certRA = ServiceFactory.getAuthenticationCertificateRegistrationService();
                java.util.List certificateInfoTypes = (java.util.List) certRA.getCertificateInfoForCitizen().getResult();
                CertificateInfoType toRevoke = null;
                for (int i =0; i<certificateInfoTypes.size(); i++) {
                	CertificateInfoType certificateInfo = (CertificateInfoType) certificateInfoTypes.get(i);
                	if (certificateInfo.isRevocable()) {
                		toRevoke = certificateInfo;
                		break;
                	}
                }
                if (toRevoke != null) {
                    RevocationContractRequest revocationContractRequest = BuilderFactory.newRevokeRequestBuilder()
                            .create()
                            .withPublicKeyIdentifier(toRevoke.getPublicKeyIdentifier())
                            .withRevocationReasonType(RevocationReasonType.KEY_COMPROMISE)
                            .build();
                    GeneratedRevocationContract generatedRevocationContract = (GeneratedRevocationContract) certRA.generateRevocationContract(revocationContractRequest).getResult();
                    generatedRevocationContract.setContractViewed(true);
                    certRA.revokeCertificate(new RevocationRequest(toRevoke.getPublicKeyIdentifier(), generatedRevocationContract));
                }
            } catch (RaException e) {
                ArrayList errorCodes = (ArrayList) e.getErrorCodes();
                Assert.Fail(errorCodes.toString());
            }
        }
   
        [Test]
        public void submitCSRForForeigner() {

                    
            AuthenticationCertificateRegistrationService certRA = ServiceFactory.getAuthenticationCertificateRegistrationService();
            KeyPair authenticationKeyPair = CertificateUtils.generateKeyPair();
            SubmitCSRForForeignerResponseInfo submitCSRForForeignerResponseInfo = (SubmitCSRForForeignerResponseInfo) certRA.submitCSRForForeigner(BuilderFactory.newForeignRequestBuilder()
                    .withSsinBis("82451234769")
                    .withFirstName("foreignerFirstName")
                    .withName("foreignerName")
                    .withPersonalEmail("foreignerFirstName.foreignerName@mail.nl")
                    .withPersonalPhone("00444456464545")
                    .withKeyPair(authenticationKeyPair)
                    .build())
                    .getResult();
            Assert.NotNull(submitCSRForForeignerResponseInfo.getValidationUrl());
        }
        
        public void walk(NewCertificateContract contract, KeyPair authenticationKeyPair, DistinguishedName distinguishedName) {
        	AuthenticationCertificateRegistrationService certRA = ServiceFactory.getAuthenticationCertificateRegistrationService();
        	EncryptionTokenRegistrationService etkRA = ServiceFactory.getEncryptionTokenRegistrationService();
        
            string password = "15";
            char[] passwd = "15".ToCharArray();

            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            string storeFilename = distinguishedName.asNormalisedBaseFileName();
            string storeLocation = KEYSTORE_LOCATION + storeFilename;
            
 			// generate certificate
       		Result generateCertificateResponse = certRA.generateCertificate(contract);

        	// get certificate
            X509Certificate[] result = (X509Certificate[]) pollToGetCertificate(certRA, ((be.fgov.ehealth.technicalconnector.ra.domain.Certificate) generateCertificateResponse.getResult()).getPublicKeyIdentifier()).getResult();
            
            be.fgov.ehealth.technicalconnector.ra.utils.KeyStoreManager store = new be.fgov.ehealth.technicalconnector.ra.utils.KeyStoreManager();
            store.addAuthenticationKeyPair(authenticationKeyPair, passwd);
            store.addAuthenticationChain(passwd, result);
            store.store(storeLocation, passwd);
   
    		ConfigFactory.getConfigValidator().getConfig().setProperty("KEYSTORE_DIR", KEYSTORE_LOCATION);
            Credential credential = new KeyStoreCredential(storeFilename, "authentication", password);
        	KeyPair etkKeyPair = CertificateUtils.generateKeyPair();
    
    		// start ETK registration
            Result challenge = etkRA.startETKRegistration(etkKeyPair.getPublic(), credential);
    
      
            // complete ETK registration
            X509Certificate etkCert = BuilderFactory.newEncryptionTokenBuilder(credential).create()
                    .withKeyPair(etkKeyPair)
            		.withChallenge((byte[]) challenge.getResult())
                    .build();
    
            etkRA.completeETKRegistration(etkCert.getEncoded(), credential);
    
            store.addEncryptionToken(etkKeyPair, passwd, etkCert);
            store.store(storeLocation, passwd);
            
            
            // Certificate cannot be immediately renewed
        	try {
            	etkRA.activateToken(credential);
            } catch (RaException e) {
            	Assert.AreEqual("[RENEW_ACTIVATION_ETK_ALREADY_ACTIF]",  ((ArrayList) e.getErrorCodes()).toString());
        	}
            
        }	
    
        private Result pollToGetCertificate(AuthenticationCertificateRegistrationService certRA, byte[] publicKeyIdentifier) {
            Result result = certRA.getCertificate(publicKeyIdentifier);
            while (result.getStatus().equals(Status.PENDING)) {
                long duration = new Duration(new DateTime(), result.getTime()).getMillis();
                if (duration > 0) {
                    Thread.sleep(duration);
                }
                result = certRA.getCertificate(publicKeyIdentifier);
            }
            if (result.hasStatusError()) {
                throw new IllegalArgumentException(result.getStatus().name());
            }
            return result;
        }
    
        private string get(string key) {
            return TestPropertiesNetLoader.getProperties("be.ehealth.technicalconnector.test.properties",".net").getProperty(key);
        }
	}
}