package be.ehealth.businessconnector.hub.session;

import java.util.Properties;

import org.joda.time.DateTime;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;

import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.config.Configuration;
import be.ehealth.technicalconnector.config.impl.ConfigurationModuleProxy;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.idgenerator.IdGeneratorFactory;
import be.ehealth.technicalconnector.session.Session;
import be.ehealth.technicalconnector.utils.MarshallerHelper;
import be.ehealth.technicalconnector.utils.SessionUtil;
import be.fgov.ehealth.hubservices.core.v1.ConsentType;
import be.fgov.ehealth.hubservices.core.v1.HCPartyIdType;
import be.fgov.ehealth.hubservices.core.v1.PatientIdType;
import be.fgov.ehealth.hubservices.core.v1.TherapeuticLinkType;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDCONSENT;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDCONSENTschemes;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDCONSENTvalues;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDHCPARTY;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDHCPARTYschemes;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDHCPARTYvalues;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDSTANDARD;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDTHERAPEUTICLINK;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDTHERAPEUTICLINKschemes;
import be.fgov.ehealth.standards.kmehr.id.v1.IDHCPARTY;
import be.fgov.ehealth.standards.kmehr.id.v1.IDHCPARTYschemes;
import be.fgov.ehealth.standards.kmehr.id.v1.IDKMEHR;
import be.fgov.ehealth.standards.kmehr.id.v1.IDKMEHRschemes;
import be.fgov.ehealth.standards.kmehr.id.v1.IDPATIENT;
import be.fgov.ehealth.standards.kmehr.id.v1.IDPATIENTschemes;
import be.fgov.ehealth.standards.kmehr.schema.v1.AuthorType;
import be.fgov.ehealth.standards.kmehr.schema.v1.HcpartyType;
import be.fgov.ehealth.standards.kmehr.schema.v1.HeaderType;
import be.fgov.ehealth.standards.kmehr.schema.v1.PersonType;
import be.fgov.ehealth.standards.kmehr.schema.v1.RecipientType;
import be.fgov.ehealth.standards.kmehr.schema.v1.SenderType;
import be.fgov.ehealth.standards.kmehr.schema.v1.StandardType;
import be.fgov.ehealth.standards.kmehr.schema.v1.TransactionType;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;
import be.fgov.ehealth.technicalconnector.tests.utils.TestPropertiesLoader;

/**
 * Class that will encapsulate methods that will create the information needed for the test.
 * 
 * @author EH054
 */
public abstract class AbstractIntrahubIntegrationTest {

    private static Configuration technicalConfig;

    /*
     * Hub Informations
     */

    /**
     * Hub ID value for RSW hub.
     */
    public static final String HUBID_RSW = "1990000035";

    /**
     * Hub ID value for VZNKUL hub.
     */
    public static final String HUBID_VZNKUL = "1990000827";

    /**
     * Hub ID value for COZO hub.
     */
    public static final String HUBID_COZO = "1990000134";

    /**
     * Hub ID value for ARH hub.
     */
    public static final String HUBID_ARH = "1990000233";

    /**
     * URL to contact for RSW hub.
     */
    public static final String URL_RSW = "https://hub.reseausantewallon.be/standards/hubservices/intrahub/intrahubservice.asmx";

    /**
     * URL to contact for VZNKUL hub.
     */
    public static final String URL_VZNKUL = "https://hubacc.vznkul.be/services/acceptance/intrahub/IntraHubService";

    /**
     * URL to contact for COZO hub.
     */
    public static final String URL_COZO = "https://servicestest.cozo.be/IntrahubServiceTest/service.asmx";

    /**
     * URL to contact for ARH hub.
     */
    public static final String URL_ARH = "https://test.antwerpseregionalehub.be/IntrahubService/service.asmx?wsdl";

    protected static final String HUB_ID = "hub.id";

    protected static final String ENDPOINT_HUB_INTRA = "endpoint.hub.intra";

    /*
     * Patient Informations
     */
    protected static final String PATIENT_INSS = "91121208397";

    protected static final String PATIENT_CARDNO = "591559638269";

    protected static final String PATIENT_FIRSTNAME = "Guillaume";

    protected static final String PATIENT_LASTNAME = "Strauven";

    /*
     * Professional Information The nihii is found in the session
     */
    protected static final String PROF_INSS = "82051234978";


    protected static final String PROF_FIRSTNAME = "Hannes";

    protected static final String PROF_LASTNAME = "De Clercq";

    protected static final String PROF_PROFESSION = CDHCPARTYvalues.PERSPHYSICIAN.value();

    /*
     * Other informations
     */
    protected static final String CHOSENHUB_NAME = "RSW";

    protected static final String CHOSENHUB_ID = HUBID_RSW;

    protected static final String CHOSENHUB_URL = URL_RSW;

    protected static final String MESSAGE_ID = "1";

    protected static final String SV_ID = "1.0";

    protected static final String SV_CD = "1.0";

    protected static Properties props;

    protected static HubServiceComplete hubServiceComplete;

    protected static String transactionId;

    @BeforeClass
    public static void init() throws Exception {
        SessionInitializer.init("/be.ehealth.businessconnector.intrahub.test.properties");
        props = TestPropertiesLoader.getProperties("/be.ehealth.businessconnector.intrahub.test.properties");

        technicalConfig = ConfigFactory.getConfigValidator().getConfig();
        new ConfigurationModuleProxy().init(technicalConfig);

        initHub(CHOSENHUB_ID);
        hubServiceComplete = HubSessionServiceFactory.getHubServiceComplete();
    }

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

    @Before
    public void initTransactionId() throws TechnicalConnectorException {
        transactionId = IdGeneratorFactory.getIdGenerator(IdGeneratorFactory.UUID).generateId();
    }

    /**
     * Initialise properties with VZNKUL hub values
     */
    private static void initHub(String hubid) {
        if (HUBID_RSW.equalsIgnoreCase(hubid)) {
            technicalConfig.setProperty(ENDPOINT_HUB_INTRA, URL_RSW);
            props.setProperty(HUB_ID, HUBID_RSW);
        } else if (HUBID_VZNKUL.equalsIgnoreCase(hubid)) {
            technicalConfig.setProperty(ENDPOINT_HUB_INTRA, URL_VZNKUL);
            props.setProperty(HUB_ID, HUBID_VZNKUL);
        } else if (HUBID_COZO.equalsIgnoreCase(hubid)) {
            technicalConfig.setProperty(ENDPOINT_HUB_INTRA, URL_COZO);
            props.setProperty(HUB_ID, HUBID_COZO);
        } else if (HUBID_ARH.equalsIgnoreCase(hubid)) {
            technicalConfig.setProperty(ENDPOINT_HUB_INTRA, URL_ARH);
            props.setProperty(HUB_ID, HUBID_ARH);
        }
    }

    /**
     * Create an IDPATIENT for Niss
     */
    protected static IDPATIENT createIdPatientInss() {
        IDPATIENT idPatient = new IDPATIENT();
        idPatient.setS(IDPATIENTschemes.INSS);
        idPatient.setSV(SV_ID);
        idPatient.setValue(PATIENT_INSS);
        return idPatient;
    }

    /**
     * Create an IDHCPARTY for Niss
     */
    protected static IDHCPARTY createIdHcPartyNiss(String value) {
        IDHCPARTY idHcparty = new IDHCPARTY();
        idHcparty.setS(IDHCPARTYschemes.INSS);
        idHcparty.setSV(SV_ID);
        idHcparty.setValue(value);
        return idHcparty;
    }

    /**
     * Create an IDHCPARTY for Nihii
     */
    protected static IDHCPARTY createIdHcPartyNihii() throws TechnicalConnectorException {
        IDHCPARTY idHcparty = new IDHCPARTY();
        idHcparty.setS(IDHCPARTYschemes.ID_HCPARTY);
        idHcparty.setSV(SV_ID);
        idHcparty.setValue(SessionUtil.getNihii11());
        return idHcparty;
    }

    /**
     * Create an IDKMEHR with the specified value
     */
    protected static IDKMEHR createMessageId(String value) throws Exception {
        IDKMEHR id = new IDKMEHR();
        id.setS(IDKMEHRschemes.ID_KMEHR);
        id.setSV(SV_ID);
        id.setValue(value);
        return id;
    }

    /**
     * Create a HcPartyId with the informations of the professional
     */
    protected static HCPartyIdType createHcPartyIdProfessional() throws TechnicalConnectorException {
        HCPartyIdType hcParty = new HCPartyIdType();
        IDHCPARTY idHcparty = createIdHcPartyNihii();
        hcParty.getIds().add(idHcparty);
        idHcparty = createIdHcPartyNiss(PROF_INSS);
        hcParty.getIds().add(idHcparty);
        return hcParty;
    }

    /**
     * Create the professional HcParty
     */
    protected static HcpartyType createHcPartyProfessional() {
        HcpartyType hcParty = new HcpartyType();
        hcParty.setFamilyname(PROF_LASTNAME);
        hcParty.setFirstname(PROF_FIRSTNAME);
        CDHCPARTY cdHcParty = createCdHcPartyProfession();
        hcParty.getCds().add(cdHcParty);
        IDHCPARTY idHcparty = createIdHcPartyNiss(PROF_INSS);
        hcParty.getIds().add(idHcparty);
        return hcParty;
    }

    /**
     * Create a PatientIdType Used by createConsentType
     */
    protected static PatientIdType createPatientIdType() {
        PatientIdType patient = new PatientIdType();
        IDPATIENT idPatient = createIdPatientInss();
        patient.getIds().add(idPatient);
        return patient;
    }

    /**
     * Create a cd with the profession in it Used by createHcPartyProfessional
     */
    protected static CDHCPARTY createCdHcPartyProfession() {
        CDHCPARTY cdHcParty = new CDHCPARTY();
        cdHcParty.setS(CDHCPARTYschemes.CD_HCPARTY);
        cdHcParty.setSV(SV_CD);
        cdHcParty.setValue(PROF_PROFESSION);
        return cdHcParty;
    }

    /**
     * Create the header of the transaction
     */
    protected static HeaderType createHeader() throws Exception {
        HeaderType header = new HeaderType();

        StandardType standard = new StandardType();
        CDSTANDARD cd = new CDSTANDARD();
        cd.setSV("1.4");
        cd.setValue("20110701");
        cd.setS("CD-STANDARD");
        standard.setCd(cd);

        header.setStandard(standard);
        header.getIds().add(createMessageId(SessionUtil.getNihii11() + "." + IdGeneratorFactory.getIdGenerator().generateId()));
        DateTime now = new DateTime();
        header.setDate(now);
        header.setTime(now);
        header.getRecipients().add(createHub());
        header.setSender(createSender());
        return header;
    }

    /**
     * Create the author of the operation
     */
    protected static SenderType createSender() throws TechnicalConnectorException {
        HcpartyType hcParty = new HcpartyType();

        IDHCPARTY doctorNISS = new IDHCPARTY();
        IDHCPARTY doctorNIHII = new IDHCPARTY();
        CDHCPARTY hcPartytype = new CDHCPARTY();

        doctorNIHII.setS(IDHCPARTYschemes.ID_HCPARTY);
        doctorNIHII.setSV(SV_ID);
        doctorNIHII.setValue(SessionUtil.getNihii());

        doctorNISS.setS(IDHCPARTYschemes.INSS);
        doctorNISS.setSV(SV_ID);
        doctorNISS.setValue(PROF_INSS);

        hcPartytype.setS(CDHCPARTYschemes.CD_HCPARTY);
        hcPartytype.setSV(SV_CD);
        hcPartytype.setValue(PROF_PROFESSION);

        hcParty.getIds().add(doctorNIHII);
        hcParty.getIds().add(doctorNISS);
        hcParty.getCds().add(hcPartytype);

        hcParty.setFamilyname(PROF_LASTNAME);
        hcParty.setFirstname(PROF_FIRSTNAME);

        SenderType sender = new SenderType();
        sender.getHcparties().add(hcParty);

        return sender;
    }

    /**
     * Create the author of the operation
     */
    protected static AuthorType createAuthor() {
        AuthorType author = new AuthorType();
        HcpartyType hcParty = createHcPartyProfessional();
        author.getHcparties().add(hcParty);
        return author;
    }

    /**
     * Create the Hub of the operation
     */
    protected static RecipientType createHub() {
        HcpartyType hub = new HcpartyType();

        IDHCPARTY id = new IDHCPARTY();
        id.setValue(CHOSENHUB_ID);
        id.setS(IDHCPARTYschemes.ID_HCPARTY);
        id.setSV(SV_ID);
        hub.getIds().add(id);

        CDHCPARTY cd = new CDHCPARTY();
        cd.setValue("hub");
        cd.setSV(SV_CD);
        cd.setS(CDHCPARTYschemes.CD_HCPARTY);
        hub.getCds().add(cd);

        hub.setName(CHOSENHUB_NAME);
        RecipientType rec = new RecipientType();
        rec.getHcparties().add(hub);
        return rec;
    }

    /**
     * Create a consentType used for consent operations
     */
    protected static ConsentType createConsentType() {
        ConsentType consent = new ConsentType();

        CDCONSENT cdConsent = new CDCONSENT();
        cdConsent.setS(CDCONSENTschemes.CD_CONSENTTYPE);
        cdConsent.setSV(SV_CD);
        cdConsent.setValue(CDCONSENTvalues.RETROSPECTIVE);
        consent.getCds().add(cdConsent);

        consent.setAuthor(createAuthor());
        consent.setPatient(createPatientIdType());
        consent.setSigndate(new DateTime());

        return consent;
    }

    /**
     * Create a TherapeuticLinkType used for ther link operations
     */
    protected static TherapeuticLinkType createTherapeuticLinkType() throws TechnicalConnectorException {
        TherapeuticLinkType therapeuticLink = new TherapeuticLinkType();

        CDTHERAPEUTICLINK cdTherLink = new CDTHERAPEUTICLINK();
        cdTherLink.setS(CDTHERAPEUTICLINKschemes.CD_THERAPEUTICLINKTYPE);
        cdTherLink.setSV(SV_CD);
        cdTherLink.setValue("gpconsultation");
        therapeuticLink.setCd(cdTherLink);

        therapeuticLink.setHcparty(createHcPartyIdProfessional());
        therapeuticLink.setPatient(createPatientIdType());
        therapeuticLink.setStartdate(new DateTime());
        return therapeuticLink;
    }

    /**
     * Create a transaction type needed for transaction operations
     */
    protected static TransactionType createTransactionType() throws Exception {
        MarshallerHelper<TransactionType, TransactionType> helper = new MarshallerHelper<TransactionType, TransactionType>(TransactionType.class, TransactionType.class);
        TransactionType transaction = helper
            .toObject("<transaction xmlns='http://www.ehealth.fgov.be/standards/kmehr/schema/v1'><id S='ID-KMEHR' SV='1.0'>1</id><cd S='CD-TRANSACTION' SV='1.4'>sumehr</cd><date>2013-07-17</date><time>10:01:51+01:00</time><iscomplete>true</iscomplete><isvalidated>true</isvalidated><item><id S='ID-KMEHR' SV='1.0'>1</id><cd S='CD-ITEM' SV='1.4'>risk</cd><content><text L='fr'>travail sur écran</text></content><beginmoment><date>2013-06-21</date><time>14:51:24+01:00</time></beginmoment><recorddatetime>2013-06-21T14:53:28+02:00</recorddatetime></item><item><id S='ID-KMEHR' SV='1.0'>2</id><cd S='CD-ITEM' SV='1.4'>adr</cd><content><text L='fr'>Ticlopidine</text></content><beginmoment><date>2013-06-21</date><time>14:51:24+01:00</time></beginmoment><recorddatetime>2013-06-21T14:52:34+02:00</recorddatetime></item><item><id S='ID-KMEHR' SV='1.0'>3</id><cd S='CD-ITEM' SV='1.4'>medication</cd><content><cd S='CD-ATC' SV='1.0'>B01AC05</cd></content><content><text L='fr'>Ticlid (c) 250mg - 30 compr. enrobé(s)</text></content><content><medicinalproduct><intendedcd S='CD-DRUG-CNK' SV='2.0'>0857995</intendedcd><intendedname>Ticlid (c) 250mg - 30 compr. enrobé(s)</intendedname></medicinalproduct></content><beginmoment><date>2013-06-21</date></beginmoment><lifecycle><cd S='CD-LIFECYCLE' SV='1.3'>prescribed</cd></lifecycle><isrelevant>true</isrelevant><temporality><cd S='CD-TEMPORALITY' SV='1.0'>chronic</cd></temporality><quantity><decimal>1</decimal><unit><cd S='CD-UNIT' SV='1.3'>pkg</cd></unit></quantity><instructionforpatient L='fr'>1 compr. enrobé(s) 1 x / jour</instructionforpatient><recorddatetime>2013-06-21T14:51:24+02:00</recorddatetime></item><item><id S='ID-KMEHR' SV='1.0'>4</id><cd S='CD-ITEM' SV='1.4'>medication</cd><content><cd S='CD-ATC' SV='1.0'>C10AA07</cd></content><content><text L='fr'>rosuvastatine 40 mg - 98 compr. pelliculé(s)</text></content><content><medicinalproduct><intendedcd S='CD-DRUG-CNK' SV='2.0'>2055176</intendedcd><intendedname>rosuvastatine 40 mg - 98 compr. pelliculé(s)</intendedname></medicinalproduct></content><beginmoment><date>2013-06-21</date></beginmoment><endmoment><date>2013-09-27</date></endmoment><lifecycle><cd S='CD-LIFECYCLE' SV='1.3'>prescribed</cd></lifecycle><isrelevant>true</isrelevant><temporality><cd S='CD-TEMPORALITY' SV='1.0'>acute</cd></temporality><quantity><decimal>1</decimal><unit><cd S='CD-UNIT' SV='1.3'>pkg</cd></unit></quantity><instructionforpatient L='fr'>1 compr. 1 x / jour</instructionforpatient><recorddatetime>2013-06-21T14:51:24+02:00</recorddatetime></item><item><id S='ID-KMEHR' SV='1.0'>5</id><cd S='CD-ITEM' SV='1.4'>vaccine</cd><content><cd S='CD-VACCINEINDICATION' SV='1.0'>diphteria</cd><cd S='CD-VACCINEINDICATION' SV='1.0'>tetanus</cd><cd S='CD-ATC' SV='1.0'>J07AM51</cd></content><content><medicinalproduct><intendedcd S='CD-DRUG-CNK' SV='2.0'>1077593</intendedcd><intendedname>Tedivax pro adulto (c)</intendedname></medicinalproduct></content><beginmoment><date>2013-05-28</date></beginmoment><lifecycle><cd S='CD-LIFECYCLE' SV='1.3'>administrated</cd></lifecycle><recorddatetime>2013-06-21T14:53:34+02:00</recorddatetime></item><item><id S='ID-KMEHR' SV='1.0'>6</id><cd S='CD-ITEM' SV='1.4'>vaccine</cd><content><cd S='CD-VACCINEINDICATION' SV='1.0'>diphteria</cd><cd S='CD-VACCINEINDICATION' SV='1.0'>tetanus</cd><cd S='CD-VACCINEINDICATION' SV='1.0'>pertussis</cd><cd S='CD-VACCINEINDICATION' SV='1.0'>poliomyelitis</cd><cd S='CD-ATC' SV='1.0'>J07CA02</cd></content><content><medicinalproduct><intendedcd S='CD-DRUG-CNK' SV='2.0'>2374429</intendedcd><intendedname>Boostrix Polio (c)</intendedname></medicinalproduct></content><beginmoment><date>2013-05-28</date></beginmoment><lifecycle><cd S='CD-LIFECYCLE' SV='1.3'>administrated</cd></lifecycle><recorddatetime>2013-06-21T14:53:34+02:00</recorddatetime></item></transaction>");

        AuthorType author = new AuthorType();
        author.getHcparties().addAll(createSender().getHcparties());

        transaction.setAuthor(author);
        transaction.getIds().add(createMessageId(MESSAGE_ID));
        transaction.getIds().add(createTransactionId(transactionId));
        return transaction;
    }

    /**
     * Create the transaction id with the specified value
     */
    protected static IDKMEHR createTransactionId(String version) {
        IDKMEHR id = new IDKMEHR();
        id.setS(IDKMEHRschemes.LOCAL);
        id.setSL("EHBASICSOFT");
        id.setSV("3.4.0-beta-5");
        id.setValue(version);
        return id;
    }

    /**
     * Create the patient needed for some transaction
     */
    protected PersonType createPatientForTransaction() throws Exception {
        PersonType patient = new PersonType();
        IDPATIENT kmehrPatientId = new IDPATIENT();
        kmehrPatientId.setS(IDPATIENTschemes.INSS);
        kmehrPatientId.setSV(SV_ID);
        kmehrPatientId.setValue(PATIENT_INSS);
        patient.getIds().add(kmehrPatientId);
        patient.getFirstnames().add(PATIENT_FIRSTNAME);
        patient.setFamilyname(PATIENT_LASTNAME);
        return patient;
    }

}
