/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.therlink.util;

import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_PATIENT_OFFL_EID;
import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_PATIENT_OFFL_FIRSTN;
import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_PATIENT_OFFL_LASTN;
import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_PATIENT_OFFL_NISS;
import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_PATIENT_OFFL_SIS;
import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_REFERRAL_DOCTOR_NISS;
import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_REFERRAL_NURSE_NISS;
import static be.ehealth.businessconnector.therlink.util.TestConstants.PROP_REFERRAL_PHARMACIST_NISS;
import static be.ehealth.businessconnector.therlink.util.TestConstants.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.joda.time.DateTime;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import be.ehealth.business.common.domain.Patient;
import be.ehealth.business.kmehrcommons.HcPartyUtil;
import be.ehealth.businessconnector.therlink.builders.ProofBuilder;
import be.ehealth.businessconnector.therlink.builders.RequestObjectBuilderFactory;
import be.ehealth.businessconnector.therlink.domain.HcParty;
import be.ehealth.businessconnector.therlink.domain.Proof;
import be.ehealth.businessconnector.therlink.domain.ProofTypeValues;
import be.ehealth.businessconnector.therlink.domain.TherapeuticLink;
import be.ehealth.businessconnector.therlink.domain.requests.GetTherapeuticLinkRequest;
import be.ehealth.businessconnector.therlink.domain.requests.PutTherapeuticLinkRequest;
import be.ehealth.businessconnector.therlink.domain.requests.RevokeTherapeuticLinkRequest;
import be.ehealth.businessconnector.therlink.domain.requests.TherapeuticLinkStatus;
import be.ehealth.businessconnector.therlink.domain.responses.Acknowledge;
import be.ehealth.businessconnector.therlink.domain.responses.GetTherapeuticLinkResponse;
import be.ehealth.businessconnector.therlink.domain.responses.PutTherapeuticLinkResponse;
import be.ehealth.businessconnector.therlink.domain.responses.RevokeTherapeuticLinkResponse;
import be.ehealth.businessconnector.therlink.domain.responses.TherapeuticLinkResponse;
import be.ehealth.businessconnector.therlink.domain.responses.TherapeuticLinkResponseError;
import be.ehealth.businessconnector.therlink.exception.TherLinkBusinessConnectorException;
import be.ehealth.businessconnector.therlink.mappers.MapperFactory;
import be.ehealth.businessconnector.therlink.mappers.RequestObjectMapper;
import be.ehealth.businessconnector.therlink.service.impl.AbstractTherlinkIsolationIntegrationTest;
import be.ehealth.businessconnector.therlink.session.TherlinkSessionServiceFactory;
import be.ehealth.technicalconnector.beid.BeIDInfo;
import be.ehealth.technicalconnector.beid.domain.Identity;
import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.exception.ConnectorException;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.service.sts.security.impl.BeIDCredential;
import be.fgov.ehealth.technicalconnector.tests.utils.TestPropertiesLoader;

/**
 * contains utility methods for therlink tests.
 * 
 * @author EHP
 * 
 */
public class TherlinkTestUtils {

    private static final String BEID_SCOPE = "tests";

    private static final Logger LOGGER = LoggerFactory.getLogger(TherlinkTestUtils.class);

    private static Properties props;

    // cached items
    private static Patient offlinePatient;

    // cached info from eid card
    private static Proof eidSigningProof;

    private static Patient patientFromEid;

    private static ProofBuilder proofBuilder;

    private static RequestObjectMapper requestObjectMapper;


    private static be.ehealth.businessconnector.therlink.session.TherLinkService therlinkWS;


    static {
        try {
            props = TestPropertiesLoader.getProperties(TestConstants.THERLINK_TEST_PROPERTIES);
            // SessionInitializer.init(TestConstants.THERLINK_TEST_PROPERTIES);
            proofBuilder = RequestObjectBuilderFactory.getProofBuilder();
            requestObjectMapper = MapperFactory.getRequestObjectMapper();

        } catch (Exception e) {
            Assert.fail("error setting up test utils : " + e.getMessage());
        }
    }

    /**
     * @return
     */
    public static TherapeuticLinkTypeValues getTherapeuticLinkTypeValue() {
        return TherapeuticLinkTypeValues.valueOf(ConfigFactory.getConfigValidator().getProperty("kmehr.single.hcparty.template.careprovider.in.therapeuticlink.cd.cdhcparty.value").toUpperCase());
    }

    public static String getReferralTypeToUse() {
        return getTherapeuticLinkTypeValue().getReferral();
    }

    private static be.ehealth.businessconnector.therlink.session.TherLinkService getTherlinkWs() throws ConnectorException {
        if (therlinkWS == null) {
            therlinkWS = TherlinkSessionServiceFactory.getTherlinkService();
        }
        return therlinkWS;
    }

    public static void revokeReferralsForEidPatient(List<HcParty> allPossibleReferralParties) throws InstantiationException, ConnectorException {
        for (HcParty hcParty : allPossibleReferralParties) {
            TherapeuticLink queryLink = new TherapeuticLink.Builder().withHcParty(hcParty).withPatient(getPatientFromEid()).withStatus(TherapeuticLinkStatus.ACTIVE).build();
            List<TherapeuticLink> allTherapeuticLinks = getAllTherapeuticLinksWithQueryLink(queryLink, getEidSigningProof());
            revokeAllLinks(allTherapeuticLinks, getEidSigningProof(), getPatientFromEid());
        }
        // revoking needs eid signing with pin code, so only for patient which has eid card in pc
    }

    /**
     * @param queryTherlink
     * @param proof
     * @throws TechnicalConnectorException
     * @throws TherLinkBusinessConnectorException
     * @throws InstantiationException
     * @throws ConnectorException
     */
    private static void revokeAllLinks(List<TherapeuticLink> listOfTherapeuticLinks, Proof proof, Patient patient) throws TechnicalConnectorException, TherLinkBusinessConnectorException, InstantiationException, ConnectorException {
        if (listOfTherapeuticLinks != null) {
            LOGGER.debug("revoking " + listOfTherapeuticLinks.size() + " links");
            for (TherapeuticLink retrievedLink : listOfTherapeuticLinks) {
                retrievedLink.setPatient(fillTherlinkPatientWithCorrectDataForProof(retrievedLink.getPatient(), patient, proof));
                RevokeTherapeuticLinkRequest revokeTherapeuticLinkRequest = RequestObjectBuilderFactory.getRequestObjectBuilder().createRevokeTherapeuticLinkRequest(retrievedLink.getStartDate().toDateTimeAtStartOfDay(), retrievedLink.getEndDate().toDateTimeAtStartOfDay(), retrievedLink.getPatient(), retrievedLink.getHcParty(), retrievedLink.getType(), "revokeAllLinks : therlink to revoke existing link ", proof);
                be.fgov.ehealth.hubservices.core.v2.RevokeTherapeuticLinkResponse revokeTherapeuticLinkResponse = getTherlinkWs().revokeTherapeuticLink(requestObjectMapper.mapRevokeTherapeuticLinkRequest(revokeTherapeuticLinkRequest));
                // ignore error messages with 'no therapeutic link found' = NIP.META.TlServiceBean
                List<String> errorsToIgnore = new ArrayList<String>();
                errorsToIgnore.add("NIP.META.TlServiceBean");
                validateAcknowledge(null, MapperFactory.getResponseObjectMapper().mapAcknowledge(revokeTherapeuticLinkResponse.getAcknowledge()), errorsToIgnore);
            }
        }
    }

    public static Patient fillTherlinkPatientWithOfflinePatientDataForProof(Proof proof) {
        return fillTherlinkPatientWithCorrectDataForProof(getOfflinePatient(), getOfflinePatient(), proof);
    }

    /**
     * @param retrievedLink
     * @param patient
     * @param templatePatient : optional , if not given the standard offlinePatient will be expected. the operation will fail if another
     *        patient is used as input!!!
     */
    private static Patient fillTherlinkPatientWithCorrectDataForProof(Patient therlinkPatient, Patient templatePatient, Proof proof) {
        LOGGER.debug("replacing patient in therlink with data from templatePatient");
        if (therlinkPatient == null || therlinkPatient.getInss() == null) {
            throw new IllegalArgumentException("the therlink , its patient and the niss number should be filled out!");
        }
        if (templatePatient == null) {
            templatePatient = getOfflinePatient();
        }
        if (templatePatient == null || templatePatient.getInss() == null) {
            throw new IllegalArgumentException("the patient to use as template and its niss should be filled out!!");
        }
        if (!templatePatient.getInss().equals(therlinkPatient.getInss())) {
            throw new IllegalArgumentException("templatePatient is not for same niss number!!");
        }
        Patient patientToUse = new Patient.Builder().withFamilyName(templatePatient.getLastName()).withFirstName(templatePatient.getFirstName()).withInss(templatePatient.getInss()).build();

        if (proof.getType().equals(ProofTypeValues.EIDREADING.getValue())) {
            String cardNumber = templatePatient.getEidCardNumber();
            checkNotNull(cardNumber, ProofTypeValues.EIDREADING);
            patientToUse.setEidCardNumber(cardNumber);
        } else if (proof.getType().equals(ProofTypeValues.ISIREADING.getValue())) {
            String cardNumber = templatePatient.getIsiCardNumber();
            checkNotNull(cardNumber, ProofTypeValues.ISIREADING);
            patientToUse.setIsiCardNumber(cardNumber);
        } else if (proof.getType().equals(ProofTypeValues.SISREADING.getValue())) {
            String cardNumber = templatePatient.getSisCardNumber();
            checkNotNull(cardNumber, ProofTypeValues.SISREADING);
            patientToUse.setSisCardNumber(cardNumber);
        } else if (proof.getType().equals(ProofTypeValues.EIDSIGNING.getValue())) {
            String cardNumber = templatePatient.getEidCardNumber();
            checkNotNull(cardNumber, ProofTypeValues.EIDSIGNING);
            patientToUse.setEidCardNumber(cardNumber);
        } else {
            throw new UnsupportedOperationException("fillTherlinkPatientWithCorrectDataForProof : unsupported proofType " + proof.getType());
        }
        return patientToUse;
    }

    /**
     * @param eidCardNumber
     * @param eidreading
     */
    private static void checkNotNull(String cardNumber, ProofTypeValues eidreading) {
        if (cardNumber == null) {
            throw new IllegalArgumentException(" the template patient used is missing the required cardNumber for Proof " + eidreading.getValue());
        }
    }

    public static void revokeNonReferrals(Patient patient) throws TherLinkBusinessConnectorException, InstantiationException, ConnectorException {
        Proof proofForEidReading = proofBuilder.createProofForEidReading();
        revokeNonReferrals(patient, proofForEidReading);
    }

    /**
     * @param patient
     * @param proof
     * @throws TechnicalConnectorException
     * @throws TherLinkBusinessConnectorException
     * @throws InstantiationException
     * @throws ConnectorException
     */
    public static void revokeNonReferrals(Patient patient, Proof proof) throws TechnicalConnectorException, TherLinkBusinessConnectorException, InstantiationException, ConnectorException {
        TherapeuticLink queryLink = new TherapeuticLink.Builder().withHcParty(ConfigReader.getCareProvider()).withPatient(patient).withStatus(TherapeuticLinkStatus.ACTIVE).build();
        List<TherapeuticLink> allTherapeuticLinks = getAllTherapeuticLinksWithQueryLink(queryLink, proof);
        revokeAllLinks(allTherapeuticLinks, proof, patient);
    }

    public static List<TherapeuticLink> getAllTherapeuticLinks(HcParty author, Patient patient, String type, Proof proof) throws InstantiationException, ConnectorException {
        return getAllTherapeuticLinks(author, patient, null, null, type, proof);
    }

    public static List<TherapeuticLink> getAllTherapeuticLinks(HcParty author, Patient patient, DateTime startDate, DateTime endTime, String type, Proof proof) throws InstantiationException, ConnectorException {
        TherapeuticLink queryLink = new TherapeuticLink.Builder().withHcParty(author).withPatient(patient).withStartDateTime(startDate).withEndDateTime(endTime).withStatus(TherapeuticLinkStatus.ALL).withType(type).build();
        return getAllTherapeuticLinksWithQueryLink(queryLink, proof);
    }

    /**
     * @param proof
     * @param queryLink
     * @return
     * @throws TechnicalConnectorException
     * @throws TherLinkBusinessConnectorException
     * @throws InstantiationException
     * @throws ConnectorException
     */
    private static List<TherapeuticLink> getAllTherapeuticLinksWithQueryLink(TherapeuticLink queryLink, Proof proof) throws TechnicalConnectorException, TherLinkBusinessConnectorException, InstantiationException, ConnectorException {
        queryLink.setPatient(fillTherlinkPatientWithCorrectDataForProof(queryLink.getPatient(), queryLink.getPatient(), proof));
        GetTherapeuticLinkRequest createGetTherapeuticLinkRequest = RequestObjectBuilderFactory.getRequestObjectBuilder().createGetTherapeuticLinkRequest(queryLink, proof);
        be.fgov.ehealth.hubservices.core.v2.GetTherapeuticLinkResponse response = getTherlinkWs().getTherapeuticLink(requestObjectMapper.mapGetTherapeuticLinkRequest(createGetTherapeuticLinkRequest));
        GetTherapeuticLinkResponse mappedGetTherapeuticLinkResponse = MapperFactory.getResponseObjectMapper().mapJaxbToGetTherapeuticLinkResponse(response);
        validateAcknowledge(null, mappedGetTherapeuticLinkResponse.getAcknowledge());
        List<TherapeuticLinkResponse> listOfTherapeuticLinks = mappedGetTherapeuticLinkResponse.getListOfTherapeuticLinks();

        ArrayList<TherapeuticLink> result = new ArrayList<TherapeuticLink>();
        if (listOfTherapeuticLinks != null) {
            result.addAll(listOfTherapeuticLinks);
        }
        return result;
    }

    public static Patient getOfflinePatient() {
        if (offlinePatient == null) {
            offlinePatient = new Patient.Builder().withSis(props.getProperty(PROP_PATIENT_OFFL_SIS)).withEid(props.getProperty(PROP_PATIENT_OFFL_EID)).withFamilyName(props.getProperty(PROP_PATIENT_OFFL_LASTN)).withFirstName(props.getProperty(PROP_PATIENT_OFFL_FIRSTN)).withInss(props.getProperty(PROP_PATIENT_OFFL_NISS)).build();
        }
        return offlinePatient;
    }

    public static void logTherapeuticLinks(List<TherapeuticLink> links) {
        for (TherapeuticLink therapeuticLink : links) {
            if (therapeuticLink != null) {
                LOGGER.debug(" therapeuticLink:" + therapeuticLink);

            }
        }
    }

    public static Proof getEidSigningProof() throws TechnicalConnectorException, TherLinkBusinessConnectorException, InstantiationException {
        if (eidSigningProof == null) {
            synchronized (AbstractTherlinkIsolationIntegrationTest.class) {
                if (eidSigningProof == null) {
                    eidSigningProof = RequestObjectBuilderFactory.getProofBuilder().createProofForEidSigning(BeIDCredential.getInstance(BEID_SCOPE, "Signature"));
                }
            }
        }
        return eidSigningProof;
    }

    public static Patient getPatientFromEid() throws TechnicalConnectorException {
        if (patientFromEid == null) {
            Identity identity = BeIDInfo.getInstance(BEID_SCOPE).getIdentity();
            return new Patient.Builder().withEid(identity.getCardNumber()).withFamilyName(identity.getName()).withFirstName(identity.getFirstName()).withMiddleName(identity.getMiddleName()).withInss(identity.getNationalNumber()).build();
        }
        return patientFromEid;
    }

    public static HcParty getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues therlinkType) throws TherLinkBusinessConnectorException {
        TherapeuticLinkTypeValues therapeuticLinkTypeValue = getTherapeuticLinkTypeValue();
        if (TherapeuticLinkTypeValues.PERSNURSE.equals(therapeuticLinkTypeValue)) {
            return new HcParty.Builder().withType("persnurse").withInss(props.getProperty(PROP_REFERRAL_NURSE_NISS)).build();
        }
        if (TherapeuticLinkTypeValues.PERSPHYSICIAN.equals(therapeuticLinkTypeValue)) {
            return new HcParty.Builder().withType("persphysician").withInss(props.getProperty(PROP_REFERRAL_DOCTOR_NISS)).build();
        }
        if (TherapeuticLinkTypeValues.ORGPHARMACY.equals(therapeuticLinkTypeValue)) {
            return new HcParty.Builder().withType("orgpharmacy").withNihii(props.getProperty(PROP_REFERRAL_PHARMACY_NIHII)).build();
        }
        if (TherapeuticLinkTypeValues.PERSDENTIST.equals(therapeuticLinkTypeValue)) {
            return new HcParty.Builder().withType("persdentist").withNihii(props.getProperty(PROP_REFERRAL_DENTIST_NIHII)).build();
        }
        throw new IllegalArgumentException("getReferralHcPartyForTherlinkType is not configured yet for type " + therapeuticLinkTypeValue);

    }

    public static List<HcParty> getReferralsToTest() throws TherLinkBusinessConnectorException {
        TherapeuticLinkTypeValues therapeuticLinkTypeValue = getTherapeuticLinkTypeValue();
        List<HcParty> referralsToTest = new ArrayList<HcParty>();
        if (TherapeuticLinkTypeValues.PERSNURSE.equals(therapeuticLinkTypeValue)) {
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.PERSNURSE));
            return referralsToTest;
        } else if (TherapeuticLinkTypeValues.PERSMIDWIFE.equals(therapeuticLinkTypeValue)) {
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.PERSMIDWIFE));
            return referralsToTest;
        } else if (TherapeuticLinkTypeValues.ORGPHARMACY.equals(therapeuticLinkTypeValue)) {
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.ORGPHARMACY));
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.PERSPHYSICIAN));
            return referralsToTest;
        } else if (TherapeuticLinkTypeValues.PERSPHYSICIAN.equals(therapeuticLinkTypeValue)) {
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.PERSPHYSICIAN));
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.PERSNURSE));
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.ORGPHARMACY));
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.SPECIALIST));

            return referralsToTest;
        } else if (TherapeuticLinkTypeValues.PERSDENTIST.equals(therapeuticLinkTypeValue)) {
            referralsToTest.add(getReferralHcPartyForTherlinkType(TherapeuticLinkTypeValues.PERSDENTIST));

            return referralsToTest;
        }
        throw new IllegalArgumentException("choosReferralNissNumberBasedOnCurrentProfessionalType : therapeuticLinkTypeValue " + therapeuticLinkTypeValue + " not configured yet !!!");
    }

    public static String choosReferralNissNumberBasedOnCurrentProfessionalType() {
        TherapeuticLinkTypeValues therapeuticLinkTypeValue = getTherapeuticLinkTypeValue();
        if (TherapeuticLinkTypeValues.PERSNURSE.equals(therapeuticLinkTypeValue)) {
            return props.getProperty(PROP_REFERRAL_NURSE_NISS);
        } else if (TherapeuticLinkTypeValues.PERSPHYSICIAN.equals(therapeuticLinkTypeValue)) {
            return props.getProperty(PROP_REFERRAL_DOCTOR_NISS);
        }
        throw new IllegalArgumentException("choosReferralNissNumberBasedOnCurrentProfessionalType : therapeuticLinkTypeValue " + therapeuticLinkTypeValue + " not configured yet !!!");
    }

    // public static TherapeuticLinkTypeValues getTherapeuticLinkTypeValue() {
    // return getTherapeuticLinkType();;
    // }

    /**
     * Is the link well created?
     * 
     */
    public static boolean doesLinkExist(TherapeuticLink therlink) throws InstantiationException, ConnectorException {
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            LOGGER.error("thread interupted " + e.getMessage());
        }
        if (therlink == null) {
            throw new IllegalArgumentException("checkLinkIsCreated received invalid therlink object " + therlink);
        }
        List<TherapeuticLink> allTherapeuticLinks = getAllTherapeuticLinksWithQueryLink(therlink, proofBuilder.createProofForEidReading());
        Assert.assertNotNull(allTherapeuticLinks);
        return (allTherapeuticLinks.size() == 1);
    }

    /**
     * Is the link well revoked?
     * 
     */
    protected void checkLinkRevoked(TherapeuticLink link) throws InstantiationException, ConnectorException {
        GetTherapeuticLinkRequest createGetTherapeuticLinkRequest = RequestObjectBuilderFactory.getRequestObjectBuilder().createGetTherapeuticLinkRequest(link, (Proof[]) null);

        be.fgov.ehealth.hubservices.core.v2.GetTherapeuticLinkRequest mapGetTherapeuticLinkRequest = requestObjectMapper.mapGetTherapeuticLinkRequest(createGetTherapeuticLinkRequest);
        GetTherapeuticLinkResponse getResponse = MapperFactory.getResponseObjectMapper().mapJaxbToGetTherapeuticLinkResponse(getTherlinkWs().getTherapeuticLink(mapGetTherapeuticLinkRequest));

        if (getResponse.getAcknowledge().isComplete()) {
            if (getResponse.getListOfTherapeuticLinks().size() > 0) {
                Assert.fail("Revoke didn't work");
            } else {
                LOGGER.warn("List size : " + getResponse.getListOfTherapeuticLinks().size());
            }
        } else {
            extractAndAssertErrorMessage(getResponse.getAcknowledge(), null, new ArrayList<String>());
        }
    }

    /**
     * @param expectedErrorCode
     * @param proof
     * @param patient
     * @param hcParty
     * @return
     * @throws TechnicalConnectorException
     * @throws TherLinkBusinessConnectorException
     * @throws InstantiationException
     */
    public static PutTherapeuticLinkResponse putTherapeuticLinkNonReferral(Patient patient, HcParty hcParty, DateTime endDate, Proof proof, String expectedErrorCode) throws InstantiationException, ConnectorException {
        Patient patientToUse = chooseOfflinePatientIfPossible(patient, proof);
        PutTherapeuticLinkRequest createPutTherapeuticLinkRequest = RequestObjectBuilderFactory.getRequestObjectBuilder().createPutTherapeuticLinkRequest(endDate, patientToUse, hcParty, getTherapeuticLinkTypeValue().getTherlinkType(), "therlink test", proof);
        be.fgov.ehealth.hubservices.core.v2.PutTherapeuticLinkRequest mapPutTherapeuticLinkRequest = requestObjectMapper.mapPutTherapeuticLinkRequest(createPutTherapeuticLinkRequest);
        PutTherapeuticLinkResponse putResponse = MapperFactory.getResponseObjectMapper().mapJaxbToPutTherapeuticLinkResponse(getTherlinkWs().putTherapeuticLink(mapPutTherapeuticLinkRequest));

        validateResponse(expectedErrorCode, putResponse);
        return putResponse;
    }

    /**
     * @param patient
     * @param proof
     * @return
     */
    private static Patient chooseOfflinePatientIfPossible(Patient patient, Proof proof) {
        Patient offlinePatientWithCorrectProperties = fillTherlinkPatientWithOfflinePatientDataForProof(proof);
        if (patient != null) {
            if (!offlinePatientWithCorrectProperties.getInss().equals(patient.getInss())) {
                return patient;
            }
        }
        return offlinePatientWithCorrectProperties;
    }

    /**
     * @param expectedErrorCode
     * @param putResponse
     */
    public static void validateResponse(String expectedErrorCode, PutTherapeuticLinkResponse putResponse) {
        Acknowledge acknowledge = putResponse.getAcknowledge();
        validateAcknowledge(expectedErrorCode, acknowledge);
    }

    /**
     * @param expectedErrorCode
     * @param acknowledge
     */
    private static void validateAcknowledge(String expectedErrorCode, Acknowledge acknowledge) {
        validateAcknowledge(expectedErrorCode, acknowledge, null);
    }

    /**
     * @param expectedErrorCode
     * @param acknowledge
     */
    private static void validateAcknowledge(String expectedErrorCode, Acknowledge acknowledge, List<String> errorsToIgnore) {
        if (acknowledge.isComplete()) {
            LOGGER.info(">>> Therapeutic link created");
            if (expectedErrorCode != null) {
                Assert.fail("expected error with code " + expectedErrorCode + ", but no errors returned");
            }
        } else {
            extractAndAssertErrorMessage(acknowledge, expectedErrorCode, errorsToIgnore);
        }
    }


    /**
     * Gets all the existing links between the current patient and the given hcParty, and revoke them all
     * 
     * Used to initialise this test
     */
    protected static void revokeLinksInit(HcParty hcp) throws InstantiationException, ConnectorException {
        // Retrieve all the links
        Patient patient = TherlinkTestUtils.getPatientFromEid();
        TherapeuticLink createTherapeuticLink = RequestObjectBuilderFactory.getCommonBuilder().createTherapeuticLink(null, null, patient, HcPartyUtil.getAuthorKmehrQuality(), null, null, hcp);
        GetTherapeuticLinkRequest createDefaultGetTherapeuticLinkRequest = new GetTherapeuticLinkRequest(new DateTime(), RequestObjectBuilderFactory.getCommonBuilder().createKmehrID(), RequestObjectBuilderFactory.getCommonBuilder().createAuthor(RequestObjectBuilderFactory.getRequestObjectBuilder().getAuthorHcParties()), createTherapeuticLink, RequestObjectBuilderFactory.getRequestObjectBuilder().getMaxRows(), TherlinkTestUtils.getEidSigningProof());

        be.fgov.ehealth.hubservices.core.v2.GetTherapeuticLinkRequest mapGetTherapeuticLinkRequest = requestObjectMapper.mapGetTherapeuticLinkRequest(createDefaultGetTherapeuticLinkRequest);
        be.fgov.ehealth.hubservices.core.v2.GetTherapeuticLinkResponse therapeuticLinkresponse = getTherlinkWs().getTherapeuticLink(mapGetTherapeuticLinkRequest);
        GetTherapeuticLinkResponse resp = MapperFactory.getResponseObjectMapper().mapJaxbToGetTherapeuticLinkResponse(therapeuticLinkresponse);

        if (!resp.getAcknowledge().isComplete()) {
            // if the therapeutic link did not exist (=TL.ACCESS.09) , let it go
            extractAndAssertErrorMessage(resp.getAcknowledge(), "TL.ACCESS.09", new ArrayList<String>());
        }

        if (resp.getListOfTherapeuticLinks() != null && resp.getListOfTherapeuticLinks().size() > 0) {
            // Revoke existing links
            LOGGER.info(">>> Revoke existing therapeutic links");
            for (TherapeuticLink therLink : resp.getListOfTherapeuticLinks()) {
                LOGGER.info(">>> " + therLink.toString());
                Patient patientFromTherapeuticLink = therLink.getPatient();
                // add eidcard number to retrieved therapeutic link, so revoke with eidReading is possible
                if (patientFromTherapeuticLink.getInss().equals(patient.getInss())) {
                    patientFromTherapeuticLink.setEidCardNumber(patient.getEidCardNumber());
                }
                RevokeTherapeuticLinkRequest createRevokeTherapeuticLinkRequest = RequestObjectBuilderFactory.getRequestObjectBuilder().createRevokeTherapeuticLinkRequestWithProof(therLink, TherlinkTestUtils.getEidSigningProof());

                be.fgov.ehealth.hubservices.core.v2.RevokeTherapeuticLinkRequest mapRevokeTherapeuticLinkRequest = requestObjectMapper.mapRevokeTherapeuticLinkRequest(createRevokeTherapeuticLinkRequest);

                RevokeTherapeuticLinkResponse response = MapperFactory.getResponseObjectMapper().mapJaxbToRevokeTherapeuticLinkResponse(getTherlinkWs().revokeTherapeuticLink(mapRevokeTherapeuticLinkRequest));

                if (response.getAcknowledge().isComplete()) {
                    LOGGER.info(">>> Link revoked");
                } else {
                    extractAndAssertErrorMessage(response.getAcknowledge(), null, new ArrayList<String>());
                }
            }
        } else {
            LOGGER.info(">>> No existing therapeutic link");
        }
    }

    /**
     * Extracts error messages from an acknowledge
     */
    protected static void extractErrorMessage(Acknowledge response) {
        extractAndAssertErrorMessage(response, null, new ArrayList<String>());
    }

    /**
     * Extracts error messages from an acknowledge
     */
    protected static void extractErrorMessage(Acknowledge response, String expectedErrorCode) {
        extractAndAssertErrorMessage(response, expectedErrorCode, new ArrayList<String>());
    }

    public static void logErrorMessages(Acknowledge acknowledge) {
        StringBuilder sb = new StringBuilder("acknowledge received : " + acknowledge.getListOfErrors().size() + " errors:");
        for (TherapeuticLinkResponseError error : acknowledge.getListOfErrors()) {
            sb.append("\n\t>>> Error code: " + error.getErrorCode());
            sb.append("\t>>> Error description : " + error.getErrorDescription());
        }
        LOGGER.debug(sb.toString());
    }

    /**
     * Extracts error messages from an acknowledge
     */
    public static void extractAndAssertErrorMessage(Acknowledge response, String expectedErrorCode) {
        extractAndAssertErrorMessage(response, expectedErrorCode, new ArrayList<String>());
    }

    /**
     * Extracts error messages from an acknowledge
     */
    public static void extractAndAssertErrorMessage(Acknowledge response, String expectedErrorCode, List<String> errorsToIgnore) {
        StringBuilder errorList = new StringBuilder("List of Errors: ");

        boolean errorCodeFound = false;
        for (TherapeuticLinkResponseError error : response.getListOfErrors()) {
            if (expectedErrorCode != null && expectedErrorCode.equals(error.getErrorCode())) {
                errorCodeFound = true;
                errorList.append("\n\t>>>  expected Error code: ");
            } else {
                errorList.append("\n\t>>> Error code: ");
            }
            errorList.append(error.getErrorCode());
            errorList.append("\t>>> Error description : " + error.getErrorDescription());
        }
        boolean areErrorsToBeIgnored = areErrorsToBeIgnored(response.getListOfErrors(), errorsToIgnore);
        if (expectedErrorCode == null) {
            if (!areErrorsToBeIgnored) {
                Assert.fail(">>> An error occured : " + errorList.toString());
            }
        } else {
            Assert.assertTrue("there were errors , but none with errorCode " + expectedErrorCode + " errors found : " + errorList.toString(), errorCodeFound);
        }
    }

    /**
     * @param listOfErrors
     * @param errorsToIgnore
     * @return
     */
    private static boolean areErrorsToBeIgnored(List<TherapeuticLinkResponseError> listOfErrors, List<String> errorsToIgnore) {
        if (errorsToIgnore == null) {
            return listOfErrors.isEmpty();
        }
        for (TherapeuticLinkResponseError responseError : listOfErrors) {
            boolean ignoreError = false;
            for (String errorString : errorsToIgnore) {
                if (errorString != null && errorString.equals(responseError.getErrorCode())) {
                    ignoreError = true;
                    break;
                }
            }
            if (!ignoreError) {
                return false;
            }
        }
        return true;
    }

}
