using System.Xml.Linq;
using be.ehealth.technicalconnector.service.sts.security;
using be.fgov.ehealth.technicalconnector.tests.utils;
using com.sun.security.auth;
using ikvm.extensions;
using java.security;

#region Header

/*
 * Copyright (c) eHealth
 */

#endregion Header

/**
 * IntegrationTest for BeIDInfo
 */
namespace be.fgov.ehealth.technicalconnector.jca
{
    using System;
    using System.Security.Cryptography;
    using be.ehealth.technicalconnector.session;
    using be.ehealth.technicalconnector.enumeration;
    using be.ehealth.technicalconnector.service.sts.security.impl;
    using be.ehealth.technicalconnector.utils;
    using be.fgov.ehealth.technicalconnector.distributedkeys;
    using be.fgov.ehealth.technicalconnector.jca.proxy;
    using be.fgov.ehealth.technicalconnector.jca.util;
    using be.fgov.ehealth.technicalconnector.jca.impl;
    using java.io;
    using java.security.cert;
    using java.util;
    using javax.xml.parsers;
    using NUnit.Framework;
    using org.apache.commons.lang;
    using org.apache.xml.security;
    using org.apache.xml.security.c14n;
    using org.apache.xml.security.signature;
    using org.apache.xml.security.transforms;
    using org.apache.xml.security.utils;
    using org.w3c.dom;
    using be.ehealth.technicalconnector.config;

    [TestFixture]
    public class DistributedTest
    {
        private java.util.Properties props;

        #region Methods
        
        [SetUp]
        public void setUp()
        {
        	ConfigFactory.getConfigValidator().getConfig().setProperty("KEYSTORE_DIR",".\\P12\\acc\\");
            props = JcaTestPropertiesLoader.getProperties("be.ehealth.technicalconnector.test.properties",
                SupportedLanguages.NET.getAbbreviation());
        }

        [TearDownAttribute]
        public void tearDown()
        {
            DistributedKeyStoreRegistry.getInstance().flushCache();
        }

        [Test]
        public void signWithEid()
        {
            Credential credential = BeIDCredential.getInstance("test", BeIDCredential.EID_AUTH_ALIAS);
            DistributedKeyStoreRegistry.getInstance()
                .createDistributedKeyStore("store-eid", new CredentialProxy(credential));
            String distributedResult = sign("Authentication", "store-eid");
            String localResult = sign(BeIDCredential.EID_AUTH_ALIAS, credential.getKeyStore(), new char[0]);
            AssertEqualXml(distributedResult, localResult);
        }


        [Test]
        public void createDistributedSessionWithEid()
        {
            DistributedKeyStoreRegistry registry = DistributedKeyStoreRegistry.getInstance();
            registry.createDistributedKeyStore(Session.IDENTIFICATION_KEYSTORE, new BeIDDistributedSigner());

            registry.createDistributedKeyStore(Session.IDENTIFICATION_KEYSTORE, new BeIDDistributedSigner());
            Assert.IsFalse(registry.getDistributedKeyStores().isEmpty());
            registry.createDistributedKeyStore(Session.HOLDEROFKEY_KEYSTORE, new BeIDDistributedSigner());
            registry.createDistributedKeyStore(Session.ENCRYPTION_KEYSTORE, new BeIDDistributedSigner());

            SessionManager sessionMgr = Session.getInstance();
            sessionMgr.setKeyStore(registry.getDistributedKeyStores());
            Assert.IsFalse(registry.getDistributedKeyStores().isEmpty());

            sessionMgr.createSessionEidOnly();
        }

        [Test]
        public void getCertificateChainWithEid()
        {
            Credential credential = BeIDCredential.getInstance("test", BeIDCredential.EID_AUTH_ALIAS);
            KeyStore keystore = DistributedKeyStoreRegistry.getInstance()
                .createDistributedKeyStore("store-eid", new CredentialProxy(credential));
            Certificate[] certs = keystore.getCertificateChain(BeIDCredential.EID_AUTH_ALIAS);
            Assert.AreEqual(3, certs.Length);
        }

        [Test]
        public void getCertificateChainWithX509()
        {
        	
            String eHealthCertificate = props.getProperty("test.keystore.location");
            String eHealthCertificatePwd = props.getProperty("test.keystore.password");
            String alias = props.getProperty("test.keystore.alias");
            KeyStoreInfo ksInfo = new KeyStoreInfo(eHealthCertificate, eHealthCertificatePwd.toCharArray(), alias,
                eHealthCertificatePwd.toCharArray());
            Credential credential = new KeyStoreCredential(ksInfo);

            KeyStore keystore = DistributedKeyStoreRegistry.getInstance()
                .createDistributedKeyStore("store-x509", new CredentialProxy(credential));
            Certificate[] certs = keystore.getCertificateChain(alias);
            Assert.AreEqual(2, certs.Length);
            for (int i = 0; i < certs.Length; i++)
            {
                X509Certificate cert = (X509Certificate) certs[i];
                System.Console.WriteLine(cert.getSubjectX500Principal().getName());
            }
        }

        [Test]
        public void signWithX509()
        {
            String eHealthCertificate = props.getProperty("test.keystore.location");
            String eHealthCertificatePwd = props.getProperty("test.keystore.password");
            String alias = props.getProperty("test.keystore.alias");
            KeyStoreInfo ksInfo = new KeyStoreInfo(eHealthCertificate, eHealthCertificatePwd.toCharArray(), alias,
                eHealthCertificatePwd.toCharArray());
            Credential credential = new KeyStoreCredential(ksInfo);

            DistributedKeyStoreRegistry.getInstance()
                .createDistributedKeyStore("store-jks", new CredentialProxy(credential));
            String distributedResult = sign("authentication", "store-jks");
            String localResult = sign("authentication", credential.getKeyStore(), eHealthCertificatePwd.toCharArray());
            AssertEqualXml(localResult, distributedResult);
        }


        private String sign(String alias, KeyStore store, char[] password)
        {
            InputStream xmlFile = new ByteArrayInputStream("<boe/>".getBytes());
            String result = signFile(xmlFile, store.getCertificateChain(alias), store.getKey(alias, password));
            return result;
        }

        private String sign(String alias, String storeName)
        {
            KeyStore store =
                (KeyStore) DistributedKeyStoreRegistry.getInstance().getDistributedKeyStores().get(storeName);
            return sign(alias, store, ArrayUtils.EMPTY_CHAR_ARRAY);
        }

        private static String signFile(InputStream xmlFile, Certificate[] certificate, Key privateKey)
        {
            Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile);
            Init.init();
            ElementProxy.setDefaultPrefix(Constants.SignatureSpecNS, "");
            XMLSignature sig = new XMLSignature(doc, null, XMLSignature.ALGO_ID_SIGNATURE_RSA);
            Transforms transforms = new Transforms(doc);
            transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
            sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
            for (int i = 0; i < certificate.Length; i++)
            {
                X509Certificate cert = (X509Certificate) certificate[i];
                sig.addKeyInfo(cert);
                System.Console.WriteLine(cert.getSubjectX500Principal().getName());
            }

            sig.sign(privateKey);
            doc.getDocumentElement().appendChild(sig.getElement());
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS).canonicalizeSubtree(doc, baos);
            return System.Text.Encoding.ASCII.GetString(baos.toByteArray());
        }

        private void AssertEqualXml(string expectedXml, string actualXml)
        {
            Assert.IsTrue(XNode.DeepEquals(XElement.Parse(expectedXml), XElement.Parse(actualXml)),
                String.Format("{0} \n does not equal \n{1}", actualXml, expectedXml));
        }

        #endregion Methods
    }
}