/*
 * Copyright (c) eHealth
 */
package be.ehealth.business.test.mycarenetcommons.builders.impl;

import be.ehealth.business.mycarenetcommons.builders.ResponseBuilder;
import be.ehealth.business.mycarenetcommons.builders.ResponseBuilderFactory;
import be.ehealth.business.mycarenetcommons.builders.util.BlobUtil;
import be.ehealth.business.mycarenetcommons.v3.mapper.SendRequestMapper;
import be.ehealth.business.mycarenetdomaincommons.builders.BlobBuilder;
import be.ehealth.business.mycarenetdomaincommons.builders.BlobBuilderFactory;
import be.ehealth.business.mycarenetdomaincommons.builders.impl.BuilderUtils;
import be.ehealth.business.mycarenetdomaincommons.domain.Blob;
import be.ehealth.business.mycarenetdomaincommons.exception.ConnectorValidationException;
import be.ehealth.business.mycarenetdomaincommons.exception.InvalidBlobContentConnectorException;
import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.config.ConfigValidator;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.fgov.ehealth.mycarenet.commons.core.v3.BlobType;
import be.fgov.ehealth.mycarenet.commons.core.v3.CommonOutputType;
import be.fgov.ehealth.mycarenet.commons.protocol.v3.ResponseReturnType;
import be.fgov.ehealth.mycarenet.commons.protocol.v3.SendResponseType;
import be.fgov.ehealth.technicalconnector.tests.session.SessionDestroyer;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3._2005._05.xmlmime.Base64Binary;

import java.security.NoSuchAlgorithmException;


/**
 * test class to test the factory.
 * 
 * @author EH058
 * 
 */
public class ResponseBuilderIntegrationTest {

    /**
     * @throws java.lang.Exception
     */
    @BeforeClass
    public static void setUpSession() throws Exception {
        SessionInitializer.init("/be.ehealth.businessconnector.mycarenetcommons.test.properties");
        // to be able to test with deflate , you also need to load the following module : ConfigurationModuleRegisterTransformers
        addConfigModuleAndReload("be.fgov.ehealth.technicalconnector.signature.config.impl.ConfigurationModuleRegisterTransformers");
    }

    /**
     * @param string
     */
    private static void addConfigModuleAndReload(String moduleName) throws TechnicalConnectorException {
        ConfigValidator configValidator = ConfigFactory.getConfigValidator();
        int i = 1;
        String nextModuleProperty = configValidator.getProperty("connector.configmodule." + i);
        while (nextModuleProperty != null && !nextModuleProperty.isEmpty()) {
            i++;
            nextModuleProperty = configValidator.getProperty("connector.configmodule." + i);
        }
        configValidator.setProperty("connector.configmodule." + i, moduleName);
        ConfigFactory.getConfigValidator().reload();

    }

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

    /**
     * Test method for {@link be.ehealth.business.mycarenetcommons.builders.impl.ResponseBuilderFactory#getResponseBuilder()}.
     */
    @SuppressWarnings("deprecation")
    @Test
    public void testGetResponseBuilderFactory() throws Exception {
        Assert.assertNotNull(ResponseBuilderFactory.getResponseBuilder());
        Assert.assertNotNull(ResponseBuilderFactory.getResponseBuilder("default"));
    }

    /**
     * Test method for {@link be.ehealth.business.mycarenetcommons.builders.impl.ResponseBuilderFactory#getResponseBuilder()}.
     */
    @Test
    public void testRightResponse() throws Exception {
        ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("default");
        SendResponseType responseType = initResponse();
        Assert.assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><blabla><BoxId><Id>10013368001</Id></BoxId></blabla>", responseBuilder.getResponse(responseType, true));
    }

    /**
     * @return
     */
    private SendResponseType initResponse() throws TechnicalConnectorException, NoSuchAlgorithmException {
        SendResponseType responseReturnType = createResponseFilledResponseReturnType();
        Base64Binary generateXades = BlobUtil.generateXades(responseReturnType.getReturn().getDetail());
        responseReturnType.getReturn().setXadesT(generateXades);
        CommonOutputType commonOutput = new CommonOutputType();
        commonOutput.setInputReference("test");
        commonOutput.setNIPReference("test");
        commonOutput.setOutputReference("test");
        responseReturnType.getReturn().setCommonOutput(commonOutput);

        return responseReturnType;
    }

    /**
     * @return
     * @throws TechnicalConnectorException
     * @throws InvalidBlobContentConnectorException
     * @throws NoSuchAlgorithmException
     */
    public SendResponseType createResponseFilledResponseReturnType() throws TechnicalConnectorException, InvalidBlobContentConnectorException, NoSuchAlgorithmException {
        BlobBuilder builder = BlobBuilderFactory.getBlobBuilder("default");
        Blob blob = builder.build("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><blabla><BoxId><Id>10013368001</Id></BoxId></blabla>".getBytes(), "deflate", "blob", "text/xml");
        byte[] decompressBlob = BuilderUtils.decompressBlob(blob.getContent(), blob.getContentEncoding());
        blob.setHashValue(BuilderUtils.buildHash(decompressBlob));
        BlobType blobType = SendRequestMapper.mapBlobToBlobType(blob);
        SendResponseType responseType = new SendResponseType();

        ResponseReturnType responseReturnType = new ResponseReturnType();
        responseReturnType.setDetail(blobType);
        responseType.setReturn(responseReturnType);


        return responseType;
    }

    /**
     * Test method for {@link be.ehealth.business.mycarenetcommons.builders.impl.ResponseBuilderFactory#getResponseBuilder()}.
     */
    @Test
    public void testWrongHash() throws Exception {
        ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("default");
        SendResponseType responseType = initResponse();
        responseType.getReturn().getDetail().setHashValue("wrong".getBytes());
        try {
            responseBuilder.getResponse(responseType, true);
            Assert.fail("should have thrown exception because hash value was not correct");
        } catch (InvalidBlobContentConnectorException e) {
            Assert.assertEquals("Hash value is different : was d3Jvbmc= but expecting 8Xce5nEDVODLUoxnqkB1UwoHSlKTW5S4KttSg94snuA=", e.getMessage());
        }
    }

    @Test
    public void testValidateXadesWithConfigPropertyMissingAndNoXades() throws Exception {
        try {
            SendResponseType responseReturnType = createResponseFilledResponseReturnType();
            ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("unconfiguredProject");
            responseBuilder.validateXades(responseReturnType);
            Assert.fail("a default check on level xades will be done if the property is not configured");
        } catch (InvalidBlobContentConnectorException e) {
            Assert.assertEquals("The xades value is required but null", e.getMessage());
        }
    }

    @Test
    public void testValidateXadesWithNoXadesPresentAndNoneNeeded() throws Exception {
        SendResponseType responseReturnType = createResponseFilledResponseReturnType();
        ConfigFactory.getConfigValidator().setProperty("mycarenet.noXadesNeededProject.response.neededxadeslevel", "none");
        ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("noXadesNeededProject");
        responseBuilder.validateXades(responseReturnType);

    }

    @Test
    public void testValidateXadesWithNoXadesPresentAndNeeded() throws Exception {
        try {
            SendResponseType responseReturnType = createResponseFilledResponseReturnType();
            ConfigFactory.getConfigValidator().setProperty("mycarenet.xadesBesNeededProject.response.neededxadeslevel", "xades");
            ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("xadesBesNeededProject");
            responseBuilder.validateXades(responseReturnType);
            Assert.fail("should have thrown InvalidBlobContentConnectorException");
        } catch (InvalidBlobContentConnectorException e) {
            Assert.assertEquals("The xades value is required but null", e.getMessage());
        }
    }

    @Test
    public void testValidateXadesWithXadesBesPresentAndXadesTNeeded() throws Exception {
        try {
            SendResponseType responseReturnType = createResponseFilledResponseReturnType();
            ConfigFactory.getConfigValidator().setProperty("mycarenet.xadesTNeededProject.response.neededxadeslevel", "xadest");
            ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("xadesTNeededProject");
            // add xadesBes
            ConfigFactory.getConfigValidator().setProperty("mycarenet.xadesGenerationProject.request.xadestype", "xades");
            responseReturnType.getReturn().setXadesT(BlobUtil.generateXades(responseReturnType.getReturn().getDetail(), "xadesGenerationProject"));
            responseBuilder.validateXades(responseReturnType);
            Assert.fail("a xades message should not pass if xadest is required");
        } catch (InvalidBlobContentConnectorException e) {
            Assert.assertTrue(e.getMessage() != null && e.getMessage().indexOf("Xades validation failed with the following error :$error: XADES_ENCAPSULATED_TIMESTAMP_NOT_FOUND:[Error indication that there was no encapsulated timestamp in the xades-t.]") != -1);
        }
    }

    @Test
    public void testValidateXadesWithXadesTPresentAndXadesTNeeded() throws Exception {
        SendResponseType responseReturnType = createResponseFilledResponseReturnType();
        ConfigFactory.getConfigValidator().setProperty("mycarenet.xadesTNeededProject.response.neededxadeslevel", "xadest");
        ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("xadesTNeededProject");
        // add xadesT
        ConfigFactory.getConfigValidator().setProperty("mycarenet.xadesTGenerationProject.request.xadestype", "xadest");
        responseReturnType.getReturn().setXadesT(BlobUtil.generateXades(responseReturnType.getReturn().getDetail(), "xadesTGenerationProject"));
        responseBuilder.validateXades(responseReturnType);
    }

    @Test
    public void testValidateXadesWithXadesTPresentAndXadesBesNeeded() throws Exception {
        // Xades-t = xades-bes + timestamp, so this is ok
        SendResponseType responseReturnType = createResponseFilledResponseReturnType();
        ConfigFactory.getConfigValidator().setProperty("mycarenet.xadesBesNeededProject.response.neededxadeslevel", "xades");
        ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("xadesBesNeededProject");
        // add xadesT
        ConfigFactory.getConfigValidator().setProperty("mycarenet.xadesTGenerationProject.request.xadestype", "xadest");
        responseReturnType.getReturn().setXadesT(BlobUtil.generateXades(responseReturnType.getReturn().getDetail(), "xadesTGenerationProject"));
        responseBuilder.validateXades(responseReturnType);
    }


    @Test
    public void testWrongCommonOutput() throws Exception {
        try {
            ResponseBuilder responseBuilder = ResponseBuilderFactory.getResponseBuilder("default");
            SendResponseType responseType = initResponse();
            responseType.getReturn().setCommonOutput(null);
            responseBuilder.getResponse(responseType, true);
            Assert.fail("must generate a ConnectorValidationException");
        } catch (ConnectorValidationException e) {
            // success
        }
    }

    // /**
    // * @return
    // */
    // private SendResponseType initResponse() {
    // SendResponseType responseType = new SendResponseType();
    // BlobType blobType = new BlobType();
    // blobType.setContentEncoding("none");
    // blobType.setContentType("text/xml");
    // blobType.setHashValue(Base64.decode("DuZxtaOXj899T8wjQ5DJqpPu/qyw1hVL0PO7p4EQoPY="));
    // blobType.setId("blob");
    // blobType
    // .setValue("PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pgo8bnMyOnJlZ2lzdHJhdGlvbnNBbnN3ZXIgeG1sbnM9InVybjpiZTpjaW46bXljYXJlbmV0OmVzYjpjb21tb246djIiIHhtbG5zOm5zMj0idXJuOmJlOmNpbjpuaXA6c3luYzpyZWc6djEiIHhtbG5zOm5zMz0idXJuOmJlOmNpbjp0eXBlczp2MSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnNjaGVtYUxvY2F0aW9uPSJodHRwOi8vd3d3LmVoZWFsdGguZmdvdi5iZS9tZXNzYWdlc2VydmljZXMvcHJvdG9jb2wvdjEgLi4veHNkLW1lc3NhZ2VzZXJ2aWNlcy0xLTAvZWhlYWx0aC1tZXNzYWdlc2VydmljZXMvWFNEL2VoZWFsdGhfbWVzc2FnZV9wcm90b2NvbC0xXzAueHNkIj4KICAgIDxuczI6cmVnaXN0cmFudD4KICAgICAgICA8bnMyOkNhcmVQcm92aWRlcj4KICAgICAgICAgICAgPE5paGlpPgogICAgICAgICAgICAgICAgPFF1YWxpdHk+ZG9jdG9yPC9RdWFsaXR5PgogICAgICAgICAgICAgICAgPFZhbHVlPjE4MzM0NzgwMDA0PC9WYWx1ZT4KICAgICAgICAgICAgPC9OaWhpaT4KICAgICAgICA8L25zMjpDYXJlUHJvdmlkZXI+CiAgICA8L25zMjpyZWdpc3RyYW50PgogICAgPG5zMjpyZWdpc3RyYXRpb25BbnN3ZXIgc2VydmljZU5hbWU9IkdNRCIgc3RhdHVzPSJFUlJPUiI+CiAgICAgICAgPG5zMjphbnN3ZXJEZXRhaWxzPgogICAgICAgICAgICA8bnMzOkRldGFpbENvZGU+MTY4PC9uczM6RGV0YWlsQ29kZT4KICAgICAgICAgICAgPG5zMzpEZXRhaWxTb3VyY2U+NTAwPC9uczM6RGV0YWlsU291cmNlPgogICAgICAgICAgICA8bnMzOkxvY2F0aW9uPipbbG9jYWwtbmFtZSgpID0gJ3JlZ2lzdHJhdGlvbnMnIGFuZCBuYW1lc3BhY2UtdXJpKCk9J3VybjpiZTpjaW46bmlwOnN5bmM6cmVnOnYxJyBdLypbbG9jYWwtbmFtZSgpID0gJ3JlZ2lzdHJhbnQnIGFuZCBuYW1lc3BhY2UtdXJpKCk9J3VybjpiZTpjaW46bmlwOnN5bmM6cmVnOnYxJyBdLypbbG9jYWwtbmFtZSgpID0gJ0NhcmVQcm92aWRlcicgYW5kIG5hbWVzcGFjZS11cmkoKT0ndXJuOmJlOmNpbjpuaXA6c3luYzpyZWc6djEnIF08L25zMzpMb2NhdGlvbj4KICAgICAgICAgICAgPG5zMzpNZXNzYWdlIHhtbDpsYW5nPSJubCI+RG9rdGVyIGlzIHJlZWRzIGdlYWZmaWxpZWVyZCB0b3QgTXlDYXJlbmV0IFNlcnZpY2VzLjwvbnMzOk1lc3NhZ2U+CiAgICAgICAgPC9uczI6YW5zd2VyRGV0YWlscz4KICAgIDwvbnMyOnJlZ2lzdHJhdGlvbkFuc3dlcj4KPC9uczI6cmVnaXN0cmF0aW9uc0Fuc3dlcj4K".getBytes());
    // ResponseReturnType responseReturnType = new ResponseReturnType();
    // responseReturnType.setDetail(blobType);
    // Base64Binary value = new Base64Binary();
    // value
    // .setValue(" ".getBytes());
    // responseReturnType.setXadesT(value);
    // CommonOutputType commonOutput = new CommonOutputType();
    // commonOutput.setInputReference("test");
    // commonOutput.setNIPReference("test");
    // commonOutput.setOutputReference("test");
    // responseReturnType.setCommonOutput(commonOutput);
    // responseType.setReturn(responseReturnType);
    // return responseType;
    // }
    // be.ehealth.business.mycarenetdomaincommons.exception.InvalidBlobContentConnectorException: Hash value is different : was
    // TUVZd01uaHZSR1V2UVRkSWNXaDVSRXhtUldWSVZsbFpXR1JtVFZWeWFsazBRVk12VVRsTVdHUnlNRDA9 but expecting
    // 0cLHGZAHVcJMH8ue34PA68R3Kx0TpNFUUmAYHlojjw4=

}
