private void FailurePayment (JudoError error, PaymentReceiptModel receipt)
		{
			DispatchQueue.MainQueue.DispatchAfter (DispatchTime.Now, () => {
				// move back to home screen
				CloseView ();
				// show receipt
				string message = "";
				if (error != null && error.ApiError != null)
					message += error.ApiError.ErrorMessage + Environment.NewLine;

				if (error != null && error.Exception != null)
					message += error.Exception.Message + Environment.NewLine;

				if (receipt != null) {
					message += "Transaction : " + receipt.Result + Environment.NewLine;
					message += receipt.Message + Environment.NewLine;
					message += "Receipt ID - " + receipt.ReceiptId;
				}

				ShowMessage ("Transaction Failed: ", message);
				// store token to further use
			});
		}
		public void MakeTokenPayment ()
		{
			try {

				JudoSDKManager.ShowLoading (this.View);
				var instance = JudoConfiguration.Instance;
				tokenPayment.CV2 = tokenCell.CCV;

				PaymentButton.Disable();

				_paymentService.MakeTokenPreAuthorisation (tokenPayment).ContinueWith (reponse => {
					var result = reponse.Result;
					if (result != null && !result.HasError && result.Response.Result != "Declined") {
						PaymentReceiptModel paymentreceipt = result.Response as PaymentReceiptModel;
						// call success callback
						if (successCallback != null)
							successCallback (paymentreceipt);
					} else {
						// Failure callback
						if (failureCallback != null) {
							var judoError = new JudoError { ApiError = result != null ? result.Error : null };
							var paymentreceipt = result != null ? result.Response as PaymentReceiptModel : null;

							if (paymentreceipt != null) {
								// send receipt even we got card declined
								failureCallback (judoError, paymentreceipt);
							} else {
								failureCallback (judoError);
							}
						}


					}
					JudoSDKManager.HideLoading ();
				});
			} catch (Exception ex) {
				JudoSDKManager.HideLoading ();
				// Failure callback
				if (failureCallback != null) {
					var judoError = new JudoError { Exception = ex };
					failureCallback (judoError);
				}
			}


		}
		public SecureWebView(IntPtr p) : base(p)
		{
			this.LoadFinished+= delegate {
				this.ScrollView.SetZoomScale(2.0f,true);
			};
			this.ShouldStartLoad = (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType) => {
				
				if(request.Url.ToString().Contains("threedsecurecallback") && ReceiptID !=null)
				{
					Dictionary<string,string> queryStringDictionary = new Dictionary<string,string>();

					var TrackTraceDataArray = request.Body.ToString().Split (new char[] { '&' });

					foreach (string keyValuePair in TrackTraceDataArray)
					{
						var pairComponents = keyValuePair.Split (new char[] { '=' });
						string key =pairComponents.First();
						string value =pairComponents.Last();
						queryStringDictionary.Add(key,value);
					}

					_paymentService.CompleteDSecure (ReceiptID,queryStringDictionary["PaRes"],queryStringDictionary["MD"]).ContinueWith (reponse => {
						var result = reponse.Result;
						if (result != null && !result.HasError && result.Response.Result != "Declined") {
							var paymentreceipt = result.Response as PaymentReceiptModel;

							if (paymentreceipt != null) {
								// call success callback
								if (_successCallback != null)

									_successCallback (paymentreceipt);
								
							} else {
								throw new Exception ("JudoXamarinSDK: unable to find the receipt in response.");
							}

						} else {
							// Failure callback
							if (_failureCallback != null) {
								var judoError = new JudoError { ApiError = result != null ? result.Error : null };
								var paymentreceipt = result != null ? result.Response as PaymentReceiptModel : null;

								if (paymentreceipt != null) {
									// send receipt even we got card declined

									_failureCallback (judoError, paymentreceipt);

								} else {

									_failureCallback (judoError);

								}
							}
						}
					});

				}

				return true;
		};
		}
        private void HandleResponse(Task<IResult<ITransactionResult>> reponse)
	    {
			var result = reponse.Result;
			if (JudoSDKManager.ThreeDSecureEnabled && result.Response != null && result.Response.GetType () == typeof(PaymentRequiresThreeDSecureModel)) {

				var threedDSecureReceipt = result.Response as PaymentRequiresThreeDSecureModel;

				JudoSDKManager.SummonThreeDSecure (threedDSecureReceipt, SWebView);

			} else {
				try {
					if (result != null && !result.HasError && result.Response.Result != "Declined") {
						var paymentreceipt = result.Response as PaymentReceiptModel;

						if (paymentreceipt != null) {
							// call success callback
							if (successCallback != null)
								successCallback (paymentreceipt);
						} else {
							var threedDSecureReceipt = result.Response as PaymentRequiresThreeDSecureModel;
							if(threedDSecureReceipt!=null)
							{
								failureCallback (new JudoError {ApiError = new JudoPayDotNet.Errors.JudoApiErrorModel{ErrorMessage ="Account requires 3D Secure but application is not configured to accept it", ErrorType = JudoApiError.General_Error, ModelErrors = null }});
							}
							else
							{
								throw new Exception ("JudoXamarinSDK: unable to find the receipt in response.");
							}
						}

					} else {
						// Failure callback
						if (failureCallback != null) {
							var judoError = new JudoError { ApiError = result != null ? result.Error : null };
							var paymentreceipt = result != null ? result.Response as PaymentReceiptModel : null;

							if (paymentreceipt != null) {
								// send receipt even we got card declined
								failureCallback (judoError, paymentreceipt);
							} else {
								failureCallback (judoError);
							}
						}

					}
					JudoSDKManager.HideLoading ();
				} catch (Exception ex) {
					JudoSDKManager.HideLoading ();
					// Failure callback
					if (failureCallback != null) {
						var judoError = new JudoError { Exception = ex };
						failureCallback (judoError);
					}
				}
			}
	    }
		private void PreAuthCard ()
		{
			try {

				JudoSDKManager.ShowLoading (this.View);
				authorisationModel.Card = GatherCardDetails ();

				RegisterButton.Disable();

                _paymentService.PreAuthoriseCard(authorisationModel).ContinueWith(HandleResponse);
                
		    }
            catch (Exception ex)
            {
                JudoSDKManager.HideLoading();
                // Failure callback
                if (failureCallback != null)
                {
                    var judoError = new JudoError { Exception = ex };
                    failureCallback(judoError);
                }
            }


		}
		private void MakePayment ()
		{
			try {
				JudoSDKManager.ShowLoading (this.View);
             
				cardPayment.Card = GatherCardDetails ();

				SubmitButton.Disable ();

				_paymentService.MakePayment (cardPayment).ContinueWith (reponse => {
					var result = reponse.Result;
					if (JudoSDKManager.ThreeDSecureEnabled && result.Response != null && result.Response.GetType () == typeof(PaymentRequiresThreeDSecureModel)) {

						var threedDSecureReceipt = result.Response as PaymentRequiresThreeDSecureModel;


					JudoSDKManager.SummonThreeDSecure(threedDSecureReceipt,SecureWebView);

					} else {
						if (result != null && !result.HasError && result.Response.Result != "Declined") {
							var paymentreceipt = result.Response as PaymentReceiptModel;

							if (paymentreceipt != null) {
								// call success callback
								if (successCallback != null)
									successCallback (paymentreceipt);
								} 
								else 
								{
								var threedDSecureReceipt = result.Response as PaymentRequiresThreeDSecureModel;
								if(threedDSecureReceipt!=null)
								{
									failureCallback (new JudoError {ApiError = new JudoPayDotNet.Errors.JudoApiErrorModel{ErrorMessage ="Account requires 3D Secure but application is not configured to accept it", ErrorType = JudoApiError.General_Error, ModelErrors = null }});
								}
								else
								{
								throw new Exception ("JudoXamarinSDK: unable to find the receipt in response.");
								}
							}

						} else {
							// Failure callback
							if (failureCallback != null) {
								var judoError = new JudoError { ApiError = result != null ? result.Error : null };
								var paymentreceipt = result != null ? result.Response as PaymentReceiptModel : null;

								if (paymentreceipt != null) {
									// send receipt even we got card declined

									failureCallback (judoError, paymentreceipt);
								} else {

									failureCallback (judoError);
								}
							}
						}

						JudoSDKManager.HideLoading ();
					}
				});

			} catch (Exception ex) {
				JudoSDKManager.HideLoading ();
				// Failure callback
				if (failureCallback != null) {
					var judoError = new JudoError { Exception = ex };
					failureCallback (judoError);
				}
			}
	
		}
		public static void SummonThreeDSecure (PaymentRequiresThreeDSecureModel threedDSecureReceipt, SecureWebView secureWebView)
		{
			secureWebView.ReceiptID =	threedDSecureReceipt.ReceiptId;

			NSCharacterSet allowedCharecterSet = NSCharacterSet.FromString (@":/=,!$&'()*+;[]@#?").InvertedSet;
			NSString paReq = new NSString (threedDSecureReceipt.PaReq);
			var encodedPaReq = paReq.CreateStringByAddingPercentEncoding (allowedCharecterSet);

			NSString termUrl = new NSString ("judo1234567890://threedsecurecallback");
			var encodedTermUrl = termUrl.CreateStringByAddingPercentEncoding (allowedCharecterSet);


			NSUrl url = new NSUrl (threedDSecureReceipt.AcsUrl);

			NSMutableUrlRequest req = new NSMutableUrlRequest (url);

			NSString postString = new NSString ("MD=" + threedDSecureReceipt.Md + "&PaReq=" + encodedPaReq + "&TermUrl=" + encodedTermUrl + "");
			NSData postData = postString.Encode (NSStringEncoding.UTF8);

			req.HttpMethod = "POST";
			req.Body = postData;

			try {
				DispatchQueue.MainQueue.DispatchAfter (DispatchTime.Now, () => {
					secureWebView.LoadRequest (req);

					JudoSDKManager.HideLoading ();
					secureWebView.Hidden = false;
				});
			} catch (Exception e) {
				if (secureWebView._failureCallback != null) {
					var judoError = new JudoError { Exception = e };
					secureWebView._failureCallback (judoError);
				}
			}
		}
        /// <summary>
        /// Process a RegisterCard
        /// </summary>
        /// <param name="registerCard">TokenPaymentViewModel to pass Amount and Token detail</param>
        /// <param name="success">Callback for success transaction</param>
        /// <param name="failure">Callback for fail transaction</param>
        /// <param name="navigationController">Navigation controller from UI this can be Null for non-UI Mode API</param>
		public static void RegisterCard (PaymentViewModel registerCard, SuccessCallback success, FailureCallback failure, UINavigationController navigationController)
		{
			var innerModel = registerCard.Clone ();
			if (UIMode && navigationController == null) {
				var error = new JudoError { Exception = new Exception ("Navigation controller cannot be null with UIMode enabled.") };
				failure (error);
			} else {
                _judoSdkApi.RegisterCard(innerModel, success, failure, navigationController);
			}
		}
        /// <summary>
        /// Process a token authorisation payment
        /// </summary>
        /// <param name="payment">TokenPaymentViewModel to pass Amount and Token detail</param>
        /// <param name="success">Callback for success transaction</param>
        /// <param name="failure">Callback for fail transaction</param>
        /// <param name="navigationController">Navigation controller from UI this can be Null for non-UI Mode API</param>
		public static void TokenPreAuth (TokenPaymentViewModel payment, SuccessCallback success, FailureCallback failure, UINavigationController navigationController)
		{
			var innerModel = payment.Clone ();
			if (UIMode && navigationController == null) {
				var error = new JudoError { Exception = new Exception ("Navigation controller cannot be null with UIMode enabled.") };
				failure (error);
			} else {
				_judoSdkApi.TokenPreAuth (innerModel, success, failure, navigationController);
			}
		}