using System.Xml.Linq;
using be.ehealth.technicalconnector.service.sts.security;
using be.ehealth.technicalconnector.utils.net;
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 System.Windows.Forms;
	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.jca;
	using be.fgov.ehealth.technicalconnector.distributedkeys.proxy;
	using be.fgov.ehealth.technicalconnector.distributedkeys;
	using be.fgov.ehealth.technicalconnector.jca.proxy;

	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;

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

		#region Methods
		[SetUp]
		public void setUp(){
			props = TestPropertiesLoader.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());
			return System.Text.Encoding.ASCII.GetString(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS).canonicalizeSubtree(doc));
		}
		
		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

	}
}