using be.ehealth.technicalconnector.config;
using be.ehealth.technicalconnector.exception;
using be.ehealth.technicalconnector.service.sts;
using be.ehealth.technicalconnector.service.sts.security;
using be.ehealth.technicalconnector.service.sts.security.impl;
using be.ehealth.technicalconnector.service.sts.utils;
using be.ehealth.technicalconnector.session;
using System;
using be.ehealth.technicalconnector.utils;
using be.fgov.ehealth.technicalconnector.tests.utils.net;
using be.fgov.ehealth.etee.crypto.utils;
using be.fgov.ehealth.technicalconnector.tests.utils;
using com.sun.mirror.type;
using com.sun.tools.apt.mirror.type;
using ikvm.extensions;
using java.io;
using java.lang;
using java.util;
using org.apache.commons.io;
using org.apache.commons.lang3;
using org.w3c.dom;

/*
 * Copyright (c) eHealth
 * 
 * Session Destroyer
 * Can be used to destroy all sessions and informations left by a program.
 */
namespace be.fgov.ehealth.technicalconnector.session
{
	public static class SessionInitializer
	{
		private static string DEFAULT_SESSION_CONFIG_FILE = "be.ehealth.technicalconnector.test.properties";

		private static string SESSION_USERNAME = "session.username";

		private static string SESSION_PROFESSION_TYPE = "session.professionType";

		private static string SESSION_ENVIRONMENT = "session.environment";

		private static string TOKENNAME = "target/tokenAsstring.token";

		private static string TEST_SESSION_PERSIST = "test.session.persist";

		private static string FILEPATH_PREFIX = "filepath.prefix";

		private static string defaultSessionType = SessionType.FALLBACK.ToString();

		private static Properties sessionProps;


		/**
		 * 
		 * Inner enum containing all the types of session supported by the connector;
		 * 
		 * @author EHP
		 * 
		 */
		public enum SessionType {
			EID_ONLY, EID, FALLBACK
		}

		public static void init() {
			init(true);
		}

		public static void init(bool initParameter) {
			init(DEFAULT_SESSION_CONFIG_FILE, initParameter);
		}

		public static void init(string propsLocation) {
			init(propsLocation, true);
		}



		public static void init(string propsLocation, bool initSession) {
			init(propsLocation, initSession, SupportedLanguages.NET.getAbbreviation());
		}

		public static void init(string propsLocation, string devLang) {
			init(propsLocation, true, devLang);
		}

		public static void init(string propsLocation, bool initSession, string devLang) {
			Properties props = TestPropertiesNetLoader.getProperties(propsLocation,".net");
			init(props, initSession, devLang);
		}

		public static void init(Properties props) {
			init(props, true, SupportedLanguages.NET.getAbbreviation());
		}


		public static void init(Properties props, string devLang) {
			init(props, true, devLang);
		}

		public static void init(Properties props, bool initSession) {
			init(props, initSession, SupportedLanguages.NET.getAbbreviation());
		}

		/**
		 * This method will initialize the session based on the props as parameter it will use the following parameters as input <li>
		 * session.environment <li>session.professionType <li>session.username
		 */
		public static void init(Properties props, bool initSession, string devLang) {
			Properties cleanedProps = TestPropertiesNetLoader.processProps(props, devLang);

			string prefix = "/";
			if (SupportedLanguages.JAVA.getAbbreviation().Equals(devLang)) {
				prefix = "/";
			} else if (SupportedLanguages.NET.getAbbreviation().Equals(devLang)) {
				prefix = ".\\";
			}
			System.Environment.SetEnvironmentVariable(FILEPATH_PREFIX, prefix); // So that we can access the prefix from everywhere, with a default value "/"
			initConfig(createLocation("be.ehealth.technicalconnector", cleanedProps, prefix, false, false), devLang);
			loadSession(createLocation("be.ehealth.connector-session-test", cleanedProps, prefix, true, true), initSession, devLang);
		}


		private static void loadSession(string sessionPropsLocation, bool initSession, string devLang) {
			sessionProps = TestPropertiesNetLoader.getProperties(sessionPropsLocation,".net");

			string identPwd = sessionProps.getProperty("test.session.identification.password");
			string hokPwd = sessionProps.getProperty("test.session.holderofkey.password");
			string encPwd = sessionProps.getProperty("test.session.encryption.password");
			SessionType type = (SessionType) System.Enum.Parse(typeof(SessionType),sessionProps.getProperty("test.sessiontype", defaultSessionType));

			Configuration config = ConfigFactory.getConfigValidator().getConfig();
			Iterator keySetIt = sessionProps.keySet().iterator();
			while (keySetIt.hasNext()) {
				object keyObj= keySetIt.next();
				string key = keyObj.ToString();
				if (!key.StartsWith("test.")) {
					string value = sessionProps.getProperty(key);
					if (value.StartsWith("/") && SupportedLanguages.NET.getAbbreviation().Equals(devLang)) {
						value = StringUtils.replaceOnce(value, "/", ".\\\\");
					}
					config.setProperty(key, value);
				}
			}


			config.reload();

			if (initSession) {
				SessionManager sessionmgmt = Session.getInstance();
				if (!sessionmgmt.hasValidSession()) {
					switch (type) {
						case SessionType.EID:
							sessionmgmt.createSession(hokPwd, encPwd);
							break;
						case SessionType.EID_ONLY:
							sessionmgmt.createSessionEidOnly();
							break;
						case SessionType.FALLBACK:
							sessionmgmt.createFallbackSession(identPwd, hokPwd, encPwd);
							break;
						default:
							break;
					}
				}
				string persistToken = sessionProps.getProperty(TEST_SESSION_PERSIST, "false");
				if ("true".equalsIgnoreCase(persistToken)) {
					storeAndReload(identPwd, hokPwd, encPwd, sessionmgmt);
				}
			}
		}

		private static void storeAndReload(string indentPwd, string hokPwd, string encPwd, SessionManager sessionmgmt) {
			SessionItem item = sessionmgmt.getSession();

			Element originalAssertion = item.getSAMLToken().getAssertion();
			string serializedToken = SAMLConverter.toXMLString(originalAssertion);

			File temp = new File(TOKENNAME);
			temp.deleteOnExit();

			IOUtils.write(serializedToken.getBytes(), new FileOutputStream(temp));

			sessionmgmt.unloadSession();

			Element savedAssertion = SAMLConverter.toElement(IOUtils.toString(new FileReader(temp)));

			ConfigValidator config = ConfigFactory.getConfigValidator();

			string hokKeystore = config.getProperty("sessionmanager.holderofkey.keystore");
			string hokAlias = config.getProperty("sessionmanager.holderofkey.alias", "authentication");

			SAMLToken token = SAMLTokenFactory.getInstance().createSamlToken(savedAssertion, new KeyStoreCredential(hokKeystore, hokAlias, hokPwd));

			sessionmgmt.loadSession(token, hokPwd, encPwd);
		}


		private static void initConfig(string location, string devLang) {
			try {
				InputStream inStream = ConnectorIOUtils.getResourceAsStream(location, false);
				File tempFile = File.createTempFile("SessionInitializer", ".properties");
				tempFile.deleteOnExit();
				Properties configProps = new Properties();
				configProps.load(inStream);
				if (SupportedLanguages.NET.getAbbreviation().Equals(devLang)) {
					Enumeration e = configProps.propertyNames();
					while (e.hasMoreElements()) {
						string key = (string) e.nextElement();
						string value = configProps.getProperty(key);
						if (value.startsWith("/")) {
							value = StringUtils.replaceOnce(value, "/", ".\\\\");
							configProps.setProperty(key, value);
						}
					}
				}
				configProps.store(new FileOutputStream(tempFile), "Process properties for " + devLang);
				ConfigFactory.setConfigLocation(tempFile.getAbsolutePath());
			} catch (java.lang.Exception e) {
				throw new TechnicalConnectorException(TechnicalConnectorExceptionValues.ERROR_GENERAL, e.getMessage(), e);
			}
		}

		private static string createLocation(string baseName, Properties props, string prefix, bool includeEnv, bool includeName) {
			string env = null;
			string profession = null;
			string name = null;
			Iterator keySetIt = props.keySet().iterator();
			while (keySetIt.hasNext()) {
				object keyObj = keySetIt.next();
				string key = keyObj.ToString();
				if (key.equalsIgnoreCase(SESSION_ENVIRONMENT)) {
					env = props.getProperty(key);
				} else if (key.equalsIgnoreCase(SESSION_PROFESSION_TYPE)) {
					profession = props.getProperty(key);
				} else if (key.equalsIgnoreCase(SESSION_USERNAME)) {
					name = props.getProperty(key);
				}
			}

			StringBuilder sb = new StringBuilder();
			if (includeEnv && !StringUtils.isEmpty(env)) {
				sb.append("-").append(env);
			}
			if (!StringUtils.isEmpty(profession)) {
				sb.append("-").append(profession);
			}
			if (includeName && !StringUtils.isEmpty(name)) {
				sb.append("-").append(name);
			}
			if (StringUtils.isEmpty(sb.ToString()) && "be.ehealth.connector-session-test".Equals(baseName)) {
				baseName = "be.ehealth.technicalconnector.test";
			}
			return prefix + baseName + sb.ToString() + ".properties";
		}


		/**
		 * @return the sessionProps
		 */
		public static Properties getSessionProps() {
			return sessionProps;
		}
	}
}
