using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.Xml.Serialization;
using Microsoft.RFIDLab.EPCISDemo.Pip3B12ShippingOrderConfirmation;
using Microsoft.RFIDLab.EPCISDemo.Pip3B12ShippingNotificationRequest;
using Microsoft.RFIDLab.EPCISDemo.PIP4B2;
using Microsoft.RFIDLab.EPCISDemo.Common;
using Microsoft.RFIDLab.EPCISDemo.EPCEvent;

namespace Microsoft.RFIDLab.EPCISDemo.ShippingAgentWS
{
	/// <summary>
	/// Web-service for performing shipping-agent operations.
	/// </summary>
	[System.Xml.Serialization.XmlInclude(typeof(PIP4B2.Pip4B2ShipmentReceiptNotification)),System.Xml.Serialization.XmlInclude(typeof(Pip3B12ShippingOrderRequest)), System.Xml.Serialization.XmlInclude(typeof(Pip3B12ShippingOrderConfirmation.Pip3B12ShippingOrderConfirmation)),WebService(Namespace="http://www.microsoft.com/RFIDLab/TrackAndTraceDemo")]
	public class ShippingAgentWebService : System.Web.Services.WebService
	{
		//Database Manager reference for EPC Event Logging.
		private TrackTraceDBManager dbManager;
		//ShippingOrder request reference. Instead of storing the shipping order
		//received in a datbase, we store in variable and use in business acks.
		private string shippingOrderNumber;
		private Pip3B12ShippingNotificationRequest.Pip3B12ShippingOrderRequest objPip3B12RequestReceived;

		/// <summary>
		/// Creates a web-service object.
		/// </summary>
		public ShippingAgentWebService()
		{
			//CODEGEN: This call is required by the ASP.NET Web Services Designer
			InitializeComponent();

			//Initialize DatabaseManager for Shipping Agent Database.
			dbManager = new TrackTraceDBManager(TrackTraceDBManager.Constants.ShippingAgent);

		}

		#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

		/// <summary>
		/// Receives and processes a business-request.
		/// </summary>
		/// <param name="objBusinessRequest">The business-request object.
		/// </param>
		/// <returns>Business-response. </returns>
		[System.Web.Services.WebMethod()]			
		public BusinessResponse ReceiveBusinessRequest (
			BusinessRequest objBusinessRequest )
		{
			BusinessResponse objBusinessResponse = new BusinessResponse () ;

			/****************************************************************************
			  Accept PIP3B12ShippingOrderRequest from Manufacturer.
			  Create ReceiptAcknowledgment and PIP3B12ShippingOrderConfirmation and reply
			  back in BusinessResponse object.
			  Update ShippingDatabase with EPC status.
			*****************************************************************************/
			if (objBusinessRequest.GlobalProcessIndicatorCode.ToUpper() == "3B12")
			{
				
				Pip3B12ShippingNotificationRequest.Pip3B12ShippingOrderRequest objPip3B12Request = (Pip3B12ShippingNotificationRequest.Pip3B12ShippingOrderRequest)objBusinessRequest.objPip;
				//store the ordernumber received by manufacturer.
				shippingOrderNumber = objPip3B12Request.ShippingOrder.OrderInformation.orderNumber.ProprietaryDocumentIdentifier;

				objBusinessResponse.GlobalProcessIndicatorCode = objBusinessRequest.GlobalProcessIndicatorCode;

				//Create ShippingOrder confirmation object.
				Pip3B12ShippingOrderConfirmation.Pip3B12ShippingOrderConfirmation objShippingOrderConfirmation = new Pip3B12ShippingOrderConfirmation.Pip3B12ShippingOrderConfirmation();

				Pip3B12ShippingNotificationRequest.Pip3B12ShippingOrderRequest objShippingOrderRequest = (Pip3B12ShippingNotificationRequest.Pip3B12ShippingOrderRequest)objBusinessRequest.objPip;
				objPip3B12RequestReceived = objShippingOrderRequest; //save for reference in BusincessACK webmethod.

				//get confirmation object ready. You can either Accept the Order or Reject the Order
				//and give reason for rejection. We implement order acceptance.
				objShippingOrderConfirmation.GlobalDocumentFunctionCode = "Response";
				objShippingOrderConfirmation.thisDocumentGenerationDateTime.DateTimeStamp = System.DateTime.UtcNow.ToUniversalTime().ToString("yyyyMMddThhmmss.000Z");
				objShippingOrderConfirmation.thisDocumentIdentifier.ProprietaryDocumentIdentifier = objPip3B12Request.ShippingOrder.OrderInformation.orderNumber.ProprietaryDocumentIdentifier;

				//ToRole information of the Acknowledgment
				objShippingOrderConfirmation.toRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value = objShippingOrderRequest.fromRole.PartnerRoleDescription.ContactInformation.contactName.ToString();
				objShippingOrderConfirmation.toRole.PartnerRoleDescription.ContactInformation.EmailAddress = objShippingOrderRequest.fromRole.PartnerRoleDescription.ContactInformation.EmailAddress;
				objShippingOrderConfirmation.toRole.PartnerRoleDescription.ContactInformation.telephoneNumber.CommunicationsNumber = objShippingOrderRequest.fromRole.PartnerRoleDescription.ContactInformation.telephoneNumber.CommunicationsNumber;
				objShippingOrderConfirmation.toRole.PartnerRoleDescription.ContactInformation.facsimileNumber.CommunicationsNumber = objShippingOrderRequest.fromRole.PartnerRoleDescription.ContactInformation.facsimileNumber.CommunicationsNumber;

				//FromRole information of the Acknowledgment
				objShippingOrderConfirmation.fromRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value = objShippingOrderRequest.toRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value;
				objShippingOrderConfirmation.fromRole.PartnerRoleDescription.ContactInformation.EmailAddress = objShippingOrderRequest.toRole.PartnerRoleDescription.ContactInformation.EmailAddress;
				objShippingOrderConfirmation.fromRole.PartnerRoleDescription.ContactInformation.facsimileNumber.CommunicationsNumber = objShippingOrderRequest.toRole.PartnerRoleDescription.ContactInformation.facsimileNumber.CommunicationsNumber;
				objShippingOrderConfirmation.fromRole.PartnerRoleDescription.ContactInformation.telephoneNumber.CommunicationsNumber = objShippingOrderRequest.toRole.PartnerRoleDescription.ContactInformation.telephoneNumber.CommunicationsNumber;
			
				//order information
				objShippingOrderConfirmation.ShippingOrder.OrderConfirmation.GlobalShippingOrderStatusCode = "Shipping Order Accepted";
				objShippingOrderConfirmation.ShippingOrder.OrderInformation.orderNumber.ProprietaryDocumentIdentifier = objShippingOrderRequest.ShippingOrder.OrderInformation.orderNumber.ProprietaryDocumentIdentifier;
			
				//include 3B12 response object.
				objBusinessResponse.objPip = objShippingOrderConfirmation;

				//Receipt Acknowledgement needs to be populated and sent along with the response
				ReceiptAcknowledgement objReceiptAcknowledgement = new ReceiptAcknowledgement();
				objReceiptAcknowledgement.fromRole = objShippingOrderConfirmation.fromRole;
				objReceiptAcknowledgement.toRole = objShippingOrderConfirmation.toRole;
				objReceiptAcknowledgement.thisMessageIdentifier.ProprietaryMessageIdentifier="Acknowledgement";
				objReceiptAcknowledgement.thisMessageDateTime.DateTimeStamp = System.DateTime.UtcNow.ToUniversalTime().ToString("yyyyMMddThhmmss.000Z");
				objReceiptAcknowledgement.receivedDocumentIdentifier.ProprietaryDocumentIdentifier = objShippingOrderRequest.thisDocumentIdentifier.ProprietaryDocumentIdentifier;
				
				objBusinessResponse.objAcknowledgement = objReceiptAcknowledgement;

				//Update ShippingDatabase with ShippingOrderReceived status for all received EPCs
				LogEPCStatus(objPip3B12RequestReceived, TrackTraceDBManager.Constants.ShippingNotificationFromManufacturerToShippingAgent);

				//Update ShippingDatabase with ShippingOrderConfirmation status for all received EPCs
				LogEPCStatus(objPip3B12RequestReceived, TrackTraceDBManager.Constants.ShippingOrderConfFromShippingAgentToManufacturer);
				
			} 
			else 
			{
				//Currently we support only PIP3B12 in ShippingAgent business request.
				objBusinessResponse.GlobalProcessIndicatorCode = "REQUEST-NOT-SUPPORTED";
			}
			
			//send ReceiptAcknowledgment and PIP3B12ShippingOrderConfirmation
			return objBusinessResponse ;
						
		} // end of ReceiveBusinessRequest ()

		/// <summary>
		/// Receives a business-acknowledgement.
		/// </summary>
		/// <param name="objBusinessResponse">Business-response. </param>
		/// <returns>True or false, depending upon the response. </returns>
		/**************************************************************************
		* The WebInterface is used to accept Business Acknowledgment. currently
		* Shipping Agent WebService handles following PIP's:
		* 1. PIP4b2NotifyOfShipmentReceipt from Receiving Agent.
		* 2. ReceiptAcknowledgment from Manufacturer.
		***************************************************************************/
		[System.Web.Services.WebMethod()]			
		public  bool ReceiveBusinessAcknowledgement(BusinessResponse objBusinessResponse)
		{
			if(objBusinessResponse == null)
				return false;

			//Process PIP4B2 Notification from Receiving Agent
			if(objBusinessResponse.GlobalProcessIndicatorCode.Equals("4B2"))
			{
				PIP4B2.Pip4B2ShipmentReceiptNotification objPip4B2 = (PIP4B2.Pip4B2ShipmentReceiptNotification)objBusinessResponse.objPip;
				string orderNumber = objPip4B2.thisDocumentIdentifier.ProprietaryDocumentIdentifier;
				
				// MS - commented
				/* if(shippingOrderNumber.Equals(orderNumber))
				{ */

					//Confirms the receipt of goods from Receiving Agent.
					//Update Shipping Database with information.
					LogEPCStatus(objPip4B2, TrackTraceDBManager.Constants.NotifyOfShipmentReceiptFromReceivingAgentToShippingAgent);
				
				// MS - commented
				/* } */
				
				return true;
			}
			else if(objBusinessResponse.GlobalProcessIndicatorCode.Equals("ACK"))
			{
				//As part of the scope of the current project, we DO NOT need to store the acknowledgement 
				//that we receive - to the database.
				//So this method will just make sure that the Acknowledgement is not null, and return a true
				//or a false
				if(objBusinessResponse.objAcknowledgement != null)
					return true;
				else
					return false;
			}
			else 
			{
				//Unknown Business Acknowledgment
				return false;
			}
		} // end of ReceiveBusinessAcknowedgement ()

		/// <summary>
		/// Receives EPC events.
		/// </summary>
		/// <param name="objEPCEvent">Encapsulated EPC event-information.
		/// </param>
		/*********************************************************************************
		 * This web interface is used to accept EPC Events and log them to local database.
		 * It also forwards the EPC Event.
		 *********************************************************************************/
		[System.Web.Services.WebMethod()]
		public void ReceiveEPCEvent(EPCEvent.EquipmentProductCodeInformation objEPCEvent)
		{
			if(objEPCEvent != null)
			{
				string ordernumber = objEPCEvent.BusinessTransactionIdentifier;
				//In future we can extend the functionality to verify if this ordernumber is
				//of interest to us. It not, take appropriate action.

				string epctag;
				int eventid;
				System.DateTime datetime;

				//For now we assume that all communication is valid in demo. loop through
				//pallets and cases and log the epc tag.
				foreach(EPCEvent.EquipmentProductCodeEvent objPallet in objEPCEvent.EquipmentProductCodeEventCollection)
				{
					epctag = objPallet.EquipmentProductCode.FreeFormText.Value;

					// MS - commented
					// eventid = Convert.ToInt32(objPallet.EventType);
					
					eventid = Convert.ToInt32 ( objPallet.EPCEventIdentifier ) ;
					datetime = System.DateTime.Now;

					// MS - commented
					// dbManager.AddEpcStatusInfo(epctag, eventid, datetime);

					dbManager.AddFullEpcStatusInfo ( epctag, eventid, datetime,
						objEPCEvent.CurrentAgent.Agent.reportedBy.PartnerDescription.ContactInformation.contactName.FreeFormText.Value,
						objPallet.Agent.reportedBy.PartnerDescription.ContactInformation.contactName.FreeFormText.Value,
						objPallet.EventLocation.GlobalLocationIdentifier ) ;

					foreach(EPCEvent.AssociateEquipmentProductCode objCase in objPallet.AssociateEquipmentProductCodeCollection)
					{
                        epctag = objCase.FreeFormText.Value;

						// MS - commented
						// dbManager.AddEpcStatusInfo(epctag, eventid, datetime);

						dbManager.AddFullEpcStatusInfo ( epctag, eventid, datetime,
							objEPCEvent.CurrentAgent.Agent.reportedBy.PartnerDescription.ContactInformation.contactName.FreeFormText.Value,
							objPallet.Agent.reportedBy.PartnerDescription.ContactInformation.contactName.FreeFormText.Value,
							objPallet.EventLocation.GlobalLocationIdentifier ) ;

					}
				}
			}

			/**************************************************************************
			//Now we forward the EPCEvent that we received to Manufacturer WebService.
			//Note:
			//In the scope of this Demo project, we assume that MFR<->SA<->RA<->Receiver
			//are trusted and known to each other.
			//In the future, this demo application can be extended to verify the name of
			//steward in the EPCEvent object and decide which Web Service to forward the
			//event.
			**************************************************************************/
			ManufacturerWS.ManufacturerWebService proxyMfr = new ManufacturerWS.ManufacturerWebService();
			proxyMfr.ReceiveEPCEvent(objEPCEvent);
            			
		}  //End of ReceiveEPCEvent WebMethod.

		/// <summary>
		/// Logs the EPC status to the data-base from the Pip3B12 object stored
		/// in the session.
		/// </summary>
		/// <param name="eventType">The event-type which occured. </param>
		private void LogEPCStatus(Pip3B12ShippingNotificationRequest.Pip3B12ShippingOrderRequest objPip3B12RequestReceived, int eventType)
		{

			string strFromRole = null;
			string strToRole = null;

			if(eventType == TrackTraceDBManager.Constants.ShippingNotificationFromManufacturerToShippingAgent)
			{
				strFromRole = objPip3B12RequestReceived.fromRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value;
				strToRole =   objPip3B12RequestReceived.toRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value;
				
			}
			else if(eventType == TrackTraceDBManager.Constants.ShippingOrderConfFromShippingAgentToManufacturer)
			{
				strToRole = objPip3B12RequestReceived.fromRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value;
				strFromRole =   objPip3B12RequestReceived.toRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value;
			}

			Pip3B12ShippingNotificationRequest.ShipmentLineItemCollection objShipmentLineItemCollection = objPip3B12RequestReceived.ShippingOrder.ShipmentLineItemCollection;
			for(int i = 0; i < objShipmentLineItemCollection.Count; i++)
			{
				Pip3B12ShippingNotificationRequest.ShipmentLineItem objShipmentLineItem = objShipmentLineItemCollection[i];
				Pip3B12ShippingNotificationRequest.ShippingContainerCollection objShippingContainerCollection = objShipmentLineItem.ShippingContainerCollection;
				for(int j = 0; j < objShippingContainerCollection.Count; j++)
				{
					Pip3B12ShippingNotificationRequest.ShippingContainer objShippingContainer = objShippingContainerCollection[j];
					Pip3B12ShippingNotificationRequest.ShippingContainerItemCollection objShippingContainerItemCollection = objShippingContainer.ShippingContainerItemCollection;
					string caseEPC = objShippingContainer.shippingContainerIdentifier.ProprietarySerialIdentifier;
					string caseEPCNumber = caseEPC.Substring(0, caseEPC.IndexOf(" "));

					// MS - commented
					// dbManager.AddEpcStatusInfo(caseEPCNumber, eventType, System.DateTime.Now);

					dbManager.AddFullEpcStatusInfo(caseEPCNumber, 
						eventType,
						System.DateTime.Now, 
						strFromRole,
						strToRole,
						"Shipping Agent Location");
						
					for(int k = 0; k < objShippingContainerItemCollection.Count; k++)
					{
						Pip3B12ShippingNotificationRequest.ShippingContainerItem objShippingContainerItem = objShippingContainerItemCollection[k];
						string strEPC = objShippingContainerItem.shippingContainerItemIdentifier.ProprietarySerialIdentifier;
						string strEPCNumber = strEPC.Substring(0, strEPC.IndexOf(" "));

						// MS - commented
						// dbManager.AddEpcStatusInfo(strEPCNumber, eventType, System.DateTime.Now);

						dbManager.AddFullEpcStatusInfo(strEPCNumber, 
							eventType,
							System.DateTime.Now,
							strFromRole,
							strToRole,
							"Shipping Agent Location");

					}
				}
			}

		} //end of LogEPCInfo

		/// <summary>
		/// Logs EPC event information to the data-base.
		/// </summary>
		/// <param name="objPip4B2">Pip4B2 object. </param>
		/// <param name="eventType">The event-type which occured. </param>
		private void LogEPCStatus(PIP4B2.Pip4B2ShipmentReceiptNotification objPip4B2, int eventType)
		{
			foreach ( ShipmentReceiptInformationResource resource
							in objPip4B2.ShipmentReceiptInformationResourceCollection )
			{
				string prop = resource.shipmentIdentifier.ProprietaryReferenceIdentifier ;
				int index = prop.IndexOf ( ' ' ) ;
				string epc = prop ;

				if ( index > 0 )
					epc = prop.Substring ( 0, index ) ; // end if

				// MS - commented
				// dbManager.AddEpcStatusInfo ( epc, eventType, DateTime.Now ) ;

				dbManager.AddFullEpcStatusInfo ( epc, eventType, DateTime.Now,
					objPip4B2.fromRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value,
					objPip4B2.toRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value,
					"Shipping Agent Location" ) ;

				foreach ( ShipmentReceiptNotificationLineItem lineItem
					in resource.ShipmentReceiptNotificationLineItemCollection )
				{
					foreach ( string proprietary in lineItem.ProprietarySerialIdentifierCollection )
					{
						index = proprietary.IndexOf ( ' ' ) ;
						epc = proprietary ;

						if ( index > 0 )
							epc = proprietary.Substring ( 0, index ) ; // end if

						// MS - commented
						// dbManager.AddEpcStatusInfo ( epc, eventType, DateTime.Now ) ;

						dbManager.AddFullEpcStatusInfo ( epc, eventType, DateTime.Now,
							objPip4B2.fromRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value,
							objPip4B2.toRole.PartnerRoleDescription.ContactInformation.contactName.FreeFormText.Value,
							"Shipping Agent Location" ) ;

					} // end nested for

				} // end nested for

			} // end nested for

		} //end of LogEPCInfo

	}
}

