using be.ehealth.technicalconnector.utils.net;
using be.fgov.ehealth.technicalconnector.session;
using ikvm.extensions;

#region Header

/*
 * Copyright (c) eHealth
 */

#endregion Header

/**
 * Time Stamping Service Integration Tests This test shows the use of the Time Stamping Consult Service through the use of the Technical
 * Connector.
 *
 * All Tests require the following pre-requisites to be met: - An eHealth certificate with access to the Time Stamping service
 */
namespace be.ehealth.technicalconnector.service.timestamp
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Linq;
	using System.Text;
	using System.Threading;

	using NUnit.Framework;
	
	using oasis.names.tc.dss._1_0.core.schema;

	using org.bouncycastle.tsp;
	using org.joda.time;

	using be.ehealth.technicalconnector.idgenerator;
	using be.ehealth.technicalconnector.service;
	using be.ehealth.technicalconnector.service.sts.security;
	using be.ehealth.technicalconnector.service.sts.security.impl;
	using be.fgov.ehealth.technicalconnector.tests.utils;
	using be.fgov.ehealth.timestamping.protocol.v2;


	[TestFixture]
	class TimeStampingConsultationIntegrationTest
	{
		#region Fields

		private static java.util.Properties config;

		#endregion Fields

		#region Methods

		[SetUp]
		public void init()
		{
			config = TestPropertiesLoader.getProperties("be.ehealth.technicalconnector.test.properties",SupportedLanguages.NET.getAbbreviation());
			SessionDestroyer.destroy();
			SessionInitializer.init(true);
		}

		[TearDown]
		public void destroy()
		{
			SessionDestroyer.destroy();
		}


		public byte[] obtainRFC3161Token() {

			String requestId = IdGeneratorFactory.getIdGenerator().generateId();
			String profile = "urn:ehealth:profiles:timestamping:1.1";
			byte[] content = "test".getBytes();
			String mimeType = "text/plain";

			SignRequest request = new SignRequest();
			request.setRequestID(requestId);
			request.setProfile(profile);

			// input document (can be either documents or document hashes)
			InputDocuments inputDocuments = new InputDocuments();
			DocumentType document = new DocumentType();
			Base64Data inputDocument = new Base64Data();
			inputDocument.setMimeType(mimeType);
			inputDocument.setValue(content);

			// set the base64 encoded document in the document element
			document.setBase64Data(inputDocument);

			// add the document element to the list of documents to be timestamped
			inputDocuments.getDocument().add(document);

			// add the input document object to the request
			request.setInputDocuments(inputDocuments);

			/*
			 * Invoke the technical connector framework's Time Stamping Authority Service's SignRequest operation
			 */
			// get the X509 certificate and private key from the test keystore. (retrieved from property file)
			Credential credential = new KeyStoreCredential(config.getProperty("test.timestamping.location"), config.getProperty("test.timestamping.alias"), config.getProperty("test.timestamping.password"));

			SignResponse response = ServiceFactory.getAuthorityService().signRequest(credential.getCertificate(), credential.getPrivateKey(), request);

			/*
			 * Verify the response
			 */
			// check if response has been received
			Assert.IsNotNull(response);
			// check if the timestamping was a success
			Assert.AreEqual("urn:oasis:names:tc:dss:1.0:resultmajor:Success", response.getResult().getResultMajor());

			// retrieve the timestamping token from the response
			return response.getSignatureObject().getTimestamp().getRFC3161TimeStampToken();
		}

		/**
		 * Test the GetTimeStamp operation from the Time Stamping Consult Service through the use of the Technical Connector. This test
		 * retrieves a time stamp from eHealth that has been created for a given hospital, for a given sequenceNr on a given time
		 * 
		 * The following main steps are done: - Create the parameters of the new message - Invoke the technical connector - Verify the response
		 */
		[Test]
		public void testGetTimeStamp() {

			String idHospital = config.getProperty("test.timestamping.tsclientid");
			TimeStampToken timestampToken = TimestampUtil.getTimestamp(obtainRFC3161Token());
			long time = timestampToken.getTimeStampInfo().getGenTime().getTime();
			String seqNr = timestampToken.getTimeStampInfo().getSerialNumber().toString();


			TSConsultTSBagRequest request = new TSConsultTSBagRequest();
			request.setIDHospital(idHospital);

			TimeStampIdentification tsIdent = new TimeStampIdentification();
			tsIdent.setDateTime(time);
			tsIdent.setSequenceNumber(seqNr);
			request.getTSLists().add(tsIdent);

			/*
			 * Invoke the technical connector framework's Time Stamp Consult Service's getTimestamp operation
			 */
			Credential credential = new KeyStoreCredential(config.getProperty("test.timestamping.location"), config.getProperty("test.timestamping.alias"), config.getProperty("test.timestamping.password"));

			// Retrieve the timestamp of the document
			TSConsultTSBagResponse response = ServiceFactory.getConsultServiceV2().getTimestamp(credential.getCertificate(), credential.getPrivateKey(), request);

			/*
			 * Verify the response
			 */
			// Check if response has been received
			Assert.IsNotNull(response);
			Assert.IsNotNull(response.getTSBags());
			Assert.IsFalse(response.getTSBags().isEmpty());
			Assert.AreEqual("urn:oasis:names:tc:dss:1.0:resultmajor:Success",((TSBagType)response.getTSBags().get(0)).getSignResponse().getResult().getResultMajor());
			// this is byte array representation of the document that has been timestamped
			TSBagType tsBag = (TSBagType) response.getTSBags().get(0);
			Assert.IsNotNull(tsBag.getTSBagValue());
			// Check if the Time Stamp Token is present
			Assert.IsNotNull(tsBag.getSignResponse().getSignatureObject());
		}

		/**
		 * Test the CheckCompleteness operation from the Time Stamping Consult Service through the use of the Technical Connector. This test
		 * checks if all time stamps that you request are in the eHealth repository.
		 * 
		 * The following main steps are done: - Create the parameters of the new message - Invoke the technical connector - Verify the response
		 */
		[Test]
		public void testCheckCompleteness() {

			String idHospital = config.getProperty("test.timestamping.tsclientid");
			// get the time on which the time stamp was generated
			TimeStampToken timestampToken = TimestampUtil.getTimestamp(obtainRFC3161Token());
			long timestamp = timestampToken.getTimeStampInfo().getGenTime().getTime();
			// get the sequence number of the timestamp
			String seqNr = timestampToken.getTimeStampInfo().getSerialNumber().toString();

			// Set the period between which to check the completeness of the timestamps. In this example we will check all timestamps from the
			// past minute

			org.joda.time.DateTime startDate = new org.joda.time.DateTime(timestamp);
			org.joda.time.DateTime endDate = new org.joda.time.DateTime(timestamp);
			endDate.plusMinutes(1);

			TSConsultRequest request = new TSConsultRequest();
			request.setIDHospital(idHospital);
			be.fgov.ehealth.timestamping.protocol.v2.PeriodType periodType = new be.fgov.ehealth.timestamping.protocol.v2.PeriodType();
			periodType.setStart(startDate.getMillis());
			periodType.setEnd(endDate.getMillis());
			request.setPeriod(periodType);

			// The Time Stamp Identification: the time of the timestamp and the sequence number
			TimeStampIdentification tsIdent = new TimeStampIdentification();
			tsIdent.setDateTime(timestamp);
			tsIdent.setSequenceNumber(seqNr);
			request.getTSLists().add(tsIdent);

			/*
			 * Invoke the technical connector framework's Time Stamp Consult Service's checkCompleteness operation
			 */
			// get the X509 certificate and private key from the test keystore. (retrieved from property file)
			Credential credential = new KeyStoreCredential(config.getProperty("test.timestamping.location"), config.getProperty("test.timestamping.alias"), config.getProperty("test.timestamping.password"));

			// Check if the timestamps are in the eHealth repository
			TSConsultResponse response = ServiceFactory.getConsultServiceV2().checkCompleteness(credential.getCertificate(), credential.getPrivateKey(), request);

			/*
			 * Verify the response
			 */
			// Check if response has been received
			Assert.IsNotNull(response);
			// Check if the timestamp could be retrieved
			Assert.AreEqual("OK", response.getStatus());
		}

		#endregion Methods
	}
}