using System;
using Microsoft.Web.Services2.Security.X509;
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Security.Tokens;
using Microsoft.Web.Services2.Security;
using System.Security.Cryptography;
using System.Security;
using Microsoft.Web.Services2.Security.Xml;
using Microsoft.Web.Services2.Addressing;
using System.Net;
using System.Collections;
using System.Xml;
using System.IO;
///!!!
using System.Text;


namespace WS2Client.Damas
{

	// trida zajistuje, aby se duverovalo vsem certifikatum
	public class TrustAllCertificatePolicy:System.Net.ICertificatePolicy 
	{
		public TrustAllCertificatePolicy() {}
		public bool CheckValidationResult(ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert, WebRequest req, int problem) 
		{
			return true;
		}
	}

	class WSTypeParameter 
	{
		private string m_Name;
		private object m_Value;
		public WSTypeParameter(string a_Name, object a_Value) 
		{
			m_Name = a_Name;
			m_Value = a_Value;
		}
		public string Name 
		{
			get {return m_Name;}
		}
		public object Value
		{
			get {return m_Value;}
		}
	}


	/// <summary>
	/// Summary description for DamasRun.
	/// </summary>
	public class DamasRun : IRun
	{

		private DamasService e_trace;
		X509Certificate mSignCert;
		String userName;
		String password;

		private ArrayList m_StringParams = new ArrayList();
		private ArrayList m_BoolParams = new ArrayList();
		private ArrayList m_DateTimeParams = new ArrayList();
		private ArrayList m_DateParams = new ArrayList();
		private ArrayList m_IntParams = new ArrayList();
		private ArrayList m_DecimalParams = new ArrayList();
		private ArrayList m_XmlParams = new ArrayList();

		public int timeOutSec
		{
			get
			{
				return e_trace.Timeout/1000;
			}
			set
			{
				e_trace.Timeout = value*1000;
			}
		}

		public DamasRun()
		{
		}

		public void Init(String URL, String targetURL, String userName, String password, X509Certificate loginCert, X509Certificate signCert)
		{
            // ignorovani hlasky upozornjici na SSL
            //03.10.2013 - vigy21 Maly - aktualizace na .NET 3.5
            //System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
            System.Net.ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                return true; // **** Always accept
            };

			// creates WSE 2.0 enabled proxy class of e-Trace web services interface 
			e_trace = new DamasService();
			e_trace.Url=URL;
            log(String.Concat("Init.e_trace.Url=", URL));///!!!
            if (loginCert != null)
			{
				e_trace.ClientCertificates.Add(loginCert);
			}
			mSignCert=signCert;
			this.userName=userName;
			this.password=password;

			//read the proxy usage from the proxy config
			if(ProxyConfiguration.UseProxy) {
				e_trace.Proxy = new WebProxy(ProxyConfiguration.Address +":"+ProxyConfiguration.Port,true);
				e_trace.Proxy.Credentials = new NetworkCredential(ProxyConfiguration.Username,ProxyConfiguration.Password);
			}

			//URL pouzivane webservice tridou k pristupu k webovkam pres web server - tj cesta takova jako bychom pristupovali k WS pres browser
			//tedy s https... apd.
			Uri proxyURI = new Uri(URL);
			//URL pouzivane pro aplikac - nemusi nutne obsahovat napriklad https... pokud na aplikaci neni SSL nainstalovano
			Uri targetURI = new Uri(targetURL);
			e_trace.Destination = new EndpointReference(targetURI,proxyURI);
		}
		//
		public OutParamsShared RunSynchronous(String FID)
		{
			// prepare parameters
			Damas.InParams in_par = pGetInParams();
			in_par.FID = FID;
			SignSoap();

			// calling webservice
			Damas.OutParams out_par=null;
			out_par =  e_trace.RunSynchrous(in_par);

			return new OutParamsShared(out_par.RQID, out_par.Result, out_par.RQState.Code, out_par.RQState.Description);
			//return out_par.Result.OuterXml;
		}

		public OutParamsShared RunAsynchronous(String FID)
		{
			// prepare parameters
			Damas.InParams in_par = pGetInParams();
			in_par.FID = FID;
			SignSoap();

			// calling webservice
			Damas.OutParams out_par=null;
			out_par =  e_trace.RunAsynchrous(in_par);
			return new OutParamsShared(out_par.RQID, out_par.Result, out_par.RQState.Code, out_par.RQState.Description);
		}

		public OutParamsShared CheckRQResult(int RQID) {
			// prepare parameters
			SignSoap();

			// calling webservice
			Damas.OutParams out_par=null;
			out_par =  e_trace.CheckRQResult(RQID);
			return new OutParamsShared(out_par.RQID, out_par.Result, out_par.RQState.Code, out_par.RQState.Description);
		}

		public OutParamsShared GetActualDateTime() {
			// prepare parameters
			SignSoap();

			// calling webservice
            log(String.Concat("calling webservice.GetActualDateTime.start", ""));///!!!
			Damas.OutParams out_par=null;
			out_par =  e_trace.GetActualDateTime();
            log(String.Concat("calling webservice.GetActualDateTime.end", ""));///!!!
			return new OutParamsShared(out_par.RQID, out_par.Result, out_par.RQState.Code, out_par.RQState.Description);
		}

		public XmlDocument getSoapResponse()
		{
			//e_trace.RequestSoapContext.
			return e_trace.ResponseSoapContext.Envelope;
		}

		public XmlDocument getSoapRequest()
		{
			//e_trace.RequestSoapContext.
			return e_trace.RequestSoapContext.Envelope;
		}	

		//vrati certifikat kterym byl podepsan soap
		public X509Certificate signCertResponse()
		{
			// Gets SOAP response context (this object holds signature of the SOAP
			// response returned by server)
			SoapContext responseContext = e_trace.ResponseSoapContext;

			// Verify signature of the SOAP response
			foreach (ISecurityElement objElem in responseContext.Security.Elements)
			{
				if (objElem is MessageSignature)
				{
					MessageSignature clientSignature = (MessageSignature)objElem;

					if (clientSignature.SigningToken is X509SecurityToken)
					{
						return ((X509SecurityToken)clientSignature.SigningToken).Certificate;
					}
				}
			}
			return null;
		}

		public void Dispose()
		{
			e_trace.Dispose();
		}


		//
		/*		private Damas.InParams fillParams(String FID, ArrayList paramsList)
				{
					//parametry
					ArrayList lBoolParams = new ArrayList();
					ArrayList lDateParams = new ArrayList();
					ArrayList lDateTimeParams = new ArrayList();
					ArrayList lDecimalParams = new ArrayList();
					ArrayList lIntParams = new ArrayList();
					ArrayList lStringParams = new ArrayList();
					ArrayList lXmlParams = new ArrayList();

					//
					Damas.InParams in_params = new Damas.InParams();
					in_params.FID=FID;
					in_params.Parameters=new ParametersCollection();
					foreach(Object par in paramsList)
					{
				//
						if(par is Damas.BooleanParam)
						{
							lBoolParams.Add(par);
							continue;
						}
						if(par is Damas.DateParam)
						{
							lDateParams.Add(par);
							continue;
						}
						if(par is Damas.DateTimeParam)
						{
							lDateTimeParams.Add(par);
							continue;
						}
						if(par is Damas.DecimalParam)
						{
							lDecimalParams.Add(par);
							continue;
						}
						if(par is Damas.IntParam)
						{
							lIntParams.Add(par);
							continue;
						}
						if(par is Damas.StringParam)
						{
							lStringParams.Add(par);
							continue;
						}
						if(par is Damas.XmlParam)
						{
							lXmlParams.Add(par);
							continue;
						}
					}
					in_params.Parameters.BooleanParam=(BooleanParam[])lBoolParams.ToArray();
					in_params.Parameters.DateParam=(DateParam[])lDateParams.ToArray();
					in_params.Parameters.DateTimeParam=(DateTimeParam[])lDateTimeParams.ToArray();
					in_params.Parameters.DecimalParam=(DecimalParam[])lDecimalParams.ToArray();
					in_params.Parameters.IntParam=(IntParam[])lIntParams.ToArray();
					in_params.Parameters.StringParam=(StringParam[])lStringParams.ToArray();
					in_params.Parameters.XmlParam=(XmlParam[])lXmlParams.ToArray();
					return in_params;
				}
		*/
		
		//fuj start
		protected Damas.InParams pGetInParams() 
		{
			Damas.InParams in_params = new Damas.InParams();
			in_params.Parameters=new ParametersCollection();
			if(m_BoolParams.Count>0){in_params.Parameters.BooleanParam = (BooleanParam[])m_BoolParams.ToArray(typeof(BooleanParam));};
			if(m_DateParams.Count>0){in_params.Parameters.DateParam = (DateParam[])m_DateParams.ToArray(typeof(DateParam));};
			if(m_DateTimeParams.Count>0){in_params.Parameters.DateTimeParam = (DateTimeParam[])m_DateTimeParams.ToArray(typeof(DateTimeParam));};
			if(m_DecimalParams.Count>0){in_params.Parameters.DecimalParam = (DecimalParam[])m_DecimalParams.ToArray(typeof(DecimalParam));};
			if(m_IntParams.Count>0){in_params.Parameters.IntParam = (IntParam[])m_IntParams.ToArray(typeof(IntParam));};
			if(m_StringParams.Count>0){in_params.Parameters.StringParam = (StringParam[])m_StringParams.ToArray(typeof(StringParam));};
			if(m_XmlParams.Count>0){in_params.Parameters.XmlParam = (XmlParam[])m_XmlParams.ToArray(typeof(XmlParam));};
			return in_params;
		}

		public void AddBoolParam(string a_Name,bool a_Value) 
		{
			Damas.BooleanParam opar = new Damas.BooleanParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_BoolParams.Add(opar);
		}
		public void AddDateParam(string a_Name,DateTime a_Value) 
		{
			Damas.DateParam opar = new Damas.DateParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_DateParams.Add(opar);
		}
		public void AddDateTimeParam(string a_Name,DateTime a_Value) 
		{
			Damas.DateTimeParam opar = new Damas.DateTimeParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_DateTimeParams.Add(opar);
		}
		public void AddStringParam(string a_Name,string a_Value) 
		{
			Damas.StringParam opar = new Damas.StringParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_StringParams.Add(opar);
		}
		public void AddIntParam(string a_Name,int a_Value) 
		{
			Damas.IntParam opar = new Damas.IntParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_IntParams.Add(opar);
		}
		public void AddXmlParam(string a_Name,string a_Value) 
		{
			Damas.XmlParam opar = new Damas.XmlParam();
			opar.Name = a_Name;
			if(a_Value==null || a_Value.Equals(""))
			{
				opar.Any=null;
			}
			else
			{
				XmlDocument doc=new XmlDocument();
				doc.LoadXml(a_Value);
				opar.Any=doc.DocumentElement;
			}
			m_XmlParams.Add(opar);
		}
		public void AddDecimalParam(string a_Name,Decimal a_Value) 
		{
			Damas.DecimalParam opar = new Damas.DecimalParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_DecimalParams.Add(opar);
		}
		//fuj konec

		private void SignSoap()
		{
			SoapContext requestContext = e_trace.RequestSoapContext;

			// Creates SHA1 hash of password
			//SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
			MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

			// Gets byte array containing password
			byte[] pass = System.Text.Encoding.UTF8.GetBytes(password);
			// Creates SHA1 hash of password
			//byte[] sha1_hash = sha1.ComputeHash(pass);
			byte[] md5_hash = md5.ComputeHash(pass);
			// Encodes password hash to BASE64 string
			//uZBWEzPEo11G2itJyxC+XQ==
			//string sha1_hash_str = Convert.ToBase64String(sha1_hash);
			string md5_hash_str = Convert.ToBase64String(md5_hash);

			// Adds wsse:UsernameToken to the SOAP request. Note that password must 
			// be encrypted using SHA1 algorithm.
			UsernameToken usr_token = new UsernameToken(userName, md5_hash_str, 
				PasswordOption.SendPlainText); 
			requestContext.Security.Tokens.Add(usr_token);

			//TODO skontrolovat jestli to tu nebude chybet
			if(mSignCert!=null)
			{
				// Generates signature for <soap:Body> element using X.509 certificate
				X509SecurityToken signatureToken = new X509SecurityToken(mSignCert);
				requestContext.Security.Tokens.Add(signatureToken);
				MessageSignature sig = new MessageSignature(signatureToken);
				// Generates signature for <wsse:UsernameToken> element
				SignatureReference usrRef = new SignatureReference("#" + usr_token.Id);
				usrRef.AddTransform(new XmlDsigExcC14NTransform());
				sig.AddReference(usrRef);
				// Adds signature to the SOAP request
				requestContext.Security.Elements.Add(sig);
			}
			
		}

        ///!!!
		private void log(string text) {
			TextWriter tw=new StreamWriter("log.txt",true);
            tw.WriteLine("[" + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString() + "].DamasRun: " + text);
			tw.Flush();
			tw.Close();
		}
	}
}
