/*
 * Copyright (c) Smals
 */
package be.ehealth.businessconnector.ehbox.v3;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.io.FileUtils;
import org.joda.time.DateTime;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.api.utils.SigningValue;
import be.ehealth.businessconnector.ehbox.v3.util.QualityMapper;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.idgenerator.IdGeneratorFactory;
import be.ehealth.technicalconnector.utils.IdentifierType;
import be.ehealth.technicalconnector.utils.SessionUtil;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.Message;
import be.fgov.ehealth.ehbox.core.v3.BoxIdType;
import be.fgov.ehealth.technicalconnector.tests.utils.TestPropertiesLoader;


/**
 * builds the testdata objects for unit tests for ehbox v3.
 * 
 * @author EHP
 * 
 */
public final class EhboxTestDataBuilder {


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

    /**
     * 
     */
    private static String inssUser2;

    private static String inssUser1;

    private static String inssUser3;

    private static String nihiiUser1;

    private static String professionType;

    private static String qualityUser1;

    private static String qualityUser2;

    private static String qualityUser3;

    private static String firstNameUser1;

    private static String lastNameUser1;

    private static String senderQuality;

    private static String senderid;

    private static String senderType;

    static final String LOREMIPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris porttitor lacus sit amet tellus iaculis, et gravida lacus elementum. Sed facilisis libero et feugiat vulputate. Vivamus vehicula tellus orci, ac tristique velit lobortis pellentesque. Etiam feugiat condimentum mi sit amet volutpat. Curabitur ut tristique dolor. Nullam in sapien eleifend, auctor quam non, rhoncus mauris. Suspendisse quis ligula fermentum, egestas lacus quis, blandit orci. Curabitur sed tellus condimentum, hendrerit felis ac, tristique est. Pellentesque sit amet posuere nibh, non gravida purus. Morbi ultrices lectus vitae leo egestas tincidunt.\n"
        + "Etiam mauris purus, egestas interdum mi ac, rhoncus lacinia purus. Ut sodales tellus in cursus mollis. Morbi commodo ipsum purus, non gravida tortor laoreet ac. Vivamus pharetra ante metus, et condimentum est porttitor a. Phasellus elementum eros eget ligula tincidunt, ac cursus dolor ornare. In vitae augue nibh. Nulla ac convallis lectus.";

    static {
        try {
            Properties properties = TestPropertiesLoader.getProperties("/be.ehealth.businessconnector.ehboxv3.test.properties");
            inssUser2 = properties.getProperty("test.user.niss.user2");
            inssUser1 = properties.getProperty("test.user.niss.user1");
            inssUser3 = properties.getProperty("test.user.niss.user3");
            nihiiUser1 = properties.getProperty("test.user.nihii.user1");

            qualityUser2 = properties.getProperty("test.user.quality.user2");
            qualityUser1 = properties.getProperty("test.user.quality.user1");
            qualityUser3 = properties.getProperty("test.user.quality.user3");

            firstNameUser1 = properties.getProperty("test.user.firstname.user1");
            lastNameUser1 = properties.getProperty("test.user.lastname.user1");


            professionType = properties.getProperty("session.professionType");
            senderid = properties.getProperty("test.sender.id");
            senderQuality = properties.getProperty("test.sender.quality");
            senderType = properties.getProperty("test.sender.type");
            // EHCON-463 : retrieve property for nihii number sender from session test properties + add property with quality of sender
        } catch (TechnicalConnectorException e) {
            LOG.error("failed to load testproperties : " + e.getMessage());
        }
    }


    /**
     * private Constructor , only static methods needed.
     */
    private EhboxTestDataBuilder() {
        super();
    }


    /**
     * @return the inssUser2
     */
    public static String getInssUser2() {
        return inssUser2;
    }


    /**
     * @return the inssUser1
     */
    public static String getInssUser1() {
        return inssUser1;
    }

    /**
     * @return the inssUser3
     */
    public static String getInssUser3() {
        return inssUser3;
    }

    /**
     * @return the nihiiUser1
     */
    public static String getNihiiUser1() {
        return nihiiUser1;
    }

    /**
     * @param encrypted boolean use encryption or not
     * @return
     * @throws TechnicalConnectorException
     */
    public static NewsMessage<Message> buildFullExampleNewsMessage(boolean encrypted, boolean useFreeTextTable) throws TechnicalConnectorException {
        return buildFullExampleNewsMessage(encrypted, useFreeTextTable, null);
    }

    /**
     * @param encrypted boolean , use encryption or not
     * @param sender the sender to use
     * @return
     * @throws TechnicalConnectorException
     */
    public static NewsMessage<Message> buildFullExampleNewsMessage(boolean encrypted, boolean useFreeTextTable, Addressee sender) throws TechnicalConnectorException {
        NewsMessage<Message> newsMessage = new NewsMessage<Message>();
        fillDocumentMessage(newsMessage, encrypted, useFreeTextTable, sender);
        return newsMessage;
    }

    public static DocumentMessage<Message> buildFullExampleDocumentMessage(boolean encrypted, boolean useFreeTextTable) throws TechnicalConnectorException {
        return buildFullExampleDocumentMessage(encrypted, useFreeTextTable, null);
    }

    public static DocumentMessage<Message> buildFullExampleDocumentMessage(boolean encrypted, boolean useFreeTextTable, Addressee sender) throws TechnicalConnectorException {
        DocumentMessage<Message> documentMessage = new DocumentMessage<Message>();
        fillDocumentMessage(documentMessage, encrypted, useFreeTextTable, sender);
        return documentMessage;
    }

    /**
     * @param documentMessage
     * @param sender if filled out this sender is used
     * @throws TechnicalConnectorException
     */
    @SuppressWarnings("deprecation")
    private static void fillDocumentMessage(DocumentMessage<Message> documentMessage, boolean encrypted, boolean useFreeTextTable, Addressee sender) throws TechnicalConnectorException {
        documentMessage.setDestinations(new ArrayList<Addressee>());
        // User3 is not known as nurse in accept for the moment
        documentMessage.getDestinations().add(getAdresseeUser3());
        documentMessage.getDestinations().add(getAdresseeUser2());
        documentMessage.getDestinations().add(getAdresseeUser1());
        documentMessage.getDestinations().add(getAddresseeNihiiUser1());
        documentMessage.generatePublicationId();
        documentMessage.setId(IdGeneratorFactory.getIdGenerator().generateId().substring(0, 13));
        documentMessage.setUseReceivedReceipt(true);
        DateTime now = new DateTime();
        StringBuilder senderIdBuilder = new StringBuilder("sender:");
        if (sender != null) {
            senderIdBuilder.append(sender.getId()).append("-").append(sender.getQuality()).append("-").append(sender.getType());
        } else {
            senderIdBuilder.append(":default");
        }
        documentMessage.setDocument(generateDocument("docTitle: " + senderIdBuilder.toString() + "day:" + now.getDayOfYear() + " h:" + now.getHourOfDay() + " m:" + now.getMinuteOfHour() + " s:" + now.getSecondOfMinute() + "." + now.getMillisOfSecond(), "text/xml"));
        documentMessage.setEncrypted(encrypted);
        documentMessage.setExpirationDateTime(new DateTime(989456123L)); // should be ignored
        if (useFreeTextTable) {
            documentMessage.setFreeInformationTableTitle("TEST");
            documentMessage.setFreeInformationTableRows(createStringStringHashMap());
        } else {
            documentMessage.setFreeText("freeText String " + LOREMIPSUM);
        }
        documentMessage.setHasAnnex(true);
        documentMessage.setHasFreeInformations(true);
        documentMessage.setImportant(true);
        documentMessage.setMandatee(getAdresseeUser2()); // normally this should be ignored
        documentMessage.setPatientInss(inssUser2);
        documentMessage.setSender(sender);
        documentMessage.setUsePublicationReceipt(true);
        documentMessage.setUseReadReceipt(true);
        documentMessage.setUseReceivedReceipt(true);
        documentMessage.getAnnexList().add(generateDocument("annex1", "text/xml"));
        documentMessage.getAnnexList().add(generateDocument("annex2", "text/xml"));
        documentMessage.getCopyMailTo().add("dummy@ehealth.fgov.be");
        documentMessage.getCustomMetas().put("customMetaKey1", "customMetaValue1");
        documentMessage.getCustomMetas().put("customMetaKey2", "customMetaValue2");
    }


    public static Addressee getSenderAsAddressee() {
        if (!"NIHII".equals(senderType)) {
            Assert.fail("error building testdata , getSenderAsAddressee only works for sender type NIHII, but was " + senderType);
        }
        return new Addressee(senderid, QualityType.getInstance(senderQuality, IdentifierType.NIHII));
    }

    /**
     * @return
     */
    public static Addressee getAddresseeNihiiUser1() {
        return new Addressee(nihiiUser1, QualityType.DOCTOR_NIHII);
    }

    /**
     * @return
     */
    static Addressee getAdresseeUser3() {
        return new Addressee(inssUser3, QualityType.NURSE_SSIN);
    }

    /**
     * @return
     */
    public static Addressee getAdresseeUser1() {
        Addressee addressee = new Addressee(inssUser1, QualityType.DOCTOR_SSIN);
        addressee.setFirstName(firstNameUser1);
        addressee.setLastName(lastNameUser1);
        return addressee;
    }

    /**
     * @return
     */
    public static Addressee getAdresseeAllDoctors() {
        return new Addressee("ALL", QualityType.DOCTOR_NIHII);
    }

    /**
     * @return
     */
    public static Map<String, String> createStringStringHashMap() {
        HashMap<String, String> hashMap = new HashMap<String, String>();
        hashMap.put("key1", "value1");
        hashMap.put("key2", "value2");
        return hashMap;
    }

    public static BoxIdType generateBoxId(String id, String type, String quality) {
        BoxIdType boxId = new BoxIdType();
        boxId.setId(id);
        boxId.setType(type);
        boxId.setQuality(quality);
        return boxId;
    }

    /**
     * @param id
     * @param idType
     * @param quality
     * @return
     */
    public static Addressee generateDestination(String id, IdentifierType idType, QualityType quality) {
        Addressee destination = new Addressee(id, idType);
        destination.setQuality(quality);
        return destination;
    }

    /**
     * @param builder MessageBuilder with needed properties.
     * @return
     */
    public static NewsMessage<Message> generateNewsMessage(MessageBuilder builder) {

        NewsMessage<Message> message = new NewsMessage<Message>();
        message.getDestinations().add(builder.getDestination());
        message.setEncrypted(builder.isEncrypted());
        message.setImportant(builder.isImportant());
        message.setUseReceivedReceipt(builder.isReceiveAck());
        message.setUsePublicationReceipt(builder.isPublicationAck());
        message.setUseReadReceipt(builder.isReadAck());
        message.getDocument().setMimeType(builder.getMimeType());
        message.getDocument().setTitle(builder.getTitle());
        message.getDocument().setContent(builder.getContent().getBytes());
        message.getDocument().setFilename("fileName " + builder.getTitle());

        return message;
    }

    /**
     * @param builder MessageBuilder with needed properties.
     * @return DocumentMessage<Message>
     */
    public static DocumentMessage<Message> generateDocumentMessage(MessageBuilder builder) {

        DocumentMessage<Message> message = new DocumentMessage<Message>();
        message.setDocument(generateDocument(builder.getTitle(), builder.getMimeType(), builder.getContent()));
        message.getDestinations().add(builder.getDestination());
        message.setEncrypted(builder.isEncrypted());
        message.setImportant(builder.isImportant());
        message.setUseReceivedReceipt(builder.isReceiveAck());
        message.setUsePublicationReceipt(builder.isPublicationAck());
        message.setUseReadReceipt(builder.isReadAck());

        return message;
    }

    /**
     * @param string
     * @return
     */
    public static Document generateDocument(String title, String mimeType) {
        Document document = new Document();
        document.setFilename("fileName " + title);
        document.setMimeType(mimeType);
        document.setTitle(title);
        String content = "documentContent " + LOREMIPSUM;
        document.setContent(content.getBytes());
        SigningValue signing = new SigningValue();
        signing.setSigningDownloadFileName("signingDownloadFileName");
        signing.setSigningType("signingType");
        signing.setTextSigningContent("msjklmfsdqjflmsdjf");
        document.setSigning(signing);
        return document;
    }

    /**
     * @param title
     * @param mimeType
     * @param content
     * @return
     */
    public static Document generateDocument(String title, String mimeType, String content) {
        Document document = generateDocument(title, mimeType);
        document.setContent(content.getBytes());
        return document;
    }

    /**
     * @return
     */
    public static Addressee getAdresseeUser2() {
        return new Addressee(inssUser2, QualityType.DOCTOR_SSIN);
    }

    /**
     * @return
     */
    public static BoxIdType getInssBoxIdUser1() {
        BoxIdType boxId = new BoxIdType();
        boxId.setId(inssUser1);
        boxId.setQuality(qualityUser1);
        boxId.setType("INSS");
        return boxId;
    }

    /**
     * @return
     */
    public static BoxIdType getInssBoxIdUser2() {
        BoxIdType boxId = new BoxIdType();
        boxId.setId(inssUser2);
        boxId.setQuality(qualityUser2);
        boxId.setType("INSS");
        return boxId;
    }

    /**
     * @return
     */
    public static BoxIdType getInssBoxIdUser3() {
        BoxIdType boxId = new BoxIdType();
        boxId.setId(inssUser3);
        boxId.setQuality(qualityUser3);
        boxId.setType("INSS");
        return boxId;
    }

    /**
     * @return
     */
    public static BoxIdType getRizivBoxUser1() {
        BoxIdType boxId = new BoxIdType();
        boxId.setId(nihiiUser1);
        boxId.setQuality(qualityUser1);
        boxId.setType("NIHII");
        QualityType.DENTIST_NIHII.getIdentifierType();
        return boxId;
    }

    /**
     * @return
     */
    public static BoxIdType getEhboxSender() {
        try {
            BoxIdType boxId = new BoxIdType();
            QualityMapper qualityMapper = QualityMapper.getMapper(professionType);

            boxId.setId(getIdFromSession(qualityMapper.getType()));
            // Session.getInstance().
            boxId.setQuality(qualityMapper.getQuality());
            boxId.setType(qualityMapper.getType());
            return boxId;
        } catch (Exception e) {
            LOG.error("failed to load testproperties : " + e.getMessage());
            throw new RuntimeException(e);
        }
    }


    /**
     * @param qualityMapper
     */
    private static String getIdFromSession(String type) throws TechnicalConnectorException {
        if ("INSS".equals(type)) {
            return SessionUtil.getNiss();
        } else if ("NIHII".equals(type)) {
            return SessionUtil.getNihii();
        } else if ("NIHII11".equals(type)) {
            return SessionUtil.getNihii11();
        } else {
            throw new IllegalArgumentException("Type " + type + " not authorized at this level, must be in [INSS, NIHII, NIHII11]");
        }
    }

    /**
     * @param sizeInKb
     * @return
     */
    public static Document buildDocumentWithSize(int sizeInKb) throws IOException, TechnicalConnectorException {
        Document generateDocument = generateDocument("document with size " + sizeInKb + " kB", "text/xml");
        File tempFile = File.createTempFile("someLargfileForEhboxAttachment", "txt");
        tempFile.deleteOnExit();
        final FileOutputStream openOutputStream = FileUtils.openOutputStream(tempFile, true);
        final byte[] someBytesToUse = LOREMIPSUM.getBytes();
        int numberOftimestoAddBytes = (sizeInKb * 1024) / someBytesToUse.length;
        for (int i = 0; i < numberOftimestoAddBytes; i++) {
            openOutputStream.write(someBytesToUse);
            if (i % 10 == 0) {
                openOutputStream.flush();
            }
        }
        openOutputStream.flush();
        openOutputStream.close();

        generateDocument.setContent(FileUtils.openInputStream(tempFile));
        return generateDocument;
    }
}
