public override IElectronicPayment ProcessHttpResponse(System.Web.HttpRequest postBackData, PaymentRequestTypes paymentType) {

			IElectronicPayment payment = new ElectronicPayment();

			try {
        
				if (postBackData["RESULT"] == CC_TRANSACTION_APPROVED 
					&& postBackData["USER10"].ToUpper() != "UPDATE_DATEBASE_DELAYED_CAPTURE") {
					payment.TransactionStatus = PaymentStatus.Approved;                                                                                                                                                     
				} else {
					payment.TransactionStatus = PaymentStatus.Declined;
				}

				payment.TransactionReference = postBackData["PNREF"];

                payment.UserInfo = new Cuyahoga.Modules.ECommerce.Util.WebStoreUser();
                string[] name = postBackData["Name"].Split(" ".ToCharArray());
				payment.UserInfo.UserDetails.FirstName = name[0];
                payment.UserInfo.UserDetails.LastName = name[1];
				payment.UserInfo.UserDetails.EmailAddress = postBackData["Email"];

				payment.UserInfo.UserAddress.Postcode = postBackData["Zip"];
				payment.UserInfo.UserAddress.AddressLine1 = postBackData["Address"];
				payment.UserInfo.UserAddress.AddressLine2 = postBackData["USER4"];
				payment.UserInfo.UserAddress.City = postBackData["USER5"];
				payment.UserInfo.UserAddress.Region = postBackData["USER6"];
				payment.UserInfo.UserDetails.TelephoneNumber = postBackData["USER7"];
                payment.UserInfo.UserDetails.FaxNumber = postBackData["USER8"];

			} catch (Exception e) {
				LogManager.GetLogger(GetType()).Error(e);
			}

			return null;
		}
		protected override string RenderFormHiddenValues(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			FuturePayElectronicPayment fPayment = payment as FuturePayElectronicPayment;

			StringBuilder html = new StringBuilder();

			html.Append(base.RenderFormHiddenValues(payment, paymentType));

			switch (paymentType) {
				case PaymentRequestTypes.ImmediatePayment:
				case PaymentRequestTypes.ReservePayment:

					html.Append("<!-- Start FuturePay Fields -->\r\n");
						
					html.Append("<input type=\"hidden\" name=\"futurePayType\" value=\"regular\">\r\n");

					if (fPayment.StartDate > DateTime.Now) {
						html.Append("<input type=\"hidden\" name=\"startDate\" value=\"" + fPayment.StartDate.ToString("yyyy-MM-dd") + "\">\r\n");
					} else {
						html.Append("<input type=\"hidden\" name=\"startDelayUnit\" value=\"" + fPayment.StartDelayUnit + "\">\r\n");
						html.Append("<input type=\"hidden\" name=\"startDelayMult\" value=\"" + fPayment.StartDelayMult + "\">\r\n");
					}

					html.Append("<input type=\"hidden\" name=\"noOfPayments\" value=\"" + fPayment.NumberOfPayments + "\">\r\n");

					if (fPayment.NumberOfPayments != 1) {
						html.Append("<input type=\"hidden\" name=\"intervalUnit\" value=\"" + fPayment.IntervalUnit + "\">\r\n");
						html.Append("<input type=\"hidden\" name=\"intervalMult\" value=\"" + fPayment.IntervalMult + "\">\r\n");
					}

					if (fPayment.InitialAmount != null && fPayment.InitialAmount.Amount > 0) {
						html.Append("<input type=\"hidden\" name=\"initialAmount\" value=\"" + fPayment.InitialAmount.Amount + "\">\r\n");
					}

					if (fPayment.NormalAmount != null && fPayment.NormalAmount.Amount > 0) {
						html.Append("<input type=\"hidden\" name=\"normalAmount\" value=\"" + fPayment.NormalAmount.Amount + "\">\r\n");
					}

					html.Append("<input type=\"hidden\" name=\"option\" value=\"" + fPayment.AgreementOption + "\">\r\n");

					html.Append("<!-- End FuturePay Fields -->\r\n");

					break;
				default:
					throw new InvalidOperationException("Payment request type not supported [" + paymentType + "]");
			}

			return html.ToString();

		}
		protected override string RenderFormHiddenValues(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			StringBuilder html = new StringBuilder();

			html.Append("<input type=\"hidden\" name=\"MFCIsapiCommand\" value=\"Orders\">");
			html.Append("<input type=\"hidden\" name=\"LOGIN\" value=\"" + MerchantID + "\">");
			html.Append("<input type=\"hidden\" name=\"PARTNER\" value=\"" + "wfb\">");
    
			html.Append("<input type=\"hidden\" name=\"AMOUNT\" value=\"" + payment.PaymentAmount.Amount + "\">");
			html.Append("<input type=\"hidden\" name=\"TYPE\" value=\"A\">");
			html.Append("<input type=\"hidden\" name=\"ECHODATA\" value=\"True\">");

			string strCustIDConcat;
			string strSep = "|";
			strCustIDConcat = payment.UserInfo.AccountID + strSep
                + payment.UserInfo.UserDetails.FirstName + " " + payment.UserInfo.UserDetails.LastName + strSep 
				+ payment.LocalRequestReference + strSep 
				+ payment.CustomValues["strSalesOrderNumber"];
 
			html.Append("<input type=\"hidden\" name=\"CUSTID\" value=\"" + strCustIDConcat + "\">");
			html.Append("<input type=\"hidden\" name=\"METHOD\" value=\"CC\">");                                  
    
			html.Append("<input type=\"hidden\" name=\"EMAIL\" value=\"" + payment.UserInfo.UserDetails.EmailAddress + "\">");
            html.Append("<input type=\"hidden\" name=\"NAME\" value=\"" + payment.UserInfo.UserDetails.FirstName + " " + payment.UserInfo.UserDetails.LastName + "\">");
			html.Append("<input type=\"hidden\" name=\"ADDRESS\" value=\"" + payment.UserInfo.UserAddress.AddressLine1 + "\">");
			html.Append("<input type=\"hidden\" name=\"CITY\" value=\"" + payment.UserInfo.UserAddress.City + "\">");                  
			html.Append("<input type=\"hidden\" name=\"ZIP\" value=\"" + payment.UserInfo.UserAddress.Postcode + "\">");
			html.Append("<input type=\"hidden\" name=\"COUNTRY\" value=\"" + payment.UserInfo.UserAddress.CountryCode + "\">");   
    
			html.Append("<input type=\"hidden\" name=\"M_paymentType\" value=\"" + payment.CustomValues["strPaymentType"] + "\">");
			html.Append("<input type=\"hidden\" name=\"USER1\" value=\"" + payment.CustomValues["strPONumber"] + "\">");                             
			html.Append("<input type=\"hidden\" name=\"USER2\" value=\"" + payment.CustomValues["strText"] + "\">");
			html.Append("<input type=\"hidden\" name=\"USER3\" value=\"" + payment.UserInfo.UserAddress.AddressLine1 + "\">");
			html.Append("<input type=\"hidden\" name=\"USER4\" value=\"" + payment.UserInfo.UserAddress.AddressLine2 + "\">");
			html.Append("<input type=\"hidden\" name=\"USER5\" value=\"" + payment.UserInfo.UserAddress.City + "\">");
			html.Append("<input type=\"hidden\" name=\"USER6\" value=\"" + payment.UserInfo.UserAddress.Region + "\">");
			html.Append("<input type=\"hidden\" name=\"USER7\" value=\"" + payment.UserInfo.UserDetails.TelephoneNumber + "\">");
			html.Append("<input type=\"hidden\" name=\"USER8\" value=\"" + payment.UserInfo.UserDetails.FaxNumber + "\">");                          
			html.Append("<input type=\"hidden\" name=\"USER9\" value=\"" + payment.CustomValues["strdispatchLabel"] + "\">");
			html.Append("<input type=\"hidden\" name=\"USER10\" value=\"" + payment.CustomValues["strdispatchAccount"] + "\">"); 

			return html.ToString();

		}
		public override IElectronicPayment ProcessHttpResponse(HttpRequest postBackData, PaymentRequestTypes paymentType) {

			IElectronicPayment payment = new ElectronicPayment();

			if (DefaultCurrency == null) {
				DefaultCurrency = new Currency(DEFAULT_CULTURE);
			}

			try {
				payment.TransactionReference = postBackData["oid"];
				Money amount = new Money(DefaultCurrency, Decimal.Parse(postBackData["total"]));
				payment.PaymentAmount = amount;
				payment.PaymentDate = DateTime.Parse(postBackData["datetime"]);

				//EPDQ don't seem to have a reference. They will create a new one
				//if you don't supply a local reference
				payment.LocalRequestReference = payment.TransactionReference;

				//Make sure this request came from the right address
				if (IsAllowedRemoteAddress(postBackData)) {        
   
					string status = postBackData["transactionstatus"];

					switch (status.ToLower()) {
						case STATUS_SUCCESS:
							payment.TransactionStatus = PaymentStatus.Approved;
							break;
						case STATUS_DECLINED:
							payment.TransactionStatus = PaymentStatus.Declined;
							break;
						case STATUS_FRAUD:
							payment.TransactionStatus = PaymentStatus.Fraud;
							break;
						default:
							payment.TransactionStatus = PaymentStatus.Other;
							break;
					}
				} else {
					payment.TransactionStatus = PaymentStatus.Fraud;
				}

				LogResponse(payment, "ePDQ Status [" + postBackData["transactionstatus"] + "], " + GetResponseHttpLogInfo(postBackData));

			} catch (Exception e) {
				Logger.Error(e);
			}

			return payment;
		}
		protected override string RenderFormHiddenValues(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			string encryptedData = GetEpdqEncryptedData(payment, paymentType);

			if (encryptedData != null && encryptedData.Length > 0) {

				StringBuilder html = new StringBuilder();

				//Required data
				html.Append("<!-- Begin EPDQ Data -->\n");
				html.Append(encryptedData); //This includes its own input tag
				html.Append("<!-- End EPDQ Data -->\n");
				html.Append("<input type=\"hidden\" name=\"returnurl\" value=\"" + ReturnUrl + "\">\n");
				html.Append("<input type=\"hidden\" name=\"merchantdisplayname\" value=\"" + MerchantDisplayName + "\">\n");
				html.Append("<input type=\"hidden\" name=\"supportedcardtypes\" value=\"" + SupportedCardTypes + "\">\n");
        
				//Customisation information
				if (CpiTextColour != null && CpiTextColour.Length > 0) {
					html.Append("<input type=\"hidden\" name=\"cpi_textcolor\" value=\"" + CpiTextColour + "\">\n");
				}

				if (CpiBackgroundColour != null && CpiBackgroundColour.Length > 0) {
					html.Append("<input type=\"hidden\" name=\"cpi_bgcolor\" value=\"" + CpiBackgroundColour + "\">\n");
				}

				//This logo should be accessed via SSL to prevent browsers complaining
				if (CpiLogoUrl != null && CpiLogoUrl.Length > 0) {
					html.Append("<input type=\"hidden\" name=\"cpi_logo\" value=\"" + CpiLogoUrl + "\">\n");
				}

				if (payment.UserInfo != null) {
					//Optional data to make EPDQ form semi-complete
					html.Append("<input type=\"hidden\" name=\"email\" value=\"" + StringUtils.Left(payment.UserInfo.UserDetails.EmailAddress, 64) + "\">\n");                
					html.Append("<input type=\"hidden\" name=\"baddr1\" value=\"" + StringUtils.Left(payment.UserInfo.UserAddress.AddressLine1, 60) + "\">\n");
					html.Append("<input type=\"hidden\" name=\"baddr2\" value=\"" + StringUtils.Left(payment.UserInfo.UserAddress.AddressLine2, 60) + "\">\n");
					html.Append("<input type=\"hidden\" name=\"bcity\" value=\"" + StringUtils.Left(payment.UserInfo.UserAddress.City, 25) + "\">\n");
					html.Append("<input type=\"hidden\" name=\"bpostalcode\" value=\"" + StringUtils.Left(payment.UserInfo.UserAddress.Postcode, 9) + "\">\n");
					html.Append("<input type=\"hidden\" name=\"bcountry\" value=\"" + StringUtils.Left(payment.UserInfo.UserAddress.CountryCode, 3) + "\">\n");
        
					if (payment.UserInfo.UserAddress.Region == null || payment.UserInfo.UserAddress.Region.Length > 2) {
						//This is for non-US customers
						html.Append("<input type=\"hidden\" name=\"bcountyprovince\" value=\"" + StringUtils.Left(payment.UserInfo.UserAddress.Region, 25) + "\">\n");
					} else {
						//This is for US customers
						html.Append("<input type=\"hidden\" name=\"bstate value=\"" + StringUtils.Left(payment.UserInfo.UserAddress.Region, 2) + "\">\n");
					}
				}
            
				return html.ToString();

			} else {
				throw new ArgumentOutOfRangeException();
			}
		}
		protected override void CheckRequestParameters(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			if (ClientID == null || ClientID.Length == 0) {
				throw new ArgumentException("Invalid ClientID");
			}

			if (MerchantPassword == null || MerchantPassword.Length == 0) {
				throw new ArgumentException("Invalid MerchantPassword");
			}

			//CurrencyCode is three digits and numeric
			if (payment.PaymentAmount.CurrencyCode == null || payment.PaymentAmount.CurrencyCode.Length != 3) {
				throw new ArgumentException("Invalid CurrencyCode");
			}
		}
		protected override string RenderFormHiddenValues(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			StringBuilder html = new StringBuilder();

			switch (paymentType) {
				case PaymentRequestTypes.ImmediatePayment:
				case PaymentRequestTypes.ReservePayment:

					string authMode = AUTH_MODE_AUTH;
					if (paymentType == PaymentRequestTypes.ReservePayment) {
						authMode = AUTH_MODE_PREAUTH;
					}

					//obligatory fields
					html.Append("<input type=\"hidden\" name=\"instId\" value=\"" + InstallationID + "\">\n");
					html.Append("<input type=\"hidden\" name=\"cartId\" value=\"" + payment.LocalRequestReference + "\">\n");
					html.Append("<input type=\"hidden\" name=\"amount\" value=\"" + payment.PaymentAmount.Amount + "\">\n");
					html.Append("<input type=\"hidden\" name=\"currency\" value=\"" + payment.PaymentAmount.CurrencyCode + "\">\n");
					html.Append("<input type=\"hidden\" name=\"desc\" value=\"" + payment.Description + "\">\n");

					//Not strictly required
					html.Append("<input type=\"hidden\" name=\"authMode\" value=\"" + authMode + "\">\n");

					//Optional stuff
					if (Mode != TransactionMode.Production) {
						html.Append("<input type=\"hidden\" name=\"testMode\" value=\"" + ((int) WorldPayTestMode) + "\">\n");
					}

					//User stuff
					if (payment.UserInfo != null) {
                        html.Append("<input type=\"hidden\" name=\"name\" value=\"" + payment.UserInfo.UserDetails.FirstName + " " + payment.UserInfo.UserDetails.LastName + "\">\n");
						html.Append("<input type=\"hidden\" name=\"address\" value=\"" + payment.UserInfo.UserAddress.AddressLine1 + "\">\n");
						html.Append("<input type=\"hidden\" name=\"postcode\" value=\"" + payment.UserInfo.UserAddress.Postcode + "\">\n");
						html.Append("<input type=\"hidden\" name=\"country\" value=\"" + payment.UserInfo.UserAddress.CountryCode + "\">\n");
						html.Append("<input type=\"hidden\" name=\"tel\" value=\"" + payment.UserInfo.UserDetails.TelephoneNumber + "\">\n");
						html.Append("<input type=\"hidden\" name=\"email\" value=\"" + payment.UserInfo.UserDetails.EmailAddress + "\">\n");
					}

					//Custom values
					if (payment.CustomValues.Count > 0) {
						foreach (object key in payment.CustomValues.Keys) {
							html.Append("<input type=\"hidden\" name=\"M_" + key.ToString().Replace(" ", "-") + "\" value=\"" + payment.CustomValues[key].ToString() + "\">");
						}
					}

					break;
				default:
					throw new InvalidOperationException("Payment request type not supported [" + paymentType + "]");
			}

			return html.ToString();
		}
		protected override string RenderFormHiddenValues(IElectronicPayment payment, PaymentRequestTypes paymentType) {
			return null;
		}
		/// <summary>
		/// Transfers the client to the payment page
		/// </summary>
		/// <param name="isDebug">If true, doesn submit automatically</param>
		public override void TransferClientToPaymentPage(IElectronicPayment payment, PaymentRequestTypes paymentType, bool isDebug) {

			LogRequest(payment);

			//This may throw an exception if the request is invalid
			string pageUrl = GetPaymentPageUrl(payment, paymentType);

			//payment now contains the transaction reference
			if (_paymentHandler != null) {
				//Tell the handler to store the transaction reference so we can find it again later
				_paymentHandler.HandleChange(this, payment);
			}

			HttpResponse response = HttpContext.Current.Response;

			response.Write("<html>\n");

			if (isDebug == false) {
				//Auto submit this form
				response.Write("<body onLoad=\"document.forms[0].submit();\">\n");
			} else {
				response.Write("<body>\n");
			}

			response.Write("<form method=\"POST\" action=\"" + pageUrl + "\">\n");

			if (isDebug) {
				//Show a button to submit this form when in debug mode
				response.Write("Press the button to submit this payment request<br/><br/>");
				response.Write("<input type=\"submit\" value=\"send\">");
			}

			response.Write("</form>\n");
			response.Write("</body>\n</html>");

			response.End();
		}
		/// <summary>
		/// Transfers the client to the payment page
		/// </summary>
		/// <param name="isDebug">If true, doesn submit automatically</param>
		public virtual void TransferClientToPaymentPage(IElectronicPayment payment, PaymentRequestTypes paymentType, bool isDebug) {

			LogRequest(payment);

			HttpResponse response = HttpContext.Current.Response;

			response.Write("<html>\n");

			if (isDebug == false) {
				//Auto submit this form
				response.Write("<body onLoad=\"document.forms[0].submit();\">\n");
			} else {
				response.Write("<body>\n");
			}

			response.Write("<form method=\"POST\" action=\"" + PaymentPageUrl + "\">\n");
			response.Write(RenderFormHiddenValues(payment, paymentType));

			if (isDebug) {
				//Show a button to submit this form when in debug mode
				response.Write("Press the button to submit this payment request<br><br>");
				response.Write("<input type=\"submit\" value=\"send\">");
			}

			response.Write("</form>\n");
			response.Write("</body>\n</html>");

			try {
				response.End();
			} catch {
				//Why doesn't this stop a further exception being thrown?
			}
		}
		public override IElectronicPayment ProcessHttpResponse(HttpRequest postBackData, PaymentRequestTypes paymentType) {

			/*
				https://www.mymerchant.com/Success.jsp
				?orderKey=MYADMINCODE^MYMERCHANT^T0211010
				&paymentStatus=AUTHORISED
				&paymentAmount=1400
				&paymentCurrency=GBP
				&mac=25eefe952a6bbd09fe1c2c09bca4fa09
			 */

			if (!IsCallbackAuthenticated(postBackData)) {
				throw new InvalidOperationException("Invalid details supplied - MAC check failed");
			}

			IElectronicPayment payment = new ElectronicPayment();

			payment.PaymentDate = DateTime.Now;
			payment.TransactionStatus = (postBackData[REQUEST_FIELD_PAYMENT_STATUS] == "AUTHORISED") ? PaymentStatus.Approved : PaymentStatus.Declined;

			string orderKey = postBackData[REQUEST_FIELD_ORDER_KEY];
			string[] orderInfo = new string[] {};

			if (orderKey != null && orderKey.Length > 0) {
				orderInfo = orderKey.Split(ORDER_KEY_DELIMITER.ToCharArray());
			}

			if (orderInfo.Length == ORDER_KEY_LENGTH) {

				string mac = postBackData[REQUEST_FIELD_MAC];
				string orderRef = orderInfo[2];
			
				//Maybe check other parameters as well
				/*
				 * Not documented, but it appears that when you use a mac secret, the order reference becomes the
				 * original local reference number, NOT the transaction reference
				 */
				if (mac != null && mac.Length > 0) {
					payment.LocalRequestReference = orderRef;
				} else {
					payment.TransactionReference = orderRef;
				}

				payment.PaymentAmount = GetPaymentAmount(postBackData);
			
			} else {
				//Something wrong with the values
				payment.TransactionStatus = PaymentStatus.Other;
			}

			//Record the details
			LogResponse(payment);

			return payment;
		}
		/// <summary>
		/// Transfers automatically
		/// </summary>
		public virtual void TransferClientToPaymentPage(IElectronicPayment payment, PaymentRequestTypes paymentType) {
			TransferClientToPaymentPage(payment, paymentType, false);
		}
		/// <summary>
		/// Handles the post back from the payment gateway
		/// </summary>
		/// <param name="postBackData"></param>
		/// <param name="paymentType"></param>
		/// <returns></returns>
		public abstract IElectronicPayment ProcessHttpResponse(HttpRequest postBackData, PaymentRequestTypes paymentType);
		protected abstract string RenderFormHiddenValues(IElectronicPayment payment, PaymentRequestTypes paymentType);
		protected virtual void CheckRequestParameters(IElectronicPayment payment, PaymentRequestTypes paymentType) {
		}
		public virtual string GetPaymentPageUrl(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			/*
			<?xml version="1.0"?>
			<!DOCTYPE paymentService PUBLIC "-//streamline-esolutions//DTD streamline-esolutions PaymentService v1//EN"
			"http://dtd.streamline-esolutions.com/paymentService_v1.dtd">
			<paymentService merchantCode="MYMERCHANT" version="1.4">
				<reply>
					<orderStatus orderCode="T0211010">
						<reference id="1234567">
						https://secure.streamline-esolutions.com/jsp/shopper/SelectPaymentMethod.jsp?orderKey=MYMERCHANT^T0211010
						</reference>
					</orderStatus>
				</reply>
			</paymentService>
			*/

			Logger.Info("Getting Streamline URL, OrderID [" + payment.LocalRequestReference + "], Value [" + payment.PaymentAmount.Amount + " " + payment.PaymentAmount.CurrencyCode + "]");

			string outXml = CreateXML(payment);
			string inXml = PostXml(PaymentPageUrl, outXml, 0);

			XmlDocument doc = new XmlDocument();
			doc.LoadXml(inXml);

			XmlNode pageUrl = doc.SelectSingleNode("//paymentService/reply/orderStatus/reference");
			XmlNode orderCode = doc.SelectSingleNode("//paymentService/reply/orderStatus/@orderCode");
			XmlNode referenceID = doc.SelectSingleNode("//paymentService/reply/orderStatus/reference/@id");

			if (IsValidOrder(referenceID, orderCode, pageUrl)) {

				Logger.Info("Streamline created reference [" + referenceID.Value + "] for OrderID [" + payment.LocalRequestReference + "]");

				//Put the transaction reference into the payment so we can refer to it later
				payment.TransactionReference = referenceID.Value;

				string url = pageUrl.InnerText;

				//Optional stuff
				if (CountryCode != null && CountryCode.Length == 2) {
					url += GetNameValue("country", CountryCode);
				} else {

                    //Is this correct? 
                    if (payment.UserInfo.UserAddress.CountryCode != null && payment.UserInfo.UserAddress.CountryCode.Length == 2) {
                        url += GetNameValue("country", payment.UserInfo.UserAddress.CountryCode);
					}
				}

				url += GetNameValue("language", LanguageCode);
				url += GetNameValue("bodyAttr", BodyAttributes);
				url += GetNameValue("fontAttr", FontAttributes);
				url += GetNameValue("successURL", SuccessUrl);
				url += GetNameValue("failureURL", FailureUrl);
				url += GetNameValue("preferredPaymentMethod", PreferredPaymentMethod);

				return url;

			} else {
				Logger.Info("Streamline failure, OrderID [" + payment.LocalRequestReference + "]");
				if (outXml != null && outXml.Length > 0) Logger.Info("Sent: [" + outXml + "]");
				if (inXml != null && inXml.Length > 0) Logger.Info("Received: [" + inXml + "]");
			}

			throw new InvalidOperationException("Payment rejected by provider");
		}
		protected override void CheckRequestParameters(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			if (InstallationID == null || InstallationID.Length == 0) {
				throw new InvalidOperationException("Invalid Installation ID");
			}

			if (payment.LocalRequestReference == null || payment.LocalRequestReference.Length == 0) {
				throw new InvalidOperationException("Invalid Local Reference");
			}

			if (payment.PaymentAmount == null || payment.PaymentAmount.Amount < 0) {
				throw new InvalidOperationException("Invalid Payment Amount");
			}
		}
		private string GetEpdqEncryptedData(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			if (paymentType != PaymentRequestTypes.ImmediatePayment && paymentType != PaymentRequestTypes.ReservePayment) {
				throw new ArgumentException("Invalid payment type");
			}

			string encryptionRequestData = "";
			string encryptedResponseData;
            
			//POST some initial data to see if (the service is available...
			//Record this request
			Logger.Info("Getting EPDQ Encrypted Data, OrderID:" + payment.LocalRequestReference + ", Value:" + payment.PaymentAmount.Amount + " " + payment.PaymentAmount.CurrencyCode);
        
			//Build the data to post
			encryptionRequestData = "clientid=" + ClientID
				+ "&password="******"&chargetype=" + ((paymentType == PaymentRequestTypes.ImmediatePayment) ? BANK_CHARGE_TYPE_IMMEDIATE_SALE : BANK_CHARGE_TYPE_RESERVE_PAYMENT)
				+ "&currencycode=" + payment.PaymentAmount.Currency.CurrencyCodeNumeric
				+ "&total=" + payment.PaymentAmount.Amount.ToString("0.00")
				+ "&oid=" + payment.LocalRequestReference;
        
			//Get encrypted data from EPDQ server
			try {

				encryptedResponseData = HttpUtils.ReadHtmlPage(EncryptionUrl, "POST", encryptionRequestData);
                
				if (encryptedResponseData.ToLower().IndexOf(BANK_ERR_TEXT.ToLower()) > -1) {
            
					//Record this in the log
					throw new Exception("EPDQ connection refused by server");
				}
 
				//Record this was successful
				Logger.Info("EPDQ Encrypted Data OK, OrderID:" + payment.LocalRequestReference);
            
			} catch (Exception e) {
				Logger.Info("EPDQ failure, OrderID:" + payment.LocalRequestReference, e);
				encryptedResponseData = null;
			}

			return encryptedResponseData;

		}
		public override IElectronicPayment ProcessHttpResponse(HttpRequest postBackData, PaymentRequestTypes paymentType) {
			
			IElectronicPayment payment = new ElectronicPayment();

			switch (paymentType) {
				case PaymentRequestTypes.ImmediatePayment:
				case PaymentRequestTypes.ReservePayment:

					try {

						Currency currency = GetPaymentCurrency(postBackData);
						payment.LocalRequestReference = postBackData["cartId"];
						Money amount = new Money(currency, Decimal.Parse(postBackData["authAmount"]));
						payment.PaymentAmount = amount;

						SetPaymentDate(postBackData, payment);

						//Make sure this request came from the right address
						if (IsAllowedRemoteAddress(postBackData) && IsCallbackAuthenticated(postBackData)) {        
   
							string status = postBackData["transStatus"];

							switch (status.ToUpper()) {
								case STATUS_SUCCESS:
									payment.TransactionStatus = PaymentStatus.Approved;
									payment.TransactionReference = postBackData["transId"];
									break;
								case STATUS_DECLINED:
									payment.TransactionStatus = PaymentStatus.Declined;
									break;
								default:
									payment.TransactionStatus = PaymentStatus.Other;
									break;
							}
						} else {
							payment.TransactionStatus = PaymentStatus.Fraud;
						}

						LogResponse(payment, "WorldPay Status [" + postBackData["transStatus"]
							+ "], Raw Auth Code [" + postBackData["rawAuthCode"] 
							+ "], Raw Auth Message [" + postBackData["rawAuthMessage"] 
							+ "], " + GetResponseHttpLogInfo(postBackData));

					} catch (Exception e) {
						Logger.Error(e);
					}

					try {
						//payment.UserInfo.UserName = postBackData["name"];
						payment.UserInfo.UserAddress.Postcode = postBackData["postcode"];
						payment.UserInfo.UserDetails.EmailAddress = postBackData["email"];
						payment.UserInfo.UserAddress.AddressLine1 = postBackData["address"];
						payment.UserInfo.UserAddress.CountryCode = postBackData["countryString"];
						payment.UserInfo.UserDetails.TelephoneNumber = postBackData["tel"];
						payment.UserInfo.UserDetails.FaxNumber = postBackData["fax"];
					} catch (Exception f) {
						Logger.Error(f);
					}

					return payment;

				default:
					throw new InvalidOperationException("Payment request type not supported [" + paymentType + "]");			
			}
		}
		protected override void CheckRequestParameters(IElectronicPayment payment, PaymentRequestTypes paymentType) {

			base.CheckRequestParameters (payment, paymentType);

			FuturePayElectronicPayment fPayment = payment as FuturePayElectronicPayment;

			if (fPayment == null) {
				throw new InvalidOperationException("Invalid payment type");
			}

			if (fPayment.AgreementOption != (int) FuturePayAgreementOption.FixedAmount
				&& fPayment.AgreementOption != (int) FuturePayAgreementOption.VariableDefineAmountAtStart
				&& fPayment.AgreementOption != (int) FuturePayAgreementOption.VariableDefineAmountInCMS) {
				throw new InvalidOperationException("Invalid Agreement Option");
			}

			if (fPayment.StartDate != SqlUtils.MinSqlDateTime) {
					
				if (fPayment.StartDate < DateTime.Now) {
					throw new InvalidOperationException("Invalid start date");
				}

				if (fPayment.AgreementOption == (int) FuturePayAgreementOption.VariableDefineAmountInCMS 
					&& fPayment.StartDate < DateTime.Now.AddDays(14)) {
					throw new InvalidOperationException("Invalid start date (at least two weeks)");
				}

			} else {

				if (fPayment.StartDelayMult < 1) {
					throw new InvalidOperationException("Invalid start delay (delay >= 1)");
				}

				if (fPayment.AgreementOption == (int) FuturePayAgreementOption.VariableDefineAmountInCMS 
					&& fPayment.StartDelayDays < 14) {
					throw new InvalidOperationException("Invalid start delay (at least two weeks)");
				}
			}

			if (fPayment.NumberOfPayments < 0) {
				throw new InvalidOperationException("Invalid number of payments");
			}

			if (fPayment.NumberOfPayments != FuturePaySelectJuniorPaymentProvider.NUMBER_OF_PAYMENTS_UNLIMITED 
				&& fPayment.NumberOfPayments > 1 && fPayment.IntervalDays < 14) {
				throw new InvalidOperationException("Invalid interval (at least two weeks)");
			}

			if (fPayment.InitialAmount != null && fPayment.InitialAmount.Amount < 0) {
				throw new InvalidOperationException("Invalid initial amount");
			}

			if (fPayment.AgreementOption == (int) FuturePayAgreementOption.VariableDefineAmountInCMS
				&& fPayment.InitialAmount.Amount > 0) {
				throw new InvalidOperationException("Cannot set Initial amount for this agreement option [" + fPayment.AgreementOption + "]");
			}

			if (fPayment.AgreementOption == (int) FuturePayAgreementOption.VariableDefineAmountInCMS) {
				if (fPayment.NormalAmount != null && fPayment.NormalAmount.Amount != 0) {
					throw new InvalidOperationException("Cannot set normal amount for this agreement option [" + fPayment.AgreementOption + "]");
				}
			} else {
				if (fPayment.NormalAmount == null || fPayment.NormalAmount.Amount == 0) {
					throw new InvalidOperationException("Must set normal amount for this agreement option [" + fPayment.AgreementOption + "]");
				}
			}
		}