/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.chapterIV.builders;

import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.bouncycastle.util.encoders.Base64;
import org.easymock.EasyMock;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import be.ehealth.businessconnector.chapterIV.validators.Chapter4XmlValidator;
import be.ehealth.businessconnector.chapterIV.validators.KmehrValidator;
import be.ehealth.businessconnector.chapterIV.validators.impl.Chapter4XmlValidatorImpl;
import be.ehealth.businessconnector.chapterIV.validators.impl.KmehrValidatorImpl;
import be.ehealth.technicalconnector.service.etee.Crypto;
import be.ehealth.technicalconnector.service.etee.domain.EncryptionToken;
import be.ehealth.technicalconnector.service.keydepot.KeyDepotManagerFactory;
import be.ehealth.technicalconnector.service.keydepot.KeyDepotService;
import be.ehealth.technicalconnector.service.kgss.KgssManager;
import be.ehealth.technicalconnector.service.kgss.KgssService;
import be.ehealth.technicalconnector.service.kgss.domain.KeyResult;
import be.ehealth.technicalconnector.service.sts.security.Credential;
import be.ehealth.technicalconnector.service.sts.security.SAMLToken;
import be.ehealth.technicalconnector.service.sts.security.impl.KeyStoreCredential;
import be.ehealth.technicalconnector.session.Session;
import be.ehealth.technicalconnector.session.SessionItem;
import be.ehealth.technicalconnector.session.SessionManager;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.ehealth.technicalconnector.utils.IdentifierType;
import be.fgov.ehealth.etee.kgss._1_0.protocol.GetNewKeyRequestContent;
import be.fgov.ehealth.technicalconnector.tests.session.SessionDestroyer;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;
import be.fgov.ehealth.technicalconnector.tests.utils.TestPropertiesLoader;


/**
 * Abstract class for Builder tests which initialise mocks for session handling
 * 
 * @author EHP
 * 
 */
public abstract class AbstractBuilderTest {

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

    private X509Certificate cert;

    private Crypto systemCrypto;

    private Crypto personalCrypto;

    private KmehrValidator kmehrValidator;


    private Chapter4XmlValidator chapter4XmlValidator;

    private BuilderFactory factory;

    private SessionManager sessionManager;

    private SessionItem sessionItem;

    private SAMLToken token;

    private Element samlElement;


    private KeyDepotService etkService;

    private KgssService kgssService;

    private Credential credential;

    protected static Properties props = null;

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

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


    /**
     * Sets easy mocks up
     * 
     * @throws Exception
     */
    @Before
    public void setupEasyMock() throws Exception {
        AbstractBuilderTest.init();

        /**
         * Instantiation of the testdata independent mocks before a test.
         */
        systemCrypto = EasyMock.createMock(Crypto.class);
        personalCrypto = EasyMock.createMock(Crypto.class);
        kmehrValidator = new KmehrValidatorImpl();
        chapter4XmlValidator = new Chapter4XmlValidatorImpl();
        factory = new BuilderFactory(systemCrypto, personalCrypto, kmehrValidator, chapter4XmlValidator);


        sessionManager = EasyMock.createMock(SessionManager.class);
        sessionItem = EasyMock.createMock(SessionItem.class);


        token = EasyMock.createMock(SAMLToken.class);

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(AbstractBuilderTest.class.getResourceAsStream("/examples/token.saml"));

        samlElement = doc.getDocumentElement();
        etkService = EasyMock.createMock(KeyDepotService.class);
        kgssService = EasyMock.createMock(KgssService.class);
        credential = EasyMock.createMock(Credential.class);
        cert = new KeyStoreCredential(props.getProperty("test.keystore.location"), props.getProperty("test.keystore.alias"), props.getProperty("test.keystore.password")).getCertificate();


        EasyMock.expect(credential.getCertificate()).andReturn(cert).anyTimes();
        EasyMock.expect(sessionManager.getSession()).andReturn(sessionItem).anyTimes();
        EasyMock.expect(sessionManager.hasValidSession()).andReturn(true).anyTimes();
             Session.setSessionManager(sessionManager);
        Session.getInstance();
        EasyMock.expect(sessionItem.getEncryptionCredential()).andReturn(credential).anyTimes();
        EasyMock.expect(sessionItem.getEncryptionCrypto()).andReturn(personalCrypto).anyTimes();
        EasyMock.expect(sessionItem.getHolderOfKeyCredential()).andReturn(credential).anyTimes();
        EasyMock.expect(sessionItem.getHolderOfKeyCrypto()).andReturn(personalCrypto).anyTimes();
        EasyMock.expect(sessionItem.getSAMLToken()).andReturn(token).anyTimes();
        KgssManager.getInstance(kgssService);
        KeyDepotManagerFactory.getKeyDepotManager().setKeyDepotService(etkService);
        EasyMock.expect(token.getAssertion()).andReturn(samlElement).anyTimes();
        EasyMock.expect(token.getCertificate()).andReturn(cert).anyTimes();
        Set<EncryptionToken> etkSet = new HashSet<EncryptionToken>();
        etkSet.add(new EncryptionToken(ConnectorIOUtils.getBytes(AdmissionBuilderTest.class.getResourceAsStream("/etee/kgss.etk"))));
        EasyMock.expect(etkService.getETKSet(IdentifierType.SSIN, "82051234978", "")).andReturn(etkSet).anyTimes();
        EasyMock.expect(etkService.getETKSet(IdentifierType.CBE, "0820563481", "MYCARENET")).andReturn(etkSet).anyTimes();
        EasyMock.expect(etkService.getETKSet(IdentifierType.CBE, "0809394427", "KGSS")).andReturn(etkSet).anyTimes();
        KeyResult generatedResult = getKeyResult();
        EasyMock.expect(kgssService.getNewKey((GetNewKeyRequestContent) EasyMock.anyObject(), (byte[]) EasyMock.anyObject())).andReturn(generatedResult).anyTimes();
        EasyMock.expect(personalCrypto.seal((byte[]) EasyMock.anyObject(), EasyMock.eq(generatedResult.getSecretKey()), EasyMock.eq(generatedResult.getKeyId()))).andReturn("freeText".getBytes()).anyTimes();
        EncryptionToken[] etkArray = new EncryptionToken[1];
        etkArray = etkSet.toArray(etkArray);
        EasyMock.expect(personalCrypto.seal(EasyMock.eq(etkArray[0]), (byte[]) EasyMock.anyObject())).andReturn("sealed".getBytes()).anyTimes();


        EasyMock.replay(systemCrypto, personalCrypto, token, etkService, kgssService, sessionManager, sessionItem, credential);


    }


    /**
     * @return
     */
    private static KeyResult getKeyResult() {
        LOG.debug("Simulation key found, proceding in test mode");
        String part1 = "15";
        String part2 = "GRUG5JUaXC/U697PrddwOA==";
        LOG.info("TEST MODE: KGSS key retrieved from configuration. Key Id = " + part1);
        byte[] keyResponse = Base64.decode(part2);
        return new KeyResult(new SecretKeySpec(keyResponse, "AES"), part1);
    }


    /**
     * @return the factory
     */
    protected BuilderFactory getFactory() {
        return factory;
    }


}