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 System.Net;
using System.Collections;
using System.Xml;
using System.IO;


namespace WS2Client.ETrace
{

	// 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 ETraceRun.
	/// </summary>
	public class ETraceRun : IRun
	{

		private ETraceServiceWse 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 ETraceRun()
		{
		}
		
		public void Init(String URL, String userName, String password, X509Certificate loginCert, X509Certificate signCert)
		{
			//
			// TODO: Add constructor logic here
			//
			// ignorovani hlasky upozornjici na SSL
			System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();

			// creates WSE 2.0 enabled proxy class of e-Trace web services interface 
			e_trace = new ETraceServiceWse();
			e_trace.Url=URL;
			if(loginCert!=null)
			{
				e_trace.ClientCertificates.Add(loginCert);
			}
			mSignCert=signCert;
			this.userName=userName;
			this.password=password;
		}
		//
		public OutParamsShared RunSynchronous(String FID)
		{
			// prepare parameters
			ETrace.InParams in_par = pGetInParams();
			in_par.FID = FID;
			SignSoap();
			/*return e_trace.RunSynchrous(par);*/

			// calling webservice
			ETrace.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
			ETrace.InParams in_par = pGetInParams();
			in_par.FID = FID;
			SignSoap();
			/*return e_trace.RunSynchrous(par);*/

			// calling webservice
			ETrace.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();
			/*return e_trace.RunSynchrous(par);*/

			// calling webservice
			ETrace.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 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 ETrace.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();

			//
			ETrace.InParams in_params = new ETrace.InParams();
			in_params.FID=FID;
			in_params.Parameters=new ParametersCollection();
			foreach(Object par in paramsList)
			{
        //
				if(par is ETrace.BooleanParam)
				{
					lBoolParams.Add(par);
					continue;
				}
				if(par is ETrace.DateParam)
				{
					lDateParams.Add(par);
					continue;
				}
				if(par is ETrace.DateTimeParam)
				{
					lDateTimeParams.Add(par);
					continue;
				}
				if(par is ETrace.DecimalParam)
				{
					lDecimalParams.Add(par);
					continue;
				}
				if(par is ETrace.IntParam)
				{
					lIntParams.Add(par);
					continue;
				}
				if(par is ETrace.StringParam)
				{
					lStringParams.Add(par);
					continue;
				}
				if(par is ETrace.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 ETrace.InParams pGetInParams() 
		{
			ETrace.InParams in_params = new ETrace.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) 
		{
			ETrace.BooleanParam opar = new ETrace.BooleanParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_BoolParams.Add(opar);
		}
		public void AddDateParam(string a_Name,DateTime a_Value) 
		{
			ETrace.DateParam opar = new ETrace.DateParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_DateParams.Add(opar);
		}
		public void AddDateTimeParam(string a_Name,DateTime a_Value) 
		{
			ETrace.DateTimeParam opar = new ETrace.DateTimeParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_DateTimeParams.Add(opar);
		}
		public void AddStringParam(string a_Name,string a_Value) 
		{
			ETrace.StringParam opar = new ETrace.StringParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_StringParams.Add(opar);
		}
		public void AddIntParam(string a_Name,int a_Value) 
		{
			ETrace.IntParam opar = new ETrace.IntParam();
			opar.Name = a_Name;
			opar.Value = a_Value;
			m_IntParams.Add(opar);
		}
		public void AddXmlParam(string a_Name,string a_Value) 
		{
			ETrace.XmlParam opar = new ETrace.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) 
		{
			ETrace.DecimalParam opar = new ETrace.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);
			}
			
		}

	}
}
