/// <summary>
        /// Combines various responses into one.
        /// </summary>
        /// <param name="tokenizeResponse">The tokenize response.</param>
        /// <param name="authorizeResponse">The authorize response.</param>
        /// <param name="captureResponse">The capture response.</param>
        /// <param name="voidResponse">The void response.</param>
        /// <returns>The combined response.</returns>
        private Response CombineResponses(Response tokenizeResponse, Response authorizeResponse, Response captureResponse, Response voidResponse)
        {
            Response paymentResponse = new Response();
            var      properties      = new List <PaymentProperty>();
            var      errors          = new List <PaymentError>();

            if (tokenizeResponse != null)
            {
                // Start with tokenize response
                paymentResponse.Locale = tokenizeResponse.Locale;

                if (tokenizeResponse.Properties != null)
                {
                    properties.AddRange(tokenizeResponse.Properties);
                }

                if (tokenizeResponse.Errors != null)
                {
                    errors.AddRange(tokenizeResponse.Errors);
                }

                // Merge with authorize response
                if (authorizeResponse != null)
                {
                    if (authorizeResponse.Properties != null)
                    {
                        var             authorizeResponseProperties    = PaymentProperty.ConvertToHashtable(authorizeResponse.Properties);
                        PaymentProperty innerAuthorizeResponseProperty = PaymentProperty.GetPropertyFromHashtable(
                            authorizeResponseProperties,
                            GenericNamespace.AuthorizationResponse,
                            AuthorizationResponseProperties.Properties);
                        properties.Add(innerAuthorizeResponseProperty);
                    }

                    if (authorizeResponse.Errors != null)
                    {
                        errors.AddRange(authorizeResponse.Errors);
                    }
                }
            }
            else if (authorizeResponse != null)
            {
                // Start with Authorize response
                paymentResponse.Locale = authorizeResponse.Locale;

                if (authorizeResponse.Properties != null)
                {
                    properties.AddRange(authorizeResponse.Properties);
                }

                if (authorizeResponse.Errors != null)
                {
                    errors.AddRange(authorizeResponse.Errors);
                }
            }

            // Merge with authorize response
            if (captureResponse != null)
            {
                if (captureResponse.Properties != null)
                {
                    var             captureResponseProperties    = PaymentProperty.ConvertToHashtable(captureResponse.Properties);
                    PaymentProperty innerCaptureResponseProperty = PaymentProperty.GetPropertyFromHashtable(
                        captureResponseProperties,
                        GenericNamespace.CaptureResponse,
                        CaptureResponseProperties.Properties);
                    properties.Add(innerCaptureResponseProperty);
                }

                if (captureResponse.Errors != null)
                {
                    errors.AddRange(captureResponse.Errors);
                }
            }

            // Merge with void response
            if (voidResponse != null)
            {
                if (voidResponse.Properties != null)
                {
                    var             voidResponseProperties    = PaymentProperty.ConvertToHashtable(voidResponse.Properties);
                    PaymentProperty innerVoidResponseProperty = PaymentProperty.GetPropertyFromHashtable(
                        voidResponseProperties,
                        GenericNamespace.VoidResponse,
                        VoidResponseProperties.Properties);
                    properties.Add(innerVoidResponseProperty);
                }

                if (voidResponse.Errors != null)
                {
                    errors.AddRange(voidResponse.Errors);
                }
            }

            if (properties.Count > 0)
            {
                paymentResponse.Properties = properties.ToArray();
            }

            if (errors.Count > 0)
            {
                paymentResponse.Errors = errors.ToArray();
            }

            return(paymentResponse);
        }
        /// <summary>
        /// Process the card payment, e.g. Tokenize, Authorize, Capture.
        /// </summary>
        /// <param name="paymentEntry">The card payment entry.</param>
        /// <returns>The payment result.</returns>
        private CardPaymentResult ProcessPayment(CardPaymentEntry paymentEntry)
        {
            // Get payment processor
            var processor = new SampleConnector();

            // Prepare payment request
            var paymentRequest = new Request();

            paymentRequest.Locale = paymentEntry.EntryLocale;

            // Get payment properties from payment entry which contains the merchant information.
            Request entryData = JsonConvert.DeserializeObject <Request>(paymentEntry.EntryData);

            PaymentProperty[] entryPaymentProperties = entryData.Properties;
            var requestProperties = new List <PaymentProperty>();

            // Filter payment card properties (they are default card data, not final card data)
            foreach (var entryPaymentProperty in entryPaymentProperties)
            {
                if (entryPaymentProperty.Namespace != GenericNamespace.PaymentCard)
                {
                    requestProperties.Add(entryPaymentProperty);
                }
            }

            // Add final card data
            PaymentProperty property;

            if (this.isSwipe)
            {
                property = new PaymentProperty(
                    GenericNamespace.PaymentCard,
                    PaymentCardProperties.CardEntryType,
                    CardEntryTypes.MagneticStripeRead.ToString());
                requestProperties.Add(property);

                if (!string.IsNullOrWhiteSpace(this.track1))
                {
                    property = new PaymentProperty(
                        GenericNamespace.PaymentCard,
                        PaymentCardProperties.Track1,
                        this.track1);
                    requestProperties.Add(property);
                }

                if (!string.IsNullOrWhiteSpace(this.track2))
                {
                    property = new PaymentProperty(
                        GenericNamespace.PaymentCard,
                        PaymentCardProperties.Track2,
                        this.track2);
                    requestProperties.Add(property);
                }
            }
            else
            {
                property = new PaymentProperty(
                    GenericNamespace.PaymentCard,
                    PaymentCardProperties.CardEntryType,
                    CardEntryTypes.ManuallyEntered.ToString());
                requestProperties.Add(property);
            }

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.CardType,
                this.cardType);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.CardNumber,
                this.cardNumber);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.ExpirationMonth,
                this.cardExpirationMonth);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.ExpirationYear,
                this.cardExpirationYear);
            requestProperties.Add(property);

            if (!string.IsNullOrWhiteSpace(this.cardSecurityCode))
            {
                property = new PaymentProperty(
                    GenericNamespace.PaymentCard,
                    PaymentCardProperties.AdditionalSecurityData,
                    this.cardSecurityCode);
                requestProperties.Add(property);
            }

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.Name,
                this.cardHolderName);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.StreetAddress,
                this.cardStreet1);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.City,
                this.cardCity);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.State,
                this.cardStateOrProvince);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.PostalCode,
                this.cardPostalCode);
            requestProperties.Add(property);

            property = new PaymentProperty(
                GenericNamespace.PaymentCard,
                PaymentCardProperties.Country,
                this.cardCountryOrRegion);
            requestProperties.Add(property);

            // Tokenize the card if requested
            Response tokenizeResponse = null;

            if (paymentEntry.SupportCardTokenization)
            {
                paymentRequest.Properties = requestProperties.ToArray();
                tokenizeResponse          = processor.GenerateCardToken(paymentRequest, null);
                if (tokenizeResponse.Errors != null && tokenizeResponse.Errors.Any())
                {
                    // Tokenization failure, Throw an exception and stop the payment.
                    throw new CardPaymentException("Tokenization failure.", tokenizeResponse.Errors);
                }
            }

            // Authorize and Capture if requested
            // Do not authorize if tokenization failed.
            Response        authorizeResponse = null;
            Response        captureResponse   = null;
            Response        voidResponse      = null;
            TransactionType transactionType   = (TransactionType)Enum.Parse(typeof(TransactionType), paymentEntry.TransactionType, true);

            if (transactionType == TransactionType.Authorize || transactionType == TransactionType.Capture)
            {
                // Add request properties for Authorize and Capture
                if (!string.IsNullOrWhiteSpace(this.voiceAuthorizationCode))
                {
                    property = new PaymentProperty(
                        GenericNamespace.PaymentCard,
                        PaymentCardProperties.VoiceAuthorizationCode,
                        this.voiceAuthorizationCode);
                    requestProperties.Add(property);
                }

                property = new PaymentProperty(
                    GenericNamespace.TransactionData,
                    TransactionDataProperties.Amount,
                    this.paymentAmount);
                requestProperties.Add(property);

                // Authorize payment
                paymentRequest.Properties = requestProperties.ToArray();
                authorizeResponse         = processor.Authorize(paymentRequest, null);
                if (authorizeResponse.Errors != null && authorizeResponse.Errors.Any())
                {
                    // Authorization failure, Throw an exception and stop the payment.
                    throw new CardPaymentException("Authorization failure.", authorizeResponse.Errors);
                }

                if (transactionType == TransactionType.Capture)
                {
                    // Check authorization result
                    var             authorizeResponseProperties    = PaymentProperty.ConvertToHashtable(authorizeResponse.Properties);
                    PaymentProperty innerAuthorizeResponseProperty = PaymentProperty.GetPropertyFromHashtable(
                        authorizeResponseProperties,
                        GenericNamespace.AuthorizationResponse,
                        AuthorizationResponseProperties.Properties);

                    var innerAuthorizeResponseProperties = PaymentProperty.ConvertToHashtable(innerAuthorizeResponseProperty.PropertyList);

                    string authorizationResult = null;
                    PaymentProperty.GetPropertyValue(
                        innerAuthorizeResponseProperties,
                        GenericNamespace.AuthorizationResponse,
                        AuthorizationResponseProperties.AuthorizationResult,
                        out authorizationResult);

                    // TO DO: In this sample, we only check the authorization results. CVV2 result and AVS result are ignored.
                    if (AuthorizationResult.Success.ToString().Equals(authorizationResult, StringComparison.OrdinalIgnoreCase))
                    {
                        // Authorize success...
                        // Get authorized amount
                        decimal authorizedAmount = 0m;
                        PaymentProperty.GetPropertyValue(
                            innerAuthorizeResponseProperties,
                            GenericNamespace.AuthorizationResponse,
                            AuthorizationResponseProperties.ApprovedAmount,
                            out authorizedAmount);

                        // Update capture amount for partial authorization
                        if (this.paymentAmount != authorizedAmount)
                        {
                            foreach (var requestProperty in requestProperties)
                            {
                                if (GenericNamespace.TransactionData.Equals(requestProperty.Namespace) &&
                                    TransactionDataProperties.Amount.Equals(requestProperty.Name))
                                {
                                    requestProperty.DecimalValue = authorizedAmount;
                                    break;
                                }
                            }
                        }

                        // Capture payment
                        property = new PaymentProperty(
                            GenericNamespace.AuthorizationResponse,
                            AuthorizationResponseProperties.Properties,
                            innerAuthorizeResponseProperty.PropertyList);
                        requestProperties.Add(property);

                        paymentRequest.Properties = requestProperties.ToArray();
                        captureResponse           = processor.Capture(paymentRequest);

                        // Check capture result
                        var             captureResponseProperties    = PaymentProperty.ConvertToHashtable(captureResponse.Properties);
                        PaymentProperty innerCaptureResponseProperty = PaymentProperty.GetPropertyFromHashtable(
                            captureResponseProperties,
                            GenericNamespace.CaptureResponse,
                            CaptureResponseProperties.Properties);

                        var innerCaptureResponseProperties = PaymentProperty.ConvertToHashtable(innerCaptureResponseProperty.PropertyList);

                        string captureResult = null;
                        PaymentProperty.GetPropertyValue(
                            innerCaptureResponseProperties,
                            GenericNamespace.CaptureResponse,
                            CaptureResponseProperties.CaptureResult,
                            out captureResult);

                        if (!CaptureResult.Success.ToString().Equals(captureResult, StringComparison.OrdinalIgnoreCase))
                        {
                            // Capture failure, we have to void authorization and return the payment result.
                            voidResponse = processor.Void(paymentRequest);
                        }
                    }
                    else
                    {
                        // Authorization failure, Throw an exception and stop the payment.
                        var errors = new List <PaymentError>();
                        errors.Add(new PaymentError(ErrorCode.AuthorizationFailure, "Authorization failure."));
                        throw new CardPaymentException("Authorization failure.", errors);
                    }
                }
            }

            // Combine responses into one.
            Response paymentResponse = this.CombineResponses(tokenizeResponse, authorizeResponse, captureResponse, voidResponse);

            // Save payment result
            CardPaymentResult result = null;

            if (paymentResponse != null)
            {
                // Success
                paymentResponse.Properties = PaymentProperty.RemoveDataEncryption(paymentResponse.Properties);

                result                  = new CardPaymentResult();
                result.EntryId          = paymentEntry.EntryId;
                result.ResultAccessCode = CommonUtility.NewGuid().ToString();
                result.ResultData       = JsonConvert.SerializeObject(paymentResponse);
                result.Retrieved        = false;
                result.ServiceAccountId = paymentEntry.ServiceAccountId;
            }
            else
            {
                this.InputErrorsHiddenField.Value = WebResources.CardPage_Error_InvalidCard;
            }

            return(result);
        }