using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Configuration;
using System.Web.Services;
using System.Web.Services.Protocols;
//using Microsoft.Web.Services2;
//using Microsoft.Web.Services2.Security;
//using Microsoft.Web.Services2.Security.Tokens;
//using Microsoft.Web.Services2.Security.X509;

namespace Microsoft.RFIDLab.EPCISDemo.ASNReceivingWS
{
	/// <summary>
	/// Summary description for Service1.
	/// </summary>
	[System.Xml.Serialization.XmlInclude(typeof(Pip3B2AdvanceShipmentNotification)), WebService(Namespace="http://www.microsoft.com/RFIDLab/EPCISDemo")]
	public class ASNReceivingService : System.Web.Services.WebService
	{
		// Replace the key id below with your own certificate Id in Base64String here
		// You can get these values for any cert with the WSE 2.0 Certificate Tool
		public static string ClientBase64KeyId = ConfigurationSettings.AppSettings["ClientBase64KeyId"];		

		public ASNReceivingService()
		{
			//CODEGEN: This call is required by the ASP.NET Web Services Designer
			InitializeComponent();
		}

		#region Component Designer generated code
		
		//Required by the Web Services Designer 
		private IContainer components = null;
				
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if(disposing && components != null)
			{
				components.Dispose();
			}
			base.Dispose(disposing);		
		}
		
		#endregion

		[System.Web.Services.WebMethod()]
		public ReceiptAcknowledgement ReceiveASN(string objASN)
		{

			//Check if security is enabled
			if (ConfigurationSettings.AppSettings["EnableWSSecurity"].ToLower() == "true")
			{
//				//Check for WS-Security
//				// Reject any requests which are not valid SOAP requests
//				if (RequestSoapContext.Current == null)
//					throw new ApplicationException("Only SOAP requests are permitted.");
//
//				// Check if the soap message contains all the required message parts
//				VerifyMessageParts(RequestSoapContext.Current);
//
//				// Check if the Soap Message is Signed.
//				X509SecurityToken x509Token = GetSigningToken(RequestSoapContext.Current) as X509SecurityToken;
//				if (x509Token == null || !CompareArray(x509Token.KeyIdentifier.Value, Convert.FromBase64String(ClientBase64KeyId)))
//				{
//					throw new SecurityFault(SecurityFault.FailedAuthenticationMessage, SecurityFault.FailedAuthenticationCode);
//				}
			}

			Pip3B2AdvanceShipmentNotification objPip3B2 = new Pip3B2AdvanceShipmentNotification();
			ReceiptAcknowledgement objAck = new ReceiptAcknowledgement();
			objAck.receivedDocumentDateTime.DateTimeStamp = System.DateTime.UtcNow.ToUniversalTime().ToString("yyyyMMddThhmmss.000Z");
			
			try
			{
				System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(objPip3B2.GetType(),"http://www.microsoft.com/RFIDLab/EPCISDemo");
				System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
				System.IO.MemoryStream  memStream = new System.IO.MemoryStream(enc.GetBytes(objASN));
				System.Xml.XmlTextWriter xmlTW = new System.Xml.XmlTextWriter(memStream,System.Text.Encoding.UTF8);				
				memStream.Position = 0;
				objPip3B2 = (Pip3B2AdvanceShipmentNotification)x.Deserialize(memStream);

				objAck.fromRole.PartnerRoleDescription = objPip3B2.toRole.PartnerRoleDescription;
				objAck.toRole.PartnerRoleDescription = objPip3B2.fromRole.PartnerRoleDescription;

				objAck.receivedDocumentIdentifier.ProprietaryDocumentIdentifier = objPip3B2.thisDocumentIdentifier.ProprietaryDocumentIdentifier;
				
				objAck.thisMessageDateTime.DateTimeStamp = System.DateTime.UtcNow.ToUniversalTime().ToString("yyyyMMddThhmmss.000Z");
				objAck.thisMessageIdentifier.ProprietaryMessageIdentifier = "Acknowledgement of ASN";


	
			}
			catch (Exception ex)
			{
				string strException = ex.ToString();	
				objAck.thisMessageIdentifier.ProprietaryMessageIdentifier = strException;
			}
			
			return objAck;
		}

		/// <summary>
		/// This method basically checks if those required message parts exist.
		/// The required headers are Soap:body, To, Action, MessageID, and Timestamp
		/// </summary>
		/// <param name="context"></param>
		/* public static void VerifyMessageParts(SoapContext context) 
		{
			// Body
			if ( context.Envelope.Body == null )
				throw new ApplicationException("The message must contain a soap:Body element");

			if ( context.Addressing.To == null || context.Addressing.To.TargetElement == null )
				throw new ApplicationException("The message must contain a wsa:To header");

			if ( context.Addressing.Action == null || context.Addressing.Action.TargetElement == null )
				throw new ApplicationException("The message must contain a wsa:Action header");

			if ( context.Addressing.MessageID == null || context.Addressing.MessageID.TargetElement == null )
				throw new ApplicationException("The message must contain a wsa:To header");

			if ( context.Security.Timestamp == null  )
				throw new ApplicationException("The message must contain a wsu:Timestamp header");
		}
		/// <summary>
		/// This method checks if the incoming message has signed all the important message parts
		/// such as soap:Body, all the addressing headers and timestamp.  
		/// </summary>
		/// <param name="context"></param>
		/// <returns>The signing token</returns>
		public static SecurityToken GetSigningToken(SoapContext context)
		{
			foreach ( ISecurityElement element in context.Security.Elements )
			{
				if ( element is MessageSignature )
				{
					// The given context contains a Signature element.
					MessageSignature sig = element as MessageSignature;

					if (CheckSignature(context, sig))
					{
						// The SOAP Body is signed.
						return sig.SigningToken;
					}
				}
			}

			return null;
		}
		static bool CheckSignature(SoapContext context, MessageSignature signature)
		{
			//
			// Now verify which parts of the message were actually signed.
			//
			SignatureOptions actualOptions   = signature.SignatureOptions;
			SignatureOptions expectedOptions = SignatureOptions.IncludeSoapBody;
          
			if (context.Security != null && context.Security.Timestamp != null ) 
				expectedOptions |= SignatureOptions.IncludeTimestamp;
            
			//
			// The <Action> and <To> are required addressing elements.
			//
			expectedOptions |= SignatureOptions.IncludeAction;
			expectedOptions |= SignatureOptions.IncludeTo;

			if ( context.Addressing.FaultTo != null && context.Addressing.FaultTo.TargetElement != null )
				expectedOptions |= SignatureOptions.IncludeFaultTo;

			if ( context.Addressing.From != null && context.Addressing.From.TargetElement != null )
				expectedOptions |= SignatureOptions.IncludeFrom;

			if ( context.Addressing.MessageID != null && context.Addressing.MessageID.TargetElement != null )
				expectedOptions |= SignatureOptions.IncludeMessageId;

			if ( context.Addressing.RelatesTo != null && context.Addressing.RelatesTo.TargetElement != null )
				expectedOptions |= SignatureOptions.IncludeRelatesTo;

			if ( context.Addressing.ReplyTo != null && context.Addressing.ReplyTo.TargetElement != null )
				expectedOptions |= SignatureOptions.IncludeReplyTo;
			//
			// Check if the all the expected options are the present.
			//
			return ( ( expectedOptions & actualOptions ) == expectedOptions );
                
		}*/

		/// <summary>
		/// Routine to compare two byte arrays
		/// </summary>
		/// <param name="a">First Byte Array</param>
		/// <param name="b">Second Byte Array</param>
		/// <returns>true or false</returns>
		public static bool CompareArray(byte[] a, byte[] b)
		{
			if (a != null && b != null && a.Length == b.Length)
			{
				int index = a.Length;
				while (--index > -1)
					if (a[index] != b[index])
						return false;
				return true;
			}
			else if (a == null && b == null)
				return true;
			else
				return false;
		}	

	}
}
