package be.ehealth.businessconnector.ehbox.v3.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unitils.UnitilsJUnit4TestClassRunner;
import org.unitils.reflectionassert.ReflectionAssert;

import be.ehealth.businessconnector.ehbox.api.domain.Addressee;
import be.ehealth.businessconnector.ehbox.api.domain.Document;
import be.ehealth.businessconnector.ehbox.api.domain.DocumentMessage;
import be.ehealth.businessconnector.ehbox.api.domain.NewsMessage;
import be.ehealth.businessconnector.ehbox.api.utils.QualityType;
import be.ehealth.businessconnector.ehbox.v3.EhboxTestDataBuilder;
import be.ehealth.businessconnector.ehbox.v3.EhboxTestUtilities;
import be.ehealth.businessconnector.ehbox.v3.builders.BuilderFactory;
import be.ehealth.businessconnector.ehbox.v3.builders.SendMessageBuilder;
import be.ehealth.businessconnector.ehbox.v3.session.EhealthBoxServiceV3;
import be.ehealth.businessconnector.ehbox.v3.session.ServiceFactory;
import be.ehealth.technicalconnector.exception.UnsealConnectorException;
import be.ehealth.technicalconnector.idgenerator.IdGeneratorFactory;
import be.ehealth.technicalconnector.session.Session;
import be.ehealth.technicalconnector.utils.ConnectorXmlUtils;
import be.ehealth.technicalconnector.utils.IdentifierType;
import be.fgov.ehealth.commons.core.v1.LocalisedString;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.GetFullMessageRequest;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.GetFullMessageResponse;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.Message;
import be.fgov.ehealth.ehbox.core.v3.BoxIdType;
import be.fgov.ehealth.ehbox.core.v3.CustomMetaType;
import be.fgov.ehealth.ehbox.core.v3.FreeInformationsType;
import be.fgov.ehealth.ehbox.core.v3.Row;
import be.fgov.ehealth.ehbox.core.v3.User;
import be.fgov.ehealth.ehbox.publication.protocol.v3.ContentSpecificationType;
import be.fgov.ehealth.ehbox.publication.protocol.v3.DestinationContextType;
import be.fgov.ehealth.ehbox.publication.protocol.v3.PublicationAnnexType;
import be.fgov.ehealth.ehbox.publication.protocol.v3.PublicationContentType;
import be.fgov.ehealth.ehbox.publication.protocol.v3.PublicationDocumentType;
import be.fgov.ehealth.ehbox.publication.protocol.v3.SendMessageRequest;
import be.fgov.ehealth.ehbox.publication.protocol.v3.SendMessageResponse;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;
import be.fgov.ehealth.technicalconnector.tests.utils.TestPropertiesLoader;

/**
 * eHealthBox Service Integration Tests This test shows the use of the eHealthBox Service through the use of the Business Connector.
 * 
 * The tests below use the Session Management Service to manage the session and SAML/STS token. The eHealthBox of the test user specified in
 * the business connector property file is used, these tests expect that this is set to a valid INSS of a citizen.
 * 
 * @author EHP
 * 
 */
@RunWith(UnitilsJUnit4TestClassRunner.class)
public class PublicationServiceIntegrationTest {

    private static boolean isDoctorTest;

    @BeforeClass
    public static void initIntegrationTest() throws Exception {
        Properties props = TestPropertiesLoader.getProperties(FILE_AS_DOC);
        SessionInitializer.init(props, true);
        isDoctorTest = EhboxTestUtilities.isDoctorTest(props);
    }

    @AfterClass
    public static void unloadSession() throws Exception {
        Session.getInstance().unloadSession();
    }

    /**
     * Properties file
     */
    private static final String FILE_AS_DOC = "/be.ehealth.businessconnector.ehboxv3.test.properties";

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

    /**
     * Test the sendMessage operation from the eHealthBox Service through the use of the Business Connector. This test creates and sends a
     * message to a predefined eHealthBox, based on a person's INSS
     * 
     * The following main steps are done: - Create the parameters of the new message - Invoke the business connector - Verify the response
     * 
     * @throws Exception
     */
    @Test
    public void testSendNewsEncryptedMessage() throws Exception {
        /*
         * Create the parameters of the new message
         */
        SendMessageBuilder builder = BuilderFactory.getSendMessageBuilder();


        NewsMessage<Message> news = new NewsMessage<Message>();
        news.getDocument().setTitle("Encrypted news " + new Date());
        news.getDocument().setContent("eureka".getBytes());
        news.getDocument().setFilename("test.txt");
        news.getDocument().setMimeType("text/xml");

        news.setDestinations(getDestination());
        news.setImportant(true);
        news.setEncrypted(true);

        SendMessageRequest request = builder.buildMessage(news);

        CustomMetaType type = new CustomMetaType();
        type.setValue("");
        type.setKey("");


        /*
         * Invoke the business connector framework's eHealthBox's sendMessage operation
         */
        EhealthBoxServiceV3 service = ServiceFactory.getEhealthBoxServiceV3();
        ConnectorXmlUtils.logXmlObject(request);
        SendMessageResponse response = service.sendMessage(request);

        /*
         * Verify the response
         */
        // check if there are no errors
        Assert.assertEquals("100", response.getStatus().getCode());
        // check if a messageId has been returned
        Assert.assertNotNull(response.getId());

        LOG.debug("Message Sent: " + response.getId());
        for (LocalisedString localisedString : response.getStatus().getMessages()) {
            LOG.debug("statusMessage" + localisedString.getValue());
        }
        Assert.assertTrue(response.getStatus().getMessages().size() == 1);
        Assert.assertEquals(response.getStatus().getMessages().get(0).getValue(), "SUCCESS");

    }

    /**
     * Sens a newsMessages and verifies the response.
     * 
     * @throws Exception
     */
    @Test
    public void testSendNewsMessage() throws Exception {
        /*
         * Create the parameters of the new message
         */
        SendMessageBuilder builder = BuilderFactory.getSendMessageBuilder();


        NewsMessage<Message> news = new NewsMessage<Message>();
        news.getDocument().setTitle("Spamming with ehbox News " + new Date());
        news.getDocument().setContent("eureka".getBytes());
        news.getDocument().setFilename("test.txt");
        news.getDocument().setMimeType("text/xml");
        news.getCopyMailTo().add("dummy@ehealth.fgov.be");

        news.setDestinations(getDestination());
        news.setImportant(true);
        news.setEncrypted(false);

        SendMessageRequest request = builder.buildMessage(news);


        /*
         * Invoke the business connector framework's eHealthBox's sendMessage operation
         */

        EhealthBoxServiceV3 service = ServiceFactory.getEhealthBoxServiceV3();
        ConnectorXmlUtils.logXmlObject(request);
        SendMessageResponse response = service.sendMessage(request);

        /*
         * Verify the response
         */
        // check if there are no errors
        Assert.assertEquals("100", response.getStatus().getCode());
        // check if a messageId has been returned
        Assert.assertNotNull(response.getId());

        LOG.debug("Message Sent: " + response.getId());
        for (LocalisedString localisedString : response.getStatus().getMessages()) {
            LOG.debug("statusMessage" + localisedString.getValue());
        }
        Assert.assertTrue(response.getStatus().getMessages().size() == 1);
        Assert.assertEquals(response.getStatus().getMessages().get(0).getValue(), "SUCCESS");

    }

    /**
     * Sens a newsMessages and verifies the response.
     * 
     * @throws Exception
     */
    @Test
    public void testSendNewsMessageWithoutPublicationId() throws Exception {
        // trying to reproduce error ehconext-92

        /*
         * Create the parameters of the new message
         */
        SendMessageBuilder builder = BuilderFactory.getSendMessageBuilder();


        NewsMessage<Message> news = new NewsMessage<Message>();
        news.getDocument().setTitle("Spamming with ehbox News " + new Date());
        news.getDocument().setContent("eureka".getBytes());
        news.getDocument().setFilename("test.txt");
        news.getDocument().setMimeType("text/xml");
        news.getCopyMailTo().add("dummy@ehealth.fgov.be");

        news.setDestinations(getDestination());
        news.setImportant(true);
        news.setEncrypted(false);
        news.setPublicationId(null);

        SendMessageRequest request = builder.buildMessage(news);


        /*
         * Invoke the business connector framework's eHealthBox's sendMessage operation
         */

        EhealthBoxServiceV3 service = ServiceFactory.getEhealthBoxServiceV3();
        ConnectorXmlUtils.logXmlObject(request);
        SendMessageResponse response = service.sendMessage(request);

        /*
         * Verify the response
         */
        // check if there are no errors
        Assert.assertEquals("100", response.getStatus().getCode());
        // check if a messageId has been returned
        Assert.assertNotNull(response.getId());

        LOG.debug("Message Sent: " + response.getId());
        for (LocalisedString localisedString : response.getStatus().getMessages()) {
            LOG.debug("statusMessage" + localisedString.getValue());
        }
        Assert.assertTrue(response.getStatus().getMessages().size() == 1);
        Assert.assertEquals(response.getStatus().getMessages().get(0).getValue(), "SUCCESS");

    }


    /**
     * Sends an encrypted document with annex and verifies the response.
     * 
     * @throws Exception
     */
    @Test
    public void testSendEncryptedDocumentWithAnnex() throws Exception {
        /*
         * Create the parameters of the new message
         */
        SendMessageBuilder builder = BuilderFactory.getSendMessageBuilder();

        DocumentMessage<Message> documentMsg = new DocumentMessage<Message>();
        documentMsg.setDestinations(getDestination());
        documentMsg.setImportant(false);
        documentMsg.setEncrypted(true);

        documentMsg.setFreeText("Free text:" + UUID.randomUUID());
        documentMsg.setPatientInss(EhboxTestDataBuilder.getInssUser1());
        documentMsg.setId(IdGeneratorFactory.getIdGenerator().generateId());

        Document doc = new Document();
        doc.setTitle("Encrypted document " + new Date());
        doc.setContent(PublicationServiceIntegrationTest.class.getResourceAsStream(FILE_AS_DOC));
        doc.setMimeType("text/plain");
        doc.setFilename("be.ehealth.businessconnector.properties");
        documentMsg.setDocument(doc);

        Document annex = new Document();
        annex.setTitle("properties");
        annex.setContent(PublicationServiceIntegrationTest.class.getResourceAsStream(FILE_AS_DOC));
        annex.setFilename("be.ehealth.technicalconnector.properties");
        annex.setMimeType("text/plain");
        documentMsg.getAnnexList().add(annex);

        SendMessageRequest request = builder.buildMessage(documentMsg);
        /*
         * Invoke the business connector framework's eHealthBox's sendMessage operation
         */

        EhealthBoxServiceV3 service = ServiceFactory.getEhealthBoxServiceV3();
        SendMessageResponse response = service.sendMessage(request);

        /*
         * Verify the response
         */
        // check if there are no errors
        Assert.assertEquals("100", response.getStatus().getCode());
        // check if a messageId has been returned
        Assert.assertNotNull(response.getId());

        LOG.debug("Message Sent: " + response.getId());
        for (LocalisedString localisedString : response.getStatus().getMessages()) {
            LOG.debug("statusMessage" + localisedString.getValue());
        }
        Assert.assertTrue(response.getStatus().getMessages().size() == 1);
        Assert.assertEquals(response.getStatus().getMessages().get(0).getValue(), "SUCCESS");


    }

    /**
     * @throws Exception
     */
    @Test
    public void testSendDocumentWithAnnex() throws Exception {

        /*
         * Create the parameters of the new message
         */
        SendMessageBuilder builder = BuilderFactory.getSendMessageBuilder();

        DocumentMessage<Message> documentMsg = new DocumentMessage<Message>();
        documentMsg.setDestinations(getDestination());
        documentMsg.setImportant(false);
        documentMsg.generatePublicationId();

        documentMsg.setFreeText("Free text:" + UUID.randomUUID());
        documentMsg.setPatientInss(EhboxTestDataBuilder.getInssUser1());
        documentMsg.setId(IdGeneratorFactory.getIdGenerator().generateId());


        Document doc = new Document();
        doc.setTitle("Document " + new Date());
        doc.setContent(PublicationServiceIntegrationTest.class.getResourceAsStream(FILE_AS_DOC));
        doc.setMimeType("text/plain");
        doc.setFilename("be.ehealth.businessconnector.properties");
        documentMsg.setDocument(doc);

        Document annex = new Document();
        annex.setTitle("properties");
        annex.setContent(PublicationServiceIntegrationTest.class.getResourceAsStream(FILE_AS_DOC));
        annex.setFilename("be.ehealth.technicalconnector.properties");
        annex.setMimeType("text/plain");
        documentMsg.getAnnexList().add(annex);

        SendMessageRequest request = builder.buildMessage(documentMsg);


        /*
         * Invoke the business connector framework's eHealthBox's sendMessage operation
         */
        EhealthBoxServiceV3 service = ServiceFactory.getEhealthBoxServiceV3();
        SendMessageResponse response = service.sendMessage(request);

        /*
         * Verify the response
         */
        // check if there are no errors
        Assert.assertEquals("100", response.getStatus().getCode());
        // check if a messageId has been returned
        Assert.assertNotNull(response.getId());

        LOG.debug("Message Sent: " + response.getId());
        for (LocalisedString localisedString : response.getStatus().getMessages()) {
            LOG.debug("statusMessage" + localisedString.getValue());
        }
        Assert.assertTrue(response.getStatus().getMessages().size() == 1);
        Assert.assertEquals(response.getStatus().getMessages().get(0).getValue(), "SUCCESS");
        EhboxTestUtilities.waitForProcessing();
        GetFullMessageRequest getFullMessageRequest = BuilderFactory.getRequestBuilder().createGetFullMessageRequest(response.getId());
        setBoxId(request, getFullMessageRequest);
        GetFullMessageResponse fullMessage = service.getFullMessage(getFullMessageRequest);
        EhboxTestUtilities.logFullMessage(BuilderFactory.getConsultationMessageBuilder().buildFullMessage(fullMessage));
        LOG.debug("retrievedFullMessage for message with annex : ");
        Assert.assertNotNull("fullMessage.getMessage() is null", fullMessage.getMessage());

    }

    /**
     * @param request
     * @param getFullMessageRequest
     */
    private void setBoxId(SendMessageRequest request, GetFullMessageRequest getFullMessageRequest) {
        BoxIdType boxId = new BoxIdType();
        boxId.setId(request.getDestinationContexts().get(0).getId());
        boxId.setQuality(request.getDestinationContexts().get(0).getQuality());
        boxId.setType(request.getDestinationContexts().get(0).getType());
        getFullMessageRequest.setBoxId(boxId);
    }

    /**
     * Returns the destination
     * 
     * @return
     */
    private List<Addressee> getDestination() {
        List<Addressee> addresseeList = new ArrayList<Addressee>();
        Addressee addressee = new Addressee(IdentifierType.SSIN);
        addressee.setId(EhboxTestDataBuilder.getInssUser1());
        addressee.setQuality(QualityType.DOCTOR_SSIN);
        addresseeList.add(addressee);

        return addresseeList;
    }

    /**
     * @throws Exception
     */
    @Test
    public void testSendDocumentWithNullAnnex() throws Exception {
        /*
         * Create the parameters of the new message
         */
        SendMessageBuilder builder = BuilderFactory.getSendMessageBuilder();

        DocumentMessage<Message> documentMsg = new DocumentMessage<Message>();
        documentMsg.setDestinations(getDestination());
        documentMsg.setImportant(false);

        documentMsg.setFreeText("Free text:" + UUID.randomUUID());
        documentMsg.setId(IdGeneratorFactory.getIdGenerator().generateId());

        Document doc = new Document();
        doc.setTitle(documentMsg.getPublicationId() + " Döé\"'(§è!çà)-ument   |; ¢¾ñ");
        doc.setContent(PublicationServiceIntegrationTest.class.getResourceAsStream(FILE_AS_DOC));
        doc.setMimeType("text/plain");
        doc.setFilename("be.ehealth.businessconnector.properties");
        documentMsg.setDocument(doc);

        Document annex = new Document();
        annex.setTitle("properties");
        annex.setContent(new byte[]{});
        annex.setFilename("be.ehealth.technicalconnector.properties");
        annex.setMimeType("text/plain");
        documentMsg.getAnnexList().add(annex);

        SendMessageRequest request = builder.buildMessage(documentMsg);

        /*
         * Invoke the business connector framework's eHealthBox's sendMessage operation
         */
        EhealthBoxServiceV3 service = ServiceFactory.getEhealthBoxServiceV3();
        SendMessageResponse response = service.sendMessage(request);

        /*
         * Verify the response
         */
        // check if there are no errors
        Assert.assertEquals("100", response.getStatus().getCode());
        // check if a messageId has been returned
        Assert.assertNotNull(response.getId());

        LOG.debug("Message Sent: " + response.getId());
        for (LocalisedString localisedString : response.getStatus().getMessages()) {
            LOG.debug("testSendDocumentWithNullAnnex : statusMessage" + localisedString.getValue());
        }
        Assert.assertTrue(response.getStatus().getMessages().size() == 1);
        Assert.assertEquals(response.getStatus().getMessages().get(0).getValue(), "SUCCESS");

    }


    @Test
    public void testFullMappingAndcheckReturnedMessage() throws Exception {
        Assume.assumeTrue(isDoctorTest);

        NewsMessage<Message> message = EhboxTestDataBuilder.buildFullExampleNewsMessage(true, true, null);
        SendMessageRequest sendMessageRequest = BuilderFactory.getSendMessageBuilder().buildMessage(message);
        EhealthBoxServiceV3 ehealthBoxServiceV3 = be.ehealth.businessconnector.ehbox.v3.session.ServiceFactory.getEhealthBoxServiceV3();
        SendMessageResponse sendMessageResponse = ehealthBoxServiceV3.sendMessage(sendMessageRequest);
        Assert.assertNotNull(message.getPublicationId());
        Assert.assertNotNull(sendMessageResponse.getId());
        Assert.assertEquals("100", sendMessageResponse.getStatus().getCode());

        EhboxTestUtilities.showMessagesFromSource("INBOX");
        EhboxTestUtilities.showMessagesFromSource("SENTBOX");
        EhboxTestUtilities.waitForProcessing();

        GetFullMessageResponse fullMessage = ehealthBoxServiceV3.getFullMessage(BuilderFactory.getRequestBuilder().createGetFullMessageRequest(sendMessageResponse.getId()));
        be.ehealth.businessconnector.ehbox.api.domain.Message<GetFullMessageResponse> buildFullMessage = BuilderFactory.getConsultationMessageBuilder().buildFullMessage(fullMessage);
        Assert.assertTrue(buildFullMessage instanceof NewsMessage<?>);
        checkFullMessageContentCorrect(message, buildFullMessage);


    }

    /**
     * @param sendMessage
     * @param retrievedFullMessage
     * @throws UnsealConnectorException
     */
    @SuppressWarnings("deprecation")
    private void checkFullMessageContentCorrect(NewsMessage<Message> sendMessage, be.ehealth.businessconnector.ehbox.api.domain.Message<GetFullMessageResponse> retrievedFullMessage) throws UnsealConnectorException {
        Assert.assertTrue(retrievedFullMessage instanceof NewsMessage<?>);
        NewsMessage<?> retrievedNews = (NewsMessage<?>) retrievedFullMessage;
        compareAnnexList(sendMessage.getAnnexList(), retrievedNews.getAnnexList());
        Assert.assertTrue("found mailTo in getFullMessage : wrong : the copyMailTo is never returned in the getFullMessage : its only usefull for the sendRequest", retrievedNews.getCopyMailTo().isEmpty());
        ReflectionAssert.assertReflectionEquals(sendMessage.getCustomMetas(), retrievedNews.getCustomMetas());
        checkListOfAddresseesEqual(sendMessage.getDestinations(), retrievedNews.getDestinations());
        compareDocument(sendMessage.getDocument(), retrievedNews.getDocument());
        ReflectionAssert.assertReflectionEquals(sendMessage.getDocumentTitle(), retrievedNews.getDocumentTitle());
        Assert.assertNotNull(retrievedNews.getExpirationDateTime());
        ReflectionAssert.assertReflectionEquals(sendMessage.getFreeInformationTableRows(), retrievedNews.getFreeInformationTableRows());
        ReflectionAssert.assertReflectionEquals(sendMessage.getFreeInformationTableTitle(), retrievedNews.getFreeInformationTableTitle());
        Assert.assertEquals(sendMessage.getFreeText(), retrievedNews.getFreeText());
        Assert.assertNotNull("the id of the returned messages is unique for that message, end not linked to send message", retrievedNews.getId());
        Assert.assertNull("the mandatee is a deprecated field from ehbox v1 and not supported anymore", retrievedNews.getMandatee());
        Assert.assertEquals(sendMessage.getPatientInss(), retrievedNews.getPatientInss());
        Assert.assertNotNull("the publication date should be filled out ( and is for this test normally the current date", retrievedNews.getPublicationDateTime().toDate());
        Assert.assertEquals(sendMessage.getPublicationId(), retrievedNews.getPublicationId());
        if (sendMessage.getSender() != null) {
            ReflectionAssert.assertReflectionEquals(sendMessage.getSender(), retrievedNews.getSender());
        }
        Assert.assertNotNull("the size is calculated by the ehealthbox and should be mapped to response object", retrievedNews.getSize());
        Assert.assertEquals(sendMessage.isEncrypted(), retrievedNews.isEncrypted());
        Assert.assertEquals(sendMessage.isImportant(), retrievedNews.isImportant());
    }

    /**
     * @param sendDocument
     * @param document2
     * @throws UnsealConnectorException
     */
    private void compareDocument(Document sendDocument, Document retrievedDocument) throws UnsealConnectorException {
        LOG.debug("compareDocument : sendDocument : " + EhboxTestUtilities.documentToString(sendDocument) + " \n and retrieved document " + EhboxTestUtilities.documentToString(retrievedDocument));
        Assert.assertEquals(new String(sendDocument.getContent()), new String(retrievedDocument.getContent()));
        Assert.assertEquals(sendDocument.getFilename(), retrievedDocument.getFilename());
        Assert.assertEquals(sendDocument.getMimeType(), retrievedDocument.getMimeType());
        Assert.assertEquals(sendDocument.getTitle(), retrievedDocument.getTitle());
    }

    /**
     * @param sendList
     * @param retrievedList
     * @throws UnsealConnectorException
     */
    private void compareAnnexList(List<Document> sendList, List<Document> retrievedList) throws UnsealConnectorException {
        Assert.assertEquals(sendList.size(), retrievedList.size());
        for (Document document : sendList) {
            boolean found = false;
            for (Document retrievedDocument : retrievedList) {
                if (retrievedDocument.getTitle().equals(document.getTitle())) {
                    if (found) {
                        Assert.fail("two documents with same title found : for testing purposes this should not be done!!, please check that each document has a unique title");
                    }
                    found = true;
                    compareDocument(document, retrievedDocument);
                }

            }
            Assert.assertTrue(found);
        }

    }

    /**
     * @param sendDestinations
     * @param retrievedDestinations
     */
    private void checkListOfAddresseesEqual(List<Addressee> sendDestinations, List<Addressee> retrievedDestinations) {
        // its possible that the sendDestinations is bigger than the retrieved destinations : if the same person receives a mail with nihii
        // and niss, he will only receive the one with niss
        // ebox converts nihii to niss and removes duplicates
        Assert.assertTrue(sendDestinations.size() >= retrievedDestinations.size());
        for (Addressee retrieved : retrievedDestinations) {
            boolean found = false;
            for (Addressee sendAddressee : sendDestinations) {
                if (sendAddressee.getId().equals(retrieved.getId()) || sendAddressee.getId().startsWith(retrieved.getId())) {
                    // the returned riziv number is sometimes shorter than the original one ( 8 chars instead of 11 )
                    found = true;
                    Assert.assertEquals(sendAddressee.getQuality(), retrieved.getQuality());
                    Assert.assertEquals(sendAddressee.getType(), retrieved.getType());
                }
            }
            if (!found) {
                Assert.fail("could not find destination for id " + retrieved.getId());
            }
        }

    }

    @Test
    public void testCreateSendMessageWithFreeText() throws Exception {
        NewsMessage<Message> message = EhboxTestDataBuilder.buildFullExampleNewsMessage(false, false, null);
        SendMessageRequest request = BuilderFactory.getSendMessageBuilder().buildMessage(message);
        checkRequestContentCorrect(message, request);
    }

    @Test
    public void testCreateSendMessageWithFreeTextTable() throws Exception {
        NewsMessage<Message> message = EhboxTestDataBuilder.buildFullExampleNewsMessage(false, true, null);
        SendMessageRequest request = BuilderFactory.getSendMessageBuilder().buildMessage(message);
        checkRequestContentCorrect(message, request);
    }

    @Test
    public void testCreateSendMessageEncryptedWithFreeText() throws Exception {
        NewsMessage<Message> message = EhboxTestDataBuilder.buildFullExampleNewsMessage(true, false, null);
        SendMessageRequest request = BuilderFactory.getSendMessageBuilder().buildMessage(message);
        checkRequestContentCorrect(message, request);
    }

    @Test
    public void testCreateSendMessageEncryptedWithFreeTextTable() throws Exception {
        NewsMessage<Message> message = EhboxTestDataBuilder.buildFullExampleNewsMessage(true, true, null);
        SendMessageRequest request = BuilderFactory.getSendMessageBuilder().buildMessage(message);
        checkRequestContentCorrect(message, request);
    }

    /**
     * @param message
     * @param request
     */
    private void checkRequestContentCorrect(NewsMessage<Message> message, SendMessageRequest request) {
        Assert.assertEquals(message.getPublicationId(), request.getPublicationId());
        Assert.assertEquals(message.getDestinations().size(), request.getDestinationContexts().size());
        for (Addressee destination : message.getDestinations()) {
            isDestinationContextPresent(request.getDestinationContexts(), destination);
        }
        ReflectionAssert.assertLenientEquals(message.getCopyMailTo(), request.getCopyMailTos());
        checkContentContextIsEqual(message, request);
    }

    /**
     * @param message
     * @param request
     */
    private void checkContentContextIsEqual(NewsMessage<Message> message, SendMessageRequest request) {
        List<CustomMetaType> customMetas = request.getContentContext().getCustomMetas();
        Map<String, String> requestCustomMetas = message.getCustomMetas();
        Assert.assertEquals("the number of customMetas should be equal", requestCustomMetas.size(), customMetas.size());
        for (CustomMetaType customMetaType : customMetas) {
            String key = customMetaType.getKey();
            Assert.assertTrue(requestCustomMetas.containsKey(key));
            Assert.assertEquals(requestCustomMetas.get(key), customMetaType.getValue());
        }
        checkContent(message, request.getContentContext().getContent());
        checkContentSpecification(message, request.getContentContext().getContentSpecification());
    }

    /**
     * @param message
     * @param contentSpecificationType
     */
    private void checkContentSpecification(NewsMessage<Message> message, ContentSpecificationType contentSpecificationType) {
        Assert.assertNotNull(contentSpecificationType.getContentType());
        Assert.assertEquals(message.isImportant(), contentSpecificationType.isIsImportant());
        Assert.assertEquals(message.isEncrypted(), contentSpecificationType.isIsEncrypted());
        Assert.assertEquals(message.isUsePublicationReceipt(), contentSpecificationType.isPublicationReceipt());
        Assert.assertEquals(message.isUseReadReceipt(), contentSpecificationType.isReadReceipt());
        Assert.assertEquals(message.isUseReceivedReceipt(), contentSpecificationType.isReceivedReceipt());

    }

    /**
     * @param message
     * @param publicationContentType
     */
    private void checkContent(NewsMessage<Message> message, PublicationContentType publicationContentType) {
        checkAnnices(message.getAnnexList(), publicationContentType.getAnnices());
        checkDocument(message.getDocument(), publicationContentType.getDocument());
        Assert.assertNotNull(publicationContentType.getEncryptableINSSPatient());
        checkFreeInformations(message, publicationContentType.getFreeInformations());

    }

    /**
     * @param message
     * @param freeInformations
     */
    private void checkFreeInformations(NewsMessage<Message> message, FreeInformationsType freeInformations) {
        // either freeInformations encryptable freetext is filled out or table inf , never both!
        String freeInformationTableTitle = message.getFreeInformationTableTitle();
        if (freeInformationTableTitle != null) {
            Assert.assertEquals(freeInformationTableTitle, freeInformations.getTable().getTitle());
            Assert.assertNull(freeInformations.getEncryptableFreeText());
            List<Row> rows = freeInformations.getTable().getRows();
            Assert.assertEquals(message.getFreeInformationTableRows().size(), rows.size());
        } else {
            Assert.assertNotNull(freeInformations.getEncryptableFreeText());
        }
    }

    /**
     * @param document
     * @param pubDocument
     */
    private void checkDocument(Document document, PublicationDocumentType pubDocument) {
        Assert.assertNotNull(pubDocument.getDigest());
        Assert.assertEquals(document.getFilename(), pubDocument.getDownloadFileName());
        Assert.assertEquals(document.getMimeType(), pubDocument.getMimeType());
        Assert.assertNotNull(pubDocument.getEncryptableBinaryContent());
        Assert.assertEquals(document.getTitle(), pubDocument.getTitle());


    }

    /**
     * @param annexList
     * @param annices
     */
    private void checkAnnices(List<Document> annexList, List<PublicationAnnexType> annices) {
        Assert.assertEquals(annexList.size(), annices.size());
        for (Document doc : annexList) {
            // check the corresponding annex document in list of documents, search on title( assume title is unique->at least for testing
            // purposes)
            boolean alreadyFound = false;
            Assert.assertNotNull("for testing purposes the filename of a doc may not be null and must be unique , its used as a key in a list of documents when comparing the contents", doc.getFilename());
            for (PublicationAnnexType annex : annices) {
                if (doc.getFilename().equals(annex.getDownloadFileName())) {
                    Assert.assertFalse("two annexes with same fileName found : for test purposes we require each annex to have a different file name", alreadyFound);
                    alreadyFound = true;
                    compareDocumentWithAnnex(doc, annex);
                }
            }
            Assert.assertTrue("annex with title " + doc.getTitle() + " was not found", alreadyFound);
        }

    }

    /**
     * @param doc
     * @param annex
     */
    private void compareDocumentWithAnnex(Document doc, PublicationAnnexType annex) {
        Assert.assertNotNull(annex.getEncryptableTitle());
        Assert.assertEquals(doc.getFilename(), annex.getDownloadFileName());
        Assert.assertEquals(doc.getMimeType(), annex.getMimeType());
        Assert.assertNotNull(annex.getDigest());
        Assert.assertNotNull(annex.getEncryptableBinaryContent());
    }

    /**
     * @param destinationContexts
     * @param destination
     */
    private void isDestinationContextPresent(List<DestinationContextType> destinationContexts, Addressee destination) {
        for (DestinationContextType idType : destinationContexts) {
            if (destination.getId().equals(idType.getId()) && destination.getType().equals(idType.getType())) {
                LOG.debug("isDestinationContextPresent : mathFound for " + destination.getId() + " " + destination.getType());
                User user = idType.getUser();
                if (user != null) {
                    Assert.assertEquals(destination.getFirstName(), user.getFirstName());
                    Assert.assertEquals(destination.getLastName(), user.getLastName());
                    Assert.assertEquals(destination.getId(), user.getValue());
                } else {
                    Assert.assertTrue(destination.getFirstName() == null || destination.getLastName() == null);
                }
                Assert.assertEquals(destination.getQuality(), idType.getQuality());
                Assert.assertEquals(destination.isOoOProcessed(), idType.isOoOProcessed().booleanValue());
                return;
            }
        }
        Assert.fail("no destinationContext found for addresee" + destination.getId());
    }


}
