/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.chapterIV.builders.impl;

import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.Enumeration;
import java.util.Properties;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import be.ehealth.businessconnector.chapterIV.builders.BuilderFactory;
import be.ehealth.businessconnector.chapterIV.builders.ResponseBuilder;
import be.ehealth.businessconnector.chapterIV.builders.WrappedResponseBuilder;
import be.ehealth.businessconnector.chapterIV.domain.ChapterIVKmehrResponseWithTimeStampInfo;
import be.ehealth.businessconnector.chapterIV.testutil.TestUtils;
import be.ehealth.technicalconnector.exception.UnsealConnectorException;
import be.ehealth.technicalconnector.session.Session;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.fgov.ehealth.chap4.protocol.v1.ConsultChap4MedicalAdvisorAgreementResponse;
import be.fgov.ehealth.technicalconnector.tests.session.SessionDestroyer;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;
import be.fgov.ehealth.technicalconnector.tests.utils.TestPropertiesLoader;
import be.fgov.ehealth.technicalconnector.tests.utils.XmlAsserter;


/**
 * tests the {@link ResponseBuilderImpl} class.
 * 
 * @author EHP
 * 
 */
public class ResponseBuilderIntegrationTest {

    private static Properties props;

    private ResponseBuilder responseBuilder;

    @Before
    public void setup() throws Exception {
        responseBuilder = BuilderFactory.getBuilderFactoryForSession().getResponseBuilder();        
    }

    @BeforeClass
    public static void init() throws Exception {
        
       SessionDestroyer.destroy();
        props = TestPropertiesLoader.getProperties("/be.ehealth.businessconnector.chapterIV.test.properties");
        SessionInitializer.init(props);
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        char[] password = props.getProperty("test.expired.keystore.password").toCharArray();
        keystore.load(ConnectorIOUtils.getResourceAsStream(props.getProperty("test.expired.keystore.location")), password);
        Enumeration<String> enums = keystore.aliases();
        while (enums.hasMoreElements()) {
            String alias = enums.nextElement();
            if (keystore.isKeyEntry(alias) && !alias.equals("authentication")) {
                Session.getInstance().getSession().getEncryptionPrivateKeys().put(alias, (PrivateKey) keystore.getKey(alias, password));
                Session.getInstance().getSession().getHolderOfKeyPrivateKeys().put(alias, (PrivateKey) keystore.getKey(alias, password));
            }
        }
    }

    @AfterClass
    public static void teardown() throws Exception {
        SessionDestroyer.destroy();
    }

    @Test
    public void testUnsealedSecuredContent() throws Exception {
        boolean expectedError = !isDoctor() || !isHannes();
        String expectedFileLocation = "/examples/response/contentUnsealedSealedContentOfSuccesfullResponse.xml";
        String expectedFileContents = TestUtils.getFileContents(expectedFileLocation);
        try {
            ConsultChap4MedicalAdvisorAgreementResponse agreementResponse = TestUtils.mapToConsultResponseObject("/examples/response/successfullResponse.xml");

            String actual = new String(((ResponseBuilderImpl) responseBuilder).unsealSecuredContent(WrappedResponseBuilder.wrap(agreementResponse), true));

            XmlAsserter.assertSimilar(expectedFileContents, actual);

        } catch (UnsealConnectorException e) {
            // we expect an UnsealConnectoException if the user is not Hannes or not a doctor
            if (!expectedError) {

                throw e;
            }
        }
    }

    @Test
    public void testRetrieveKmehrResponseIgnoreWarningsTrue() throws Exception {
        ConsultChap4MedicalAdvisorAgreementResponse agreementResponse = TestUtils.mapToConsultResponseObject("/examples/response/successfullResponse.xml");
        boolean expectedError = !isDoctor() || !isHannes();

        try {
            responseBuilder.validateTimestampAndretrieveChapterIVKmehrResponseWithTimeStampInfo(agreementResponse, true);
            Assert.assertFalse("An UnsealConnectorException should have been thrown", expectedError);
        } catch (UnsealConnectorException e) {
            // we expect an UnsealConnectoException if the user is not Hannes or not a doctor
            if (!expectedError) {
                throw e;
            }
        }
    }


    @Test
    public void testUnsealedSecuredContentExpiredCertificate() throws Exception {
        boolean expectedError = !isDoctor() || !isHannes();
        try {
            ConsultChap4MedicalAdvisorAgreementResponse agreementResponse = TestUtils.mapToConsultResponseObject("/examples/response/successfullResponse_expiredcert.xml");

            String actual = new String(((ResponseBuilderImpl) responseBuilder).unsealSecuredContent(WrappedResponseBuilder.wrap(agreementResponse), true));

            String expectedFileLocation = "/examples/response/contentUnsealedSealedContentOfSuccessfullResponse_expiredCert.xml";
            XmlAsserter.assertSimilar(TestUtils.getFileContents(expectedFileLocation), actual);
        } catch (UnsealConnectorException e) {
            // we expect an UnsealConnectoException if the user is not Hannes or not a doctor
            if (!expectedError) {
                throw e;
            }
        }
    }

    /**
     * If Hannes is not the doctor, the UnsealConnectorException is thrown because the certificate is not valid for the content of the
     * message (because it's encrypted for another person) Otherwise, the exception is thrown because the certificate is expired.
     * 
     * @throws Exception
     */
    @Test(expected = UnsealConnectorException.class)
    public void testRetrieveKmehrResponseExpiredCertificateIgnoreWarningsFalse() throws Exception {
        ConsultChap4MedicalAdvisorAgreementResponse agreementResponse = TestUtils.mapToConsultResponseObject("/examples/response/successfullResponse_expiredcert.xml");
        responseBuilder.validateTimestampAndretrieveChapterIVKmehrResponseWithTimeStampInfo(agreementResponse, false);
    }

    @Test
    public void testRetrieveKmehrResponseExpiredCertificateIgnoreWarningsTrue() throws Exception {
        boolean expectedError = !isDoctor() || !isHannes();
        try {
            ConsultChap4MedicalAdvisorAgreementResponse agreementResponse = TestUtils.mapToConsultResponseObject("/examples/response/successfullResponse_expiredcert.xml");

            ChapterIVKmehrResponseWithTimeStampInfo validateTimestampAndretrieveChapterIVKmehrResponseWithTimeStampInfo = responseBuilder.validateTimestampAndretrieveChapterIVKmehrResponseWithTimeStampInfo(agreementResponse, true);

            String actual = new String(validateTimestampAndretrieveChapterIVKmehrResponseWithTimeStampInfo.getKmehrResponseBytes());

            String expectedFileLocation = "/examples/response/contentKmehrMessageInSuccessfulResponse_expiredcert.xml";
            XmlAsserter.assertSimilar(TestUtils.getFileContents(expectedFileLocation), actual);

        } catch (UnsealConnectorException e) {
            // we expect an UnsealConnectoException if the user is not Hannes or not a doctor
            if (!expectedError) {
                throw e;
            }
        }
    }

    private boolean isDoctor() {
        return "persphysician".equals(props.getProperty("session.professionType"));
    }

    private boolean isHannes() {
        return "hannes".equals(props.getProperty("session.username"));
    }


}
