//
// BookingCheckoutViewController.m
// GoToBus
//
// Created by paul on 11/28/14.
//
//

#import "BookingCheckoutViewController.h"
#import "Lang.h"
#import "SDK.h"
#import "BeanUtils.h"
#import "CocoaUtils.h"
#import "DrawUtils.h"
#import "ImageUtils.h"
#import "Validator.h"
#import "TextViewController.h"
#import "UIConstants.h"
#import "UIToolkit.h"
#ifdef POD_OF_AlipaySDK
 #import <AlipaySDK/AlipaySDK.h>
#endif
#import <AXNavigationBackItemInjection/AXPopNavigationController.h>
#import <BlocksKit/BlocksKit+UIKit.h>
#import <libextobjc/EXTScope.h>
#import <MZFormSheetPresentationController/MZFormSheetPresentationViewController.h>
#import <PayPal-iOS-SDK/PayPalMobile.h>
#import <PureLayout/PureLayout.h>
#import <YYText/YYText.h>
#ifdef POD_OF_UPPaymentControl
 #import <UPPaymentControl.h>
#endif
#ifdef POD_OF_WechatOpenSDK
 #import <WechatOpenSDK/WXApi.h>
 #import <WechatOpenSDK/WXApiObject.h>
#endif
#import "Utility.h"
#import "JavaAppAjaxDo.h"
#import "BookGoodsResponseJsonMapper.h"
#import "CheckAvailabilityAndPricesResponseJsonMapper.h"
#import "BusCheckOutClientPolicyCell.h"
#import "BusSearchDetailPriceCell.h"
#import "AddressListViewController.h"
#import "AddressDetailViewController.h"
#import "BookingFinishViewController.h"
#import "BookingPriceDetailViewController.h"
#import "CreditCardListViewController.h"
#import "CreditCardDetailViewController.h"
#import "SecurityAttentionViewController.h"
#import "AppTracker.h"
#import "Vars.h"

static NSString * const kTotalPriceDetailTableViewCellIdentier = @"TotalPriceDetailTableViewCellIdentier";

@interface BookingCheckoutViewController ()
#ifdef POD_OF_WechatOpenSDK
<UITextFieldDelegate, PayPalPaymentDelegate, WXApiDelegate>
#else
< UITextFieldDelegate, PayPalPaymentDelegate >
#endif

@property (nonatomic, strong) Address *selectedContactInfo;
@property (nonatomic, strong) CreditCard *selectedCreditCard;
@property (nonatomic, strong) NSString *currentCouponCode;
@property (nonatomic, strong) NSMutableDictionary *clientPolicyContent;
@property (nonatomic, strong) NSMutableArray  *anonymousCreditCards;
@property (nonatomic, strong) NSMutableArray  *anonymousAddresses;
@property (nonatomic, assign) BOOL terms;
@property (nonatomic, strong) NSString *paymentId;
@property (nonatomic, strong) NSString *outTradeNo;
@property (nonatomic, assign) BOOL paySending;
@property (nonatomic, assign) BOOL orderBooking;

@property (nonatomic, strong) NSMutableArray *cellDataArrays;
@property (nonatomic, strong) NSArray *sectionHeaderTitles;

@property (nonatomic, assign, readonly) BOOL allowsPriceDetail;
@property (nonatomic, assign, readonly) BOOL allowsCoupon;
@property (nonatomic, assign, readonly) BOOL allowsPaypal;
@property (nonatomic, assign, readonly) BOOL allowsMyAccount;
@property (nonatomic, assign, readonly) BOOL isPaypalSandbox;
@property (nonatomic, assign, readonly) BOOL isUnionpaySandbox;
@property (nonatomic, assign, readwrite) BOOL creditCardSelected;
@property (nonatomic, assign, readwrite) BOOL paypalSelected;
@property (nonatomic, assign, readwrite) BOOL myAccountSelected;
@property (nonatomic, assign, readwrite) BOOL wechatpaySelected;
@property (nonatomic, assign, readwrite) BOOL alipaySelected;
@property (nonatomic, assign, readwrite) BOOL unionpaySelected;

@end

@implementation BookingCheckoutViewController

- (instancetype)init {
	self = [super init];
	if (self) {
		self.title = IMLocalizedString(@"Checkout");
		self.hidesBottomBarWhenPushed = YES;
		[[Vars appDelegate] applyDefaultConfigurationForViewController:self];
	}
	return self;
}

- (void)viewDidLoad {
	[super viewDidLoad];
	
	[[AppTracker sharedInstance] sendView:[self class]];
	
	self.clientPolicyContent = [NSMutableDictionary dictionary];

	[[Vars appDelegate].shopCarts clearPreSale];
	self.selectedContactInfo = [Address primaryOfAddresses:[Vars appDelegate].loginUser.contactInfos];
	self.selectedCreditCard = [CreditCard primaryOfCreditCards:[Vars appDelegate].loginUser.creditCards];

	NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
	[notificationCenter addObserver:self selector:@selector(didSelectAddress:) name:AddressDidSelectNotification object:nil];
	[notificationCenter addObserver:self selector:@selector(didSelectCreditCard:) name:CreditCardDidSelectNotification object:nil];
	if ([Vars is_cn_website]) {
		[notificationCenter addObserver:self selector:@selector(perfromNotificationForAlipayOrderPaymentResult:) name:AlipayOrderPaymentResultNotification object:nil];
		[notificationCenter addObserver:self selector:@selector(perfromNotificationForWXPayResp:) name:WXPayRespNotification object:nil];
		[notificationCenter addObserver:self selector:@selector(perfromNotificationForUPPaymentResult:) name:UPPaymentResultNotification object:nil];
		[notificationCenter addObserver:self selector:@selector(perfromNotificationForApplicationDidEnterBackground)
		name:UIApplicationDidEnterBackgroundNotification object:nil];
		[notificationCenter addObserver:self selector:@selector(perfromNotificationForApplicationDidBecomeActive)
		name:UIApplicationDidBecomeActiveNotification object:nil];
	}

	@weakify(self)
	[self.navigationController setPopHandler:^BOOL (UINavigationBar *_Nonnull navigationBar, UINavigationItem *_Nonnull navigationItem) {
		@strongify(self)
		if (self.orderBooking || ![StringUtils isEmpty:self.outTradeNo]) {
			[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:@"The booking is not placed successfully. Would you like to cancel this reservation?" cancelActionTitle:IMLocalizedString(@"NO") otherActionTitle:IMLocalizedString(@"YES") otherActionHandler:^{
				[self.navigationController popViewControllerAnimated:YES];
			}];
			return NO;
		}
		return YES;
	}];

	self.tableView.sectionHeaderHeight = [UIConstants defaultTableViewCellLayoutInsets].top;
	self.tableView.sectionFooterHeight = [UIConstants defaultTableViewCellLayoutInsets].bottom;
	[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([BusSearchDetailPriceCell class]) bundle:nil] forCellReuseIdentifier:NSStringFromClass([BusSearchDetailPriceCell class])];
	[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([BusSearchDetailPriceCell class]) bundle:nil] forCellReuseIdentifier:kTotalPriceDetailTableViewCellIdentier];
    [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([BusCheckOutClientPolicyCell class]) bundle:[NSBundle mainBundle]] forCellReuseIdentifier:NSStringFromClass([BusCheckOutClientPolicyCell class])];
	if (YES) {
		UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), [UIConstants defaultTableViewRowHeight] + 15 * 2)];
		UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
		button.tag = NSStringFromClass([UIButton class]).hash;
		button.frame = CGRectMake(15, 15, CGRectGetWidth([UIScreen mainScreen].bounds) - 15 * 2, [UIConstants defaultTableViewRowHeight]);
		button.titleLabel.font = [UIFont boldSystemFontOfSize:[UIFont buttonFontSize]];
		[button addTarget:self action:@selector(completeBooking) forControlEvents:UIControlEventTouchUpInside];
		[Utility addRoundedBorderToButton:button];
		[footerView addSubview:button];
		self.tableView.tableFooterView = footerView;
	}
	[self buildSectionHeader];
	[self buildCellDataSource];
	[self reloadFooterView];
}

- (void)viewWillAppear:(BOOL)animated {
	[super viewWillAppear:animated];

	if (self.allowsPaypal) {
		[PayPalMobile preconnectWithEnvironment:self.isPaypalSandbox ? PayPalEnvironmentSandbox : PayPalEnvironmentProduction];
	}
}

- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];
	// ajax
	if (self.unionpaySelected && ![StringUtils isEmpty:self.outTradeNo]) {
#ifdef POD_OF_UPPaymentControl
		if (![UPPaymentControl defaultControl].isPaymentAppInstalled) {
			[self performRequestForGetThirdPartyPaymentState];
		}
#endif
	}
}

#pragma mark - Property

- (NSMutableArray *)anonymousCreditCards{
	if (!_anonymousCreditCards) {
		_anonymousCreditCards = [NSMutableArray array];
	}
	return _anonymousCreditCards;
}

- (NSMutableArray *)anonymousAddresses{
	if (!_anonymousAddresses) {
		_anonymousAddresses = [NSMutableArray array];
	}
	return _anonymousAddresses;
}

- (BOOL)allowsPriceDetail {
	BOOL hasTour = [[Vars appDelegate].shopCarts.entries bk_any:^BOOL (CartEntry *obj) {
		return obj.product.is_tour_related;
	}];
	if (hasTour) {
		return NO;
	}
	return YES;
}

- (BOOL)allowsCoupon {
	return !self.checkAvailabilityAndPricesResponse.disable_coupon;
}

- (BOOL)allowsPaypal {
	return !self.checkAvailabilityAndPricesResponse.disable_paypal;
}

-(BOOL)allowsMyAccount {
    return NO;
}

- (BOOL)isPaypalSandbox {
#if DEBUG
	return [Vars isPaypalSandbox];
#else
	return NO;
#endif
}

- (BOOL)isUnionpaySandbox {
#if DEBUG
 #ifdef POD_OF_UPPaymentControl
	if ([UPPaymentControl defaultControl].isPaymentAppInstalled) {
		return NO;
	}
 #endif
	return [Vars isUnionpaySandbox];
#else
	return NO;
#endif
}

- (BOOL)creditCardSelected {
	return [Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type == 2;
}

- (void)setCreditCardSelected:(BOOL)creditCardSelected {
	[Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type = creditCardSelected ? 2 : 0;
}

- (BOOL)paypalSelected {
	return [Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type == 14;
}

- (BOOL)myAccountSelected {
    return [Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type == 1;
}

- (void)setPaypalSelected:(BOOL)paypalSelected {
	[Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type = paypalSelected ? 14 : 0;
}

- (BOOL)wechatpaySelected {
	return [Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type == 19;
}

- (void)setWechatpaySelected:(BOOL)wechatpaySelected {
	[Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type = wechatpaySelected ? 19 : 0;
}

- (BOOL)alipaySelected {
	return [Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type == 12;
}

- (void)setAlipaySelected:(BOOL)alipaySelected {
	[Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type = alipaySelected ? 12 : 0;
}

- (BOOL)unionpaySelected {
	return [Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type == 20;
}

- (void)setUnionpaySelected:(BOOL)unionpaySelected {
	[Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type = unionpaySelected ? 20 : 0;
}

- (void)setMyAccountSelected:(BOOL)myAccountSelected {
    [Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type = myAccountSelected ? 1 : 0;
}

#pragma mark - Action

- (void)completeBooking {
	if ([self validateBooking]) {
		[self preInstallBooking];
	}
}

- (void)perfromActionForPaymentMethodWithSegmentedControl:(UISegmentedControl *)segmentedControl {
	switch (segmentedControl.selectedSegmentIndex) {
		case 0:
			[Vars appDelegate].shopCarts.rmb_selected = YES;
			self.alipaySelected = YES;
			[self updateTableViewCellDataArrayForPaymentMethod];
			[self.tableView reloadData];
			[self reloadFooterView];
			// [self.tableView beginUpdates];
			// [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:2]] withRowAnimation:UITableViewRowAnimationNone];
			// [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
			// [self.tableView endUpdates];
			break;

		case 1:
			[Vars appDelegate].shopCarts.rmb_selected = NO;
			self.creditCardSelected = YES;
			[self updateTableViewCellDataArrayForPaymentMethod];
			[self.tableView reloadData];
			[self reloadFooterView];
			// [self.tableView beginUpdates];
			// [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:2]] withRowAnimation:UITableViewRowAnimationNone];
			// [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
			// [self.tableView endUpdates];
			break;

		default:
			break;
	}
}

- (void)clickAgreeTerm:(UIButton *)sender{
    sender.selected = !sender.selected;
    self.terms = sender.selected;
    
}

#pragma mark - Notification

- (void)didSelectAddress:(NSNotification *)notification {
	Address *address = notification.object;
	if ([Vars appDelegate].loginUser) {
		if ([[Vars appDelegate].loginUser.contactInfos containsObject:address]) {
			self.selectedContactInfo = address;
		} else {
			self.selectedContactInfo = [Address primaryOfAddresses:[Vars appDelegate].loginUser.contactInfos];
		}
	} else {
		self.selectedContactInfo = address;
	}
	[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}

- (void)didSelectCreditCard:(NSNotification *)notification {
	CreditCard *creditCard = notification.object;
	if ([Vars appDelegate].loginUser) {
		if ([[Vars appDelegate].loginUser.creditCards containsObject:creditCard]) {
			self.selectedCreditCard = creditCard;
		} else {
			self.selectedCreditCard = [CreditCard primaryOfCreditCards:[Vars appDelegate].loginUser.creditCards];
		}
	} else {
		self.selectedCreditCard = creditCard;
	}
	if (self.creditCardSelected) {
		[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:1 inSection:3]] withRowAnimation:UITableViewRowAnimationNone];
	}
}

- (void)perfromNotificationForAlipayOrderPaymentResult:(NSNotification *)notication {
	[self receivePaymentWithAlipayOrderPaymentResult:notication.object];
}

- (void)perfromNotificationForWXPayResp:(NSNotification *)notification {
	[self receivePaymentWithWXPayResp:notification.object];
}

- (void)perfromNotificationForUPPaymentResult:(NSNotification *)notication {
	[self receivePaymentWithUPPaymentResult:notication.object];
}

- (void)perfromNotificationForApplicationDidEnterBackground {
}

- (void)perfromNotificationForApplicationDidBecomeActive {
	// ajax
	if (![StringUtils isEmpty:self.outTradeNo] && self.paySending) {
		dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
			self.paySending = NO;
			[self performRequestForGetThirdPartyPaymentState];
		});
	}
}

#pragma mark - Segue

-(void)performSegueForContactInfoList:(Address *)selectedContactInfo{
    AddressListViewController *viewController = [[AddressListViewController alloc] init];
    viewController.title = IMLocalizedString(@"Your Contact Information");
    viewController.addressType = AddressTypeContactInfo;
	if (![Vars appDelegate].loginUser) {
		viewController.addresses = self.anonymousAddresses;
	}else{
    	viewController.addresses = [Vars appDelegate].loginUser.contactInfos;
	}
    viewController.allowsTransient = ![Vars appDelegate].loginUser;
    viewController.allowsDefault = [Vars appDelegate].loginUser;
    viewController.allowsSelection = YES;
    viewController.isSelection = YES;
    [viewController selectAddress:selectedContactInfo];
    [viewController setDidSelectBlock:^(Address *address) {
        [self.navigationController popViewControllerAnimated:YES];
    }];
    [self.navigationController pushViewController:viewController animated:YES];
}

-(void)performSegueForContactInfoDetail:(Address *)selectedContactInfo{
    AddressDetailViewController *viewController = [[AddressDetailViewController alloc] initWithAddress:selectedContactInfo];
    viewController.addressType = AddressTypeContactInfo;
    viewController.allowsTransient = ![Vars appDelegate].loginUser;
    viewController.allowsDefault = [Vars appDelegate].loginUser;
    [viewController setDidInsertBlock:^(Address *address) {
        [self.navigationController popViewControllerAnimated:YES];
		if (![Vars appDelegate].loginUser) {
			[self.anonymousAddresses addObject:address];
		}else{
        	[[Vars appDelegate].loginUser.contactInfos addObject:address];
		}
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter postNotificationName:AddressDidSelectNotification object:address];
    }];
    [viewController setDidUpdateBlock:^(Address *address) {
        [self.navigationController popViewControllerAnimated:YES];
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter postNotificationName:AddressDidSelectNotification object:address];
    }];
    [viewController setDidDeleteBlock:^(Address *address) {
        [self.navigationController popViewControllerAnimated:YES];
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter postNotificationName:AddressDidSelectNotification object:nil];
    }];
    [self.navigationController pushViewController:viewController animated:YES];
}


- (void)performSegueForCreditCardList:(CreditCard *)selectedCreditCard {
    CreditCardListViewController *viewController = [[CreditCardListViewController alloc] init];
    viewController.title = IMLocalizedString(@"Your Credit Cards");
	if (![Vars appDelegate].loginUser) {
		viewController.creditCards = self.anonymousCreditCards;
	}else{
    	viewController.creditCards = [Vars appDelegate].loginUser.creditCards;
	}
    viewController.allowsTransient = ![Vars appDelegate].loginUser;
    viewController.allowsDefault = [Vars appDelegate].loginUser;
    viewController.allowsSelection = YES;
    viewController.isSelection = YES;
    [viewController selectCreditCard:selectedCreditCard];
    [viewController setDidSelectBlock:^(CreditCard *creditCard) {
        [self.navigationController popViewControllerAnimated:YES];
    }];
    [self.navigationController pushViewController:viewController animated:YES];
}

- (void)performSegueForCreditCardDetail:(CreditCard *)selectedCreditCard {
    CreditCardDetailViewController *viewController = [[CreditCardDetailViewController alloc] initWithCreditCard:selectedCreditCard];
    viewController.allowsTransient = ![Vars appDelegate].loginUser;
    viewController.allowsDefault = [Vars appDelegate].loginUser;
    [viewController setDidInsertBlock:^(CreditCard *creditCard) {
        [self.navigationController popViewControllerAnimated:YES];
		if (![Vars appDelegate].loginUser) {
			[self.anonymousCreditCards addObject:creditCard];
		}else {
        	[[Vars appDelegate].loginUser.creditCards addObject:creditCard];
		}
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter postNotificationName:CreditCardDidSelectNotification object:creditCard];
    }];
    [viewController setDidUpdateBlock:^(CreditCard *creditCard) {
        [self.navigationController popViewControllerAnimated:YES];
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter postNotificationName:CreditCardDidSelectNotification object:creditCard];
    }];
    [viewController setDidDeleteBlock:^(CreditCard *creditCard) {
        [self.navigationController popViewControllerAnimated:YES];
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter postNotificationName:CreditCardDidSelectNotification object:nil];
    }];
    [self.navigationController pushViewController:viewController animated:YES];
}

- (void)performSegueForPolicy:(NSString *)content {
    IMWebViewController *viewController = [[IMWebViewController alloc] initWithHTMLString:content];
    viewController.title = IMLocalizedString(@"Terms & Conditions");
    [[Vars appDelegate] applyDefaultConfigurationForViewController:viewController];
    viewController.autoshrink = YES;
    [self.navigationController pushViewController:viewController animated:YES];
}

- (void)performSegueForPolicy {
	TextViewController *viewController = [[TextViewController alloc] init];
	viewController.title = IMLocalizedString(@"Terms & Conditions");
	[[Vars appDelegate] applyDefaultConfigurationForViewController:viewController];
	viewController.textView.text = [NSString stringWithContentsOfFile:IMLocalizedPath(@"terms", @"txt") encoding:NSUTF8StringEncoding error:NULL];
	[self.navigationController pushViewController:viewController animated:YES];
}

- (void)performSegueForPriceDetail {
	BookingPriceDetailViewController *viewController = [[BookingPriceDetailViewController alloc] init];
	viewController.response = self.checkAvailabilityAndPricesResponse;
	[self.navigationController pushViewController:viewController animated:YES];
}

- (void)performSegueForPaymentMethodDescription:(id)obj {
	UIView *contentView = [[UIView alloc] init];
	contentView.backgroundColor = [UIColor whiteColor];
	UILabel *label = [[UILabel alloc] init];
	label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
	label.numberOfLines = 0;
	if ([obj isKindOfClass:[NSString class]]) {
		label.text = obj;
	} else if ([obj isKindOfClass:[NSAttributedString class]]) {
		label.attributedText = obj;
	}
	[contentView addSubview:label];
	[label autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(15, 15, 15, 15)];
	[NSLayoutConstraint autoSetPriority:UILayoutPriorityRequired - 1 forConstraints:^{
		[contentView autoSetDimension:ALDimensionWidth toSize:CGRectGetWidth([UIScreen mainScreen].bounds) - 15 * 2];
	}];
	MZFormSheetPresentationViewController *viewController = [[MZFormSheetPresentationViewController alloc] initWithContentView:contentView];
	viewController.presentationController.shouldCenterVertically = YES;
	viewController.presentationController.shouldDismissOnBackgroundViewTap = YES;
	[self presentViewController:viewController animated:YES completion:nil];
}

#pragma mark - Network

- (void)performRequestForGetClientPolicy:(NSInteger)vid {
	GetClientPolicy *getClientPolicy = [[GetClientPolicy alloc] init];
	getClientPolicy.vid = vid;
	
	NSDictionary *requestDict = [Utility perlParamXml:[getClientPolicy innerXML] action:getClientPolicy.name];
	
	[Utility getXMLFromRequestWithMethod:@"GET" url:getClientPolicy.address parameters:requestDict success:^(NSString *xml) {
		NSString *responseStr = xml;
		// NSLog(@"%@", responseStr);
		WebServiceResponseJsonMapper *mapper = [[WebServiceResponseJsonMapper alloc] initWithClass:[GetClientPolicyResponse class]];
		NSDictionary *jsonDict = [Utility JSONObjectWithXMLString:responseStr objectMapping:mapper.objectMapping];
		// NSLog(@"%@", jsonDict);
		if (![mapper parseWithJSONObject:jsonDict]) {
			GetClientPolicyResponse *response = mapper.response;
			if (response.error_code > 0) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:response.error_message];
			} else {
				[self.clientPolicyContent setValue:response.policy forKey:@(vid)];
				[self performSegueForPolicy:[self.clientPolicyContent objectForKey:@(vid)]];
			}
		}
	}];
}

- (void)performRequestForExecuteReservation {
	ExecuteReservation *executeReservation = [[ExecuteReservation alloc] init];
	executeReservation.outTradeNo = self.outTradeNo;

	NSDictionary *requestDict = [Utility perlParamXml:[executeReservation innerXML] action:executeReservation.name];

	[Utility getXMLFromRequestWithMethod:@"POST" url:executeReservation.address parameters:requestDict beforeSend:^{
		self.orderBooking = YES;
		[CocoaUtils showBusyIndicator:self.view];
	} success:^(NSString *xml) {
		NSString *responseStr = xml;
		// NSLog(@"%@", responseStr);
		BookGoodsResponseJsonMapper *mapper = [[BookGoodsResponseJsonMapper alloc] init];
		NSDictionary *jsonDict = [Utility JSONObjectWithXMLString:responseStr objectMapping:mapper.objectMapping];
		if (![mapper parseWithJSONObject:jsonDict]) {
			BookGoodsResponse *response = mapper.response;
			if (response.error_code > 0) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:response.error_message];
			} else if (![StringUtils isEmpty:response.order_code]) {
				self.paymentId = nil;
				self.outTradeNo = nil;
				BookingFinishViewController *viewController = [[BookingFinishViewController alloc] init];
				viewController.bookGoodsResponse = response;
				[self.navigationController pushViewController:viewController animated:YES];
			} else if(response.priceChanged){
				[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Error") message:@"The payment is accepted but the booking is not placed successfully due to shopping cart change during checkout. It may due to product info or shopping cart updates." otherActionTitle:IMLocalizedString(@"Contact Us") otherActionHandler:^{
					[CocoaUtils callPhoneNumber:[Vars phone]];
				}];
			}else {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:[Vars responseException]];
			}
		}
	} complete:^{
		self.orderBooking = NO;
		[CocoaUtils hideBusyIndicator:self.view];
	}];
}

- (void)bookGoods {
	BookGoods *bookGoods = [Vars appDelegate].shopCarts.bookGoods;
	bookGoods.travelerDetails = [WebService travelerDetailsWithCartEntries:[Vars appDelegate].shopCarts.entries];
	bookGoods.ignoreDuplicated = YES;

	NSDictionary *requestDict = [Utility perlParamXml:[bookGoods innerXML] action:bookGoods.name];
	// NSLog(@"%@", requestDict);
	[Utility getXMLFromRequestWithMethod:@"POST" url:bookGoods.address parameters:requestDict beforeSend:^{
		self.orderBooking = YES;
		[CocoaUtils showBusyIndicator:self.view];
	} success:^(NSString *xml) {
		NSString *responseStr = xml;
		// NSLog(@"%@", responseStr);
		BookGoodsResponseJsonMapper *mapper = [[BookGoodsResponseJsonMapper alloc] init];
		NSDictionary *jsonDict = [Utility JSONObjectWithXMLString:responseStr objectMapping:mapper.objectMapping];
		if (![mapper parseWithJSONObject:jsonDict]) {
			BookGoodsResponse *response = mapper.response;
			if (response.priceChanged) {
				if (self.creditCardSelected) {
					[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"ShopCart has been Updated, Please Review and Continue.") dismissalHandler:^{
						[self checkAvailabilityAndPrices:nil];
					}];
				} else {
					[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Error") message:@"The payment is accepted but the booking is not placed successfully due to shopping cart change during checkout. It may due to product info or shopping cart updates." otherActionTitle:IMLocalizedString(@"Contact Us") otherActionHandler:^{
						[CocoaUtils callPhoneNumber:[Vars phone]];
					}];
				}
			} else if (response.error_code > 0) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:response.error_message];
			} else if (response.paypal_payment) {
				if ([StringUtils isEmpty:response.paypal_payment.out_trade_no]) {
					[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"An error occurred, please try again.") otherActionTitle:IMLocalizedString(@"Retry Submit") otherActionHandler:^{
						[self submitBooking];
					}];
				} else {
					self.outTradeNo = response.paypal_payment.out_trade_no;
					[self createPaypalSinglePayment];
				}
			} else if (response.wechatpay_payment) {
				if ([StringUtils isEmpty:response.wechatpay_payment.out_trade_no] || !response.wechatpay_payment.unifiedorder_prepay) {
					[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"An error occurred, please try again.") otherActionTitle:IMLocalizedString(@"Retry Submit") otherActionHandler:^{
						[self submitBooking];
					}];
				} else {
					self.outTradeNo = response.wechatpay_payment.out_trade_no;
#ifdef POD_OF_WechatOpenSDK
					PayReq *payReq = [[PayReq alloc] init];
					payReq.partnerId = response.wechatpay_payment.unifiedorder_prepay.partnerid;
					payReq.prepayId = response.wechatpay_payment.unifiedorder_prepay.prepayid;
					payReq.package = response.wechatpay_payment.unifiedorder_prepay.package;
					payReq.nonceStr = response.wechatpay_payment.unifiedorder_prepay.noncestr;
					payReq.timeStamp = response.wechatpay_payment.unifiedorder_prepay.timestamp;
					payReq.sign = response.wechatpay_payment.unifiedorder_prepay.sign;
					[WXApi sendReq:payReq];
#endif
					self.paySending = YES;
				}
			} else if (response.alipay_payment) {
				if ([StringUtils isEmpty:response.alipay_payment.out_trade_no] || [StringUtils isEmpty:response.alipay_payment.orderString]) {
					[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"An error occurred, please try again.") otherActionTitle:IMLocalizedString(@"Retry Submit") otherActionHandler:^{
						[self submitBooking];
					}];
				} else {
					self.outTradeNo = response.alipay_payment.out_trade_no;
#ifdef POD_OF_AlipaySDK
					[[AlipaySDK defaultService] payOrder:response.alipay_payment.orderString fromScheme:[Vars alipayUrlScheme] callback:^(NSDictionary *resultDic) {
						[self receivePaymentWithAlipayOrderPaymentResult:resultDic];
					}];
#endif
				}
			} else if (response.unionpay_payment) {
				if ([StringUtils isEmpty:response.unionpay_payment.out_trade_no] || [StringUtils isEmpty:response.unionpay_payment.tn]) {
					[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"An error occurred, please try again.") otherActionTitle:IMLocalizedString(@"Retry Submit") otherActionHandler:^{
						[self submitBooking];
					}];
				} else {
					self.outTradeNo = response.unionpay_payment.out_trade_no;
#ifdef POD_OF_UPPaymentControl
					[[UPPaymentControl defaultControl] startPay:response.unionpay_payment.tn fromScheme:[Vars unionpayUrlScheme] mode:self.isUnionpaySandbox ? @"01" : @"00" viewController:self];
					if ([UPPaymentControl defaultControl].isPaymentAppInstalled) {
						self.paySending = YES;
					}
#endif
				}
			} else if (response.need_verify_credit_card) {
				SecurityAttentionViewController *viewController = [[SecurityAttentionViewController alloc] init];
				viewController.bookGoodsResponse = response;
				[self.navigationController pushViewController:viewController animated:YES];
			} else if (![StringUtils isEmpty:response.order_code]) {
				[[AppTracker sharedInstance] sendTrackOrderTransactionWithResponse:self.checkAvailabilityAndPricesResponse orderCode:response.order_code];
				BookingFinishViewController *viewController = [[BookingFinishViewController alloc] init];
				viewController.bookGoodsResponse = response;
				[self.navigationController pushViewController:viewController animated:YES];
			} else {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:[Vars responseException]];
			}
		}
	} complete:^{
		self.orderBooking = NO;
		[CocoaUtils hideBusyIndicator:self.view];
	}];
}

- (void)checkAvailabilityAndPrices:(void (^)(void))completion {
	CheckAvailabilityAndPrices *checkAvailabilityAndPrices = [[CheckAvailabilityAndPrices alloc] init];
	checkAvailabilityAndPrices.travelerDetails = [WebService travelerDetailsWithCartEntries:[Vars appDelegate].shopCarts.entries];
	checkAvailabilityAndPrices.contactInfo = [Vars appDelegate].shopCarts.bookGoods.contactInfo;
	checkAvailabilityAndPrices.couponCode = [Vars appDelegate].shopCarts.bookGoods.couponCode;

	NSDictionary *requestDict = [Utility perlParamXml:[checkAvailabilityAndPrices innerXML] action:checkAvailabilityAndPrices.name];
	// NSLog(@"%@", requestDict);
	[Utility getXMLFromRequestWithMethod:@"POST" url:checkAvailabilityAndPrices.address parameters:requestDict success:^(NSString *xml) {
		NSString *responseStr = xml;
		// NSLog(@"%@", responseStr);
		CheckAvailabilityAndPricesResponseJsonMapper *mapper = [[CheckAvailabilityAndPricesResponseJsonMapper alloc] init];
		NSDictionary *jsonDict = [Utility JSONObjectWithXMLString:responseStr objectMapping:mapper.objectMapping];
		if (![mapper parseWithJSONObject:jsonDict]) {
			CheckAvailabilityAndPricesResponse *response = mapper.response;
			if (response.error_code > 0) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:response.error_message];
			} else {
				self.checkAvailabilityAndPricesResponse = response;
				[[AppTracker sharedInstance] sendCartUpdateTransactionWithResponse:self.checkAvailabilityAndPricesResponse];
				if (self.allowsCoupon) {
					for (NSString *errorMessage in response.couponErrorMessages) {
						[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:errorMessage];
					}
					[self updateTableViewCellDataArrayForAppliedCouponCodes];
				}
				if (completion) {
					completion();
				}
				if (self.allowsCoupon) {
					[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
					[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationNone];
					[self updateTableViewCellDataArrayForPaymentMethod];
					[self buildSectionHeader];
					[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
				}
			}
		}
	}];
}

- (void)checkDuplicatedBooking {
	CheckDuplicatedBooking *checkDuplicatedBooking = [[CheckDuplicatedBooking alloc] init];
	checkDuplicatedBooking.travelerDetails = [WebService travelerDetailsWithCartEntries:[Vars appDelegate].shopCarts.entries];
	checkDuplicatedBooking.contactInfo = [Vars appDelegate].shopCarts.bookGoods.contactInfo;

	NSDictionary *requestDict = [Utility perlParamXml:[checkDuplicatedBooking innerXML] action:checkDuplicatedBooking.name];
	// NSLog(@"%@", requestDict);
	[Utility getXMLFromRequestWithMethod:@"POST" url:checkDuplicatedBooking.address parameters:requestDict success:^(NSString *xml) {
		NSString *responseStr = xml;
		// NSLog(@"%@", responseStr);
		WebServiceResponseJsonMapper *mapper = [[WebServiceResponseJsonMapper alloc] initWithClass:[CheckDuplicatedBookingResponse class]];
		NSDictionary *jsonDict = [Utility JSONObjectWithXMLString:responseStr objectMapping:mapper.objectMapping];
		if (![mapper parseWithJSONObject:jsonDict]) {
			CheckDuplicatedBookingResponse *response = mapper.response;
			if (response.error_code > 0) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:response.error_message];
			} else if (response.isDuplicated) {
				[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"Duplicated bookings! You have submitted on identical order earlier and the eTicket has been sent to your email. If this is not a duplicated booking, please click \"Continue Shopping\" and checkout.") otherActionTitle:IMLocalizedString(@"Continue Shopping") otherActionHandler:^{
					[self postInstallBooking];
				}];
			} else {
				[self postInstallBooking];
			}
		}
	}];
}

- (void)performRequestForGetThirdPartyPaymentState {
	GetPaymentState *getPaymentState = [[GetPaymentState alloc] init];
	getPaymentState.outTradeNo = self.outTradeNo;
	if (self.paypalSelected) {
		getPaymentState.paymentId = self.paymentId;
	}

	NSDictionary *requestDict = [BeanUtils describeAccessibleSimple:getPaymentState];

	[Utility performRESTRequestWithMethod:@"GET" url:getPaymentState.address parameters:requestDict success:^(id jsonObject) {
		WebServiceResponseJsonMapper *mapper = [[WebServiceResponseJsonMapper alloc] initWithClass:[GetPaymentStateResponse class]];
		if (![mapper parseWithJSONObject:jsonObject]) {
			GetPaymentStateResponse *response = mapper.response;
			if (response.paymentState == 1 || response.paypalPending) {
				[self performRequestForExecuteReservation];
			} else {
				NSString *paymentName = nil;
				if (self.paypalSelected) {
					paymentName = IMLocalizedString(@"PayPal");
				} else if (self.alipaySelected) {
					paymentName = IMLocalizedString(@"Alipay");
				} else if (self.wechatpaySelected) {
					paymentName = IMLocalizedString(@"WeChat Pay");
				} else if (self.unionpaySelected) {
					paymentName = IMLocalizedString(@"UnionPay");
                }
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[NSString stringWithFormat:IMLocalizedString(@"Please confirm %@ transcation"), paymentName]];
			}
		}
	}];
}

#pragma mark - Private

- (void)buildSectionHeader {
	NSMutableArray *array = [NSMutableArray array];
	if (YES) {
		[array addObject:IMLocalizedString(@"Traveler Contact Information")];
	}
	if (self.allowsCoupon) {
		[array addObject:IMLocalizedString(@"Coupon")];
	} else {
		[array addObject:[NSNull null]];
	}
	if (YES) {
		[array addObject:IMLocalizedString(@"Complete your order")];
	}
	if (self.checkAvailabilityAndPricesResponse.not_need_pay) {
		[array addObject:[NSNull null]];
	}else{
		[array addObject:IMLocalizedString(@"Payment Method")];
	}
	if (YES) {
		[array addObject:IMLocalizedString(@"Terms & Conditions")];
	}
	self.sectionHeaderTitles = [NSArray arrayWithArray:array];
}

- (void)buildCellDataSource {
	NSMutableArray *arrays = [NSMutableArray array];
	@weakify(self)
	if (YES) {
		TableViewCellData *data = [[TableViewCellData alloc] init];
		data.style = UITableViewCellStyleSubtitle;
		[data setTextBlock:^NSString *{
			@strongify(self)
			return self.selectedContactInfo ? self.selectedContactInfo.fullName : [NSString stringWithFormat:IMLocalizedString(@"Add %@"), IMLocalizedString(@"Contact Information")];
		}];
		[data setDetailAttributedTextBlock:^NSAttributedString *{
			@strongify(self)
			return self.selectedContactInfo.attributedEmailIfDefaultAppending;
		}];
		data.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
		[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
			@strongify(self)
            if (self.selectedContactInfo) {
                [self performSegueForContactInfoList:self.selectedContactInfo];
            } else {
                [self performSegueForContactInfoDetail:self.selectedContactInfo];
            }
		}];
		data.validationMessageCaption = IMLocalizedString(@"Contact Information");
		[data setRequiredValidationRuleBlock:^BOOL {
			@strongify(self)
			return self.selectedContactInfo;
		}];
		[arrays addObject:@[data]];
	}
	if (self.allowsCoupon) {
		NSMutableArray *array = [NSMutableArray array];
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.editingType = TableViewCellEditingTypeTextField;
			data.placeholder = IMLocalizedString(@"Coupon Code");
			[data setAccessoryViewBlock:^UIView *(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data){
				UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
				button.backgroundColor = [Vars defaultTintColor];
				button.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
				[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
				[button setTitle:IMLocalizedString(@"Apply") forState:UIControlStateNormal];
				[button sizeToFit];
				button.frame = CGRectMake(0, 0, CGRectGetWidth(button.frame) + 5 * 2, [UIConstants defaultLabelHeight]);
				[button bk_addEventHandler:^(id sender) {
					@strongify(self)
					[self.tableView endEditing:YES];
					if (![StringUtils isBlank:self.currentCouponCode]) {
						NSMutableArray *couponCodes = [NSMutableArray arrayWithArray:self.checkAvailabilityAndPricesResponse.appliedCouponCodes];
						if ([couponCodes containsObject:self.currentCouponCode]) {
							[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"The coupon code is duplicated")];
						} else {
							[couponCodes addObject:self.currentCouponCode];
							[Vars appDelegate].shopCarts.bookGoods.couponCode = [couponCodes componentsJoinedByString:@";"];
							[self checkAvailabilityAndPrices:^(void) {
								self.currentCouponCode = nil;
							}];
						}
					}
				} forControlEvents:UIControlEventTouchUpInside];
				[Utility addRoundedBorderToButton:button];
				return button;
			}];
			data.observedObject = self;
			data.keyPath = @"currentCouponCode";
			[data addIntegrityValidationRuleBlock:^BOOL {
				@strongify(self)
				if (![StringUtils isBlank:self.currentCouponCode] && self.checkAvailabilityAndPricesResponse.appliedCouponCodes.count == 0) {
					return NO;
				}
				return YES;
			} withMessageBlock:^NSString *{
				return IMLocalizedString(@"Please enter coupon code and click \"Apply\" to purchase with your coupon code.");
			}];
			[array addObject:data];
		}
		[arrays addObject:array];
	} else {
		[arrays addObject:@[]];
	}
	if (YES) {
		NSMutableArray *array = [NSMutableArray array];
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.reuseIdentifier = kTotalPriceDetailTableViewCellIdentier;
			data.isCustomRegistered = YES;
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusSearchDetailPriceCell *cell) {
				@strongify(self)
				cell.imageView.image = nil;
				if (self.checkAvailabilityAndPricesResponse) {
					NSMutableString *string = [NSMutableString string];
					[string im_appendString:IMLocalizedString(@"Total")];
					[string im_appendString:IMLocalizedString(PUNCTUATION_COLON)];
					[string im_appendString:IMLocalizedString(WORD_DIVIDER_SPACE)];
					[string im_appendString:[self.checkAvailabilityAndPricesResponse totalFareTextWithCurrencyCode:[Vars appDelegate].shopCarts.currency_code]];
					cell.titleLabel.text = string;
					cell.titleLabel.textColor = [Vars defaultTintColor];
				} else {
					cell.titleLabel.text = nil;
					cell.titleLabel.textColor = [UIColor blackColor];
				}
				if (self.checkAvailabilityAndPricesResponse.app_first_purchase_discount > 0)  {
					cell.subtitleLabel.text = [NSString stringWithFormat:@"%@ Off Applied", [self.checkAvailabilityAndPricesResponse currencyTextFromNumber:self.checkAvailabilityAndPricesResponse.app_first_purchase_discount currencyCode:[Vars appDelegate].shopCarts.currency_code]];
					cell.subtitleLabel.textColor = [UIColor blackColor];
				} else if (self.checkAvailabilityAndPricesResponse.app_first_purchase_discount_rate > 0) {
					cell.subtitleLabel.text = [NSString stringWithFormat:@"%@ Off Applied", [CocoaUtils percentStringWithNumber:@(self.checkAvailabilityAndPricesResponse.app_first_purchase_discount_rate)]];
					cell.subtitleLabel.textColor = [UIColor blackColor];
				} else if ([Vars appDelegate].shopCarts.rmb_selected && self.checkAvailabilityAndPricesResponse.second_currency_discount) {
					NSMutableString *string = [NSMutableString string];
					[string im_appendString:IMLocalizedString(@"RMB Discount")];
					[string im_appendString:IMLocalizedString(WORD_DIVIDER_SPACE)];
					[string im_appendString:self.checkAvailabilityAndPricesResponse.secondCurrencyDiscountText];
					cell.subtitleLabel.text = string;
					cell.subtitleLabel.textColor = [UIColor blackColor];
				} else {
					cell.subtitleLabel.text = nil;
					cell.subtitleLabel.textColor = [UIColor lightGrayColor];
				}
				cell.detailDisclosureButton.hidden = !self.allowsPriceDetail;
				if (self.allowsPriceDetail) {
					[cell.detailDisclosureButton removeTarget:self action:@selector(performSegueForPriceDetail) forControlEvents:UIControlEventTouchUpInside];
					[cell.detailDisclosureButton addTarget:self action:@selector(performSegueForPriceDetail) forControlEvents:UIControlEventTouchUpInside];
				}
				if ([Vars is_cn_website]) {
					NSMutableArray *items = [NSMutableArray array];
					for (NSString *localeIdentifier in @[@"zh-Hans_CN", @"en_US"]) {
						NSLocale *locale = [NSLocale localeWithLocaleIdentifier:localeIdentifier];
						[items addObject:[NSString stringWithFormat:@"%@ %@", [locale objectForKey:NSLocaleCurrencySymbol], IMLocalizedString([locale objectForKey:NSLocaleCurrencyCode])]];
					}
					UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
					[segmentedControl addTarget:self action:@selector(perfromActionForPaymentMethodWithSegmentedControl:) forControlEvents:UIControlEventValueChanged];
					segmentedControl.selectedSegmentIndex = [Vars appDelegate].shopCarts.rmb_selected ? 0 : 1;
					cell.accessoryView = segmentedControl;
				} else {
					cell.accessoryView = nil;
				}
				[cell setNeedsLayout];
			}];
			[array addObject:data];
		}
		if ([Vars isAffiliate]) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.attributedText = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"* Transaction service is provided by %@", [Vars clientServiceProvider]]];
			data.textFont = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
			data.textColor = [UIColor darkGrayColor];
			data.allowsTextLineWrapping = YES;
			[array addObject:data];
		}
		[arrays addObject:[NSArray arrayWithArray:array]];
	}
	if (YES) {
		[arrays addObject:[NSMutableArray array]];
	}
	if (YES) {
		NSMutableArray *array = [NSMutableArray array];
        if(YES) {
            TableViewCellData *data = [[TableViewCellData alloc] init];
            data.reuseIdentifier = NSStringFromClass([BusCheckOutClientPolicyCell class]);
            data.isCustomRegistered = YES;
			[data setNeedLayoutFittingHeight];
            [data addIntegrityValidationRuleBlock:^BOOL {
                @strongify(self)
                return self.terms;
            } withMessageBlock:^NSString *{
                return IMLocalizedString(@"You must read and agree to the terms and conditions");
            }];
            [data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusCheckOutClientPolicyCell *cell) {
				UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
				NSMutableAttributedString *attachText = [[NSMutableAttributedString alloc] init];
				if (YES) {
					UIButton *btnAgree = [UIButton buttonWithType:UIButtonTypeCustom];
					[btnAgree setImage:[DrawUtils imageWithFAKIcon:[FAKFontAwesomeRegular squareIconWithSize:font.pointSize] fillColor:[Vars defaultTintColor]] forState:UIControlStateNormal];
					[btnAgree setImage:[DrawUtils imageWithFAKIcon:[FAKFontAwesomeRegular checkSquareIconWithSize:font.pointSize] fillColor:[Vars defaultTintColor]] forState:UIControlStateSelected];
					[btnAgree addTarget:self action:@selector(clickAgreeTerm:) forControlEvents:UIControlEventTouchUpInside];
					[btnAgree sizeToFit];
					[attachText appendAttributedString:[NSAttributedString yy_attachmentStringWithContent:btnAgree contentMode:UIViewContentModeCenter attachmentSize:btnAgree.frame.size alignToFont:font alignment:YYTextVerticalAlignmentCenter]];
				}
				[attachText appendAttributedString:[[NSAttributedString alloc] im_initWithString:@" " attributes:@{ NSForegroundColorAttributeName : [UIColor blackColor]}]];
				if (YES) {
					NSString *sentence = IMLocalizedString(@"I read and agree to the Standard Terms and Conditions");
					NSString *word = IMLocalizedString(@"Standard Terms and Conditions");
					NSMutableAttributedString *one = [[NSMutableAttributedString alloc] im_initWithString:sentence attributes:@{ NSForegroundColorAttributeName : [UIColor blackColor]}];
					[one yy_setTextHighlightRange:[sentence rangeOfString:word]
											color:[UIColor blueColor]
								  backgroundColor:[UIColor whiteColor]
										tapAction:^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect){
											[self performSegueForPolicy];
										}];
					[attachText appendAttributedString:one];
				}
				if (YES) {
					NSMutableDictionary *clientPolicy = [NSMutableDictionary dictionary];
					for (CartEntry *entry in [Vars appDelegate].shopCarts.entries) {
						if (entry.product.is_bus) {
							[clientPolicy setValue:entry.product.vendor_obj.short_name forKey:@(entry.product.vendor_obj.id)];
						}
					}
					for (NSNumber *key in clientPolicy) {
						[attachText appendAttributedString:[[NSAttributedString alloc] im_initWithString:@", " attributes:@{ NSForegroundColorAttributeName : [UIColor blackColor]}]];
						NSMutableAttributedString *two = [[NSMutableAttributedString alloc] im_initWithString:[NSString stringWithFormat:@"%@ Terms & Conditions", clientPolicy[key]]];
						[two yy_setTextHighlightRange:two.yy_rangeOfAll
												color:[UIColor blueColor]
									  backgroundColor:[UIColor whiteColor]
											tapAction:^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect){
												if ([StringUtils isEmpty:[self.clientPolicyContent objectForKey:key]] ){
													[self performRequestForGetClientPolicy:key.integerValue];
												} else {
													[self performSegueForPolicy:[self.clientPolicyContent objectForKey:key]];
												}
												
											}];
						[attachText appendAttributedString:two];
					}
				}
                cell.label.attributedText = attachText;
				cell.label.font = font;
            }];
			[array addObject:data];
        }
		[arrays addObject:[NSArray arrayWithArray:array]];
	}
	self.cellDataArrays = [NSArray arrayWithArray:arrays];

	[self updateTableViewCellDataArrayForAppliedCouponCodes];
	[self updateTableViewCellDataArrayForPaymentMethod];
}

- (void)updateTableViewCellDataArrayForAppliedCouponCodes {
	NSMutableArray *array = self.cellDataArrays[1];
	[CocoaUtils removeObjectsInArray:array fromIndex:1];
	@weakify(self)
	for (NSString *couponCode in self.checkAvailabilityAndPricesResponse.appliedCouponCodes) {
		TableViewCellData *data = [[TableViewCellData alloc] init];
		data.text = couponCode;
		[data setAccessoryViewBlock:^UIView *(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data){
			UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
			[button setImage:[DrawUtils imageWithFAKIcon:[FAKIonIcons iosCloseOutlineIconWithSize:24] fillColor:[UIColor lightGrayColor]] forState:UIControlStateNormal];
			[button sizeToFit];
			[button bk_addEventHandler:^(id sender) {
				@strongify(self)
				NSMutableArray *couponCodes = [NSMutableArray arrayWithArray:self.checkAvailabilityAndPricesResponse.appliedCouponCodes];
				[couponCodes removeObject:couponCode];
				[Vars appDelegate].shopCarts.bookGoods.couponCode = [couponCodes componentsJoinedByString:@";"];
				[self checkAvailabilityAndPrices:nil];
			} forControlEvents:UIControlEventTouchUpInside];
			return button;
		}];
		[array addObject:data];
	}
	if (self.checkAvailabilityAndPricesResponse.appliedCouponCodes.count > 0) {
		TableViewCellData *data = [[TableViewCellData alloc] init];
		data.allowsTextLineWrapping = YES;
		data.text = IMLocalizedString(@"Your coupon code(s) are applied successfully, and the total shopping cart charge has been adjusted accordingly!");
		data.textColor = [UIColor cloverColor];
		data.textFont = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
		[array addObject:data];
	}
}

- (void)updateTableViewCellDataArrayForPaymentMethod {
	NSMutableArray *array = self.cellDataArrays[3];
	[array removeAllObjects];
	@weakify(self)
	if (self.checkAvailabilityAndPricesResponse.not_need_pay) {
		[Vars appDelegate].shopCarts.bookGoods.paymentInfo.payment_type = 11;
		[self reloadFooterView];
		return;
	}else{
		if ([Vars appDelegate].shopCarts.rmb_selected) {
			self.alipaySelected = YES;
		}else{
			self.creditCardSelected = YES;
		}
	}
	
	if ([Vars appDelegate].shopCarts.rmb_selected) {
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.reuseIdentifier = NSStringFromClass([BusSearchDetailPriceCell class]);
			data.isCustomRegistered = YES;
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusSearchDetailPriceCell *cell) {
				@strongify(self)
				cell.imageView.image = [ImageUtils scaleSVGImageNamed:@"icon_alipay" toSize:CGSizeMake(24, 24)];
				cell.titleLabel.text = IMLocalizedString(@"Alipay");
				cell.subtitleLabel.text = nil;
				cell.detailDisclosureButton.hidden = NO;
				[cell.detailDisclosureButton bk_removeEventHandlersForControlEvents:UIControlEventTouchUpInside];
				[cell.detailDisclosureButton bk_addEventHandler:^(id sender) {
				[self performSegueForPaymentMethodDescription:[Utility attributedStringWithHtmlString:IMLocalizedString(@"_ALIPAY_") fixAttributes:@{ NSFontAttributeName : [UIFont preferredFontForTextStyle:UIFontTextStyleBody] }]];
				} forControlEvents:UIControlEventTouchUpInside];
				cell.accessoryType = self.alipaySelected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
			}];
			[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				@strongify(self)
				self.alipaySelected = YES;
				[tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
				[self reloadFooterView];
			}];
			[array addObject:data];
		}
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.reuseIdentifier = NSStringFromClass([BusSearchDetailPriceCell class]);
			data.isCustomRegistered = YES;
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusSearchDetailPriceCell *cell) {
				@strongify(self)
				cell.imageView.image = [ImageUtils scaleImage:[UIImage imageNamed:@"wepay_logo_green_200x200"] toWidth:24];
				cell.titleLabel.text = IMLocalizedString(@"WeChat Pay");
				cell.subtitleLabel.text = nil;
				cell.detailDisclosureButton.hidden = NO;
				[cell.detailDisclosureButton bk_removeEventHandlersForControlEvents:UIControlEventTouchUpInside];
				[cell.detailDisclosureButton bk_addEventHandler:^(id sender) {
					[self performSegueForPaymentMethodDescription:IMLocalizedString(@"_WECHAT_PAY_")];
				} forControlEvents:UIControlEventTouchUpInside];
				cell.accessoryType = self.wechatpaySelected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
			}];
			[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				@strongify(self)
				self.wechatpaySelected = YES;
				[tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
				[self reloadFooterView];
			}];
			[array addObject:data];
		}
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.reuseIdentifier = NSStringFromClass([BusSearchDetailPriceCell class]);
			data.isCustomRegistered = YES;
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusSearchDetailPriceCell *cell) {
				@strongify(self)
				cell.imageView.image = [UIImage imageNamed:@"icon_unionpay_cloud_quickpass"];
				if (YES) {
					NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
					[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:IMLocalizedString(@"UnionPay")]];
					[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:@" "]];
					[attributedString appendAttributedString:[CocoaUtils attributedStringForImage:[UIImage imageNamed:@"icon_unionpay"] verticalAlignWithFont:cell.titleLabel.font]];
					cell.titleLabel.attributedText = attributedString;
				}
				cell.subtitleLabel.text = nil;
				cell.detailDisclosureButton.hidden = NO;
				[cell.detailDisclosureButton bk_removeEventHandlersForControlEvents:UIControlEventTouchUpInside];
				[cell.detailDisclosureButton bk_addEventHandler:^(id sender) {
					[self performSegueForPaymentMethodDescription:IMLocalizedString(@"_UNIONPAY_")];
				} forControlEvents:UIControlEventTouchUpInside];
				cell.accessoryType = self.unionpaySelected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
			}];
			[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				@strongify(self)
				self.unionpaySelected = YES;
				[tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
				[self reloadFooterView];
			}];
			[array addObject:data];
		}
	} else {
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.reuseIdentifier = NSStringFromClass([BusSearchDetailPriceCell class]);
			data.isCustomRegistered = YES;
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusSearchDetailPriceCell *cell) {
				@strongify(self)
				cell.imageView.image = [DrawUtils tableViewCellImageWithFAKIcon:[FAKFontAwesome creditCardIconWithSize:20] fillColor:[Vars defaultTintColor]];
				cell.titleLabel.text = IMLocalizedString(@"Credit Card");
				cell.subtitleLabel.text = nil;
				cell.detailDisclosureButton.hidden = NO;
				[cell.detailDisclosureButton bk_removeEventHandlersForControlEvents:UIControlEventTouchUpInside];
				[cell.detailDisclosureButton bk_addEventHandler:^(id sender) {
					NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
					[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:IMLocalizedString(@"A debit card with VISA, MasterCard or American Express logo can be accepted as a credit card") attributes:@{ NSForegroundColorAttributeName : [UIColor darkGrayColor] }]];
					[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:@"\n"]];
					[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:IMLocalizedString(@"Your payment details are secure") attributes:@{ NSForegroundColorAttributeName : [UIColor blueColor] }]];
					[self performSegueForPaymentMethodDescription:attributedString];
				} forControlEvents:UIControlEventTouchUpInside];
				cell.accessoryType = self.creditCardSelected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
			}];
			[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				@strongify(self)
				self.creditCardSelected = YES;
				[tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
				[self reloadFooterView];
			}];
			[array addObject:data];
		}
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			[data setPreInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				@strongify(self)
				data.image = [ImageUtils scaleImage:[ImageUtils imageWithColor:[UIColor clearColor]] toWidth:24];
				if (self.selectedCreditCard) {
					data.text = nil;
					data.attributedText = [self.selectedCreditCard attributedRedactedCardNumberIfDefaultAppendingWithFormat:[self.selectedCreditCard.cardTypeName im_stringByAppendingString:@" (%@)"]];
					data.textColor = [UIColor darkGrayColor];
					data.textFont = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
					data.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
				} else {
					data.text = [NSString stringWithFormat:IMLocalizedString(@"Add %@"), IMLocalizedString(@"Credit Card")];
					data.attributedText = nil;
					data.textColor = [UIColor blackColor];
					data.textFont = [UIConstants defaultTableViewCellTextLabelFont:UITableViewCellStyleDefault];
					data.accessoryType = UITableViewCellAccessoryNone;
				}
			}];
			[data setAccessoryViewBlock:^UIView *(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				return self.selectedCreditCard ? nil : [[UIImageView alloc] initWithImage:[DrawUtils imageWithFAKIcon:[FAKIonIcons iosPlusIconWithSize:24] fillColor:[Vars defaultTintColor]]];
			}];
			[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				@strongify(self)
                if (self.selectedCreditCard) {
                    [self performSegueForCreditCardList:self.selectedCreditCard];
                } else {
                    [self performSegueForCreditCardDetail:self.selectedCreditCard];
                }
			}];
			data.validationMessageCaption = IMLocalizedString(@"Credit Card");
			[data setRequiredValidationRuleBlock:^BOOL {
				@strongify(self)
				return !self.creditCardSelected || self.selectedCreditCard;
			}];
			[array addObject:data];
		}
		if (self.allowsPaypal) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.reuseIdentifier = NSStringFromClass([BusSearchDetailPriceCell class]);
			data.isCustomRegistered = YES;
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusSearchDetailPriceCell *cell) {
				@strongify(self)
				cell.imageView.image = [ImageUtils scaleSVGImageNamed:@"icon_paypal" toSize:CGSizeMake(24, 24)];
				cell.titleLabel.text = IMLocalizedString(@"PayPal");
				cell.subtitleLabel.text = nil;
				cell.detailDisclosureButton.hidden = NO;
				[cell.detailDisclosureButton bk_removeEventHandlersForControlEvents:UIControlEventTouchUpInside];
				[cell.detailDisclosureButton bk_addEventHandler:^(id sender) {
					[self performSegueForPaymentMethodDescription:IMLocalizedString(@"1. PayPal is an electronic payment system that allows you to pay through the use of your PayPal account or through the PayPal Web site.\n2. If the status of your Paypal transaction shows as \"Payment Review\", reservation is not confirmed until cleared receipt of the payment. In case of any price changes at the time of confirmation, we will notify you of the price change and ask your acceptance before processing your order. Your shopping cart will be expired after 15 min. Please remit payment as soon as possible.")];
				} forControlEvents:UIControlEventTouchUpInside];
				cell.accessoryType = self.paypalSelected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
			}];
			[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
				@strongify(self)
				self.paypalSelected = YES;
				[tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
				[self reloadFooterView];
			}];
			[array addObject:data];
		}
        if (self.allowsMyAccount) {
            TableViewCellData *data = [[TableViewCellData alloc] init];
            data.reuseIdentifier = NSStringFromClass([BusSearchDetailPriceCell class]);
            data.isCustomRegistered = YES;
            [data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, BusSearchDetailPriceCell *cell) {
                @strongify(self)
                cell.imageView.image = [DrawUtils tableViewCellImageWithFAKIcon:[FAKFontAwesomeSolid userIconWithSize:24] fillColor:[Vars defaultTintColor]];
                cell.titleLabel.text = IMLocalizedString(@"My Account");
				cell.subtitleLabel.text = nil;
				cell.detailDisclosureButton.hidden = YES;
                cell.accessoryType = self.myAccountSelected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
            }];
            [data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
                @strongify(self)
                self.myAccountSelected = YES;
                [tableView reloadSections:[NSIndexSet indexSetWithIndex:3] withRowAnimation:UITableViewRowAnimationNone];
                [self reloadFooterView];
            }];
            [array addObject:data];
        }
	}
}

- (void)reloadFooterView {
	UIButton *button = [self.tableView.tableFooterView viewWithTag:NSStringFromClass([UIButton class]).hash];
	if (self.paypalSelected) {
		button.backgroundColor = [CocoaUtils colorWithRGBs:0xffc439];
		[button setImage:[ImageUtils scaleSVGImageNamed:@"logo_paypal" byFactor:1] forState:UIControlStateNormal];
		[button setTitle:nil forState:UIControlStateNormal];
	} else if (self.wechatpaySelected) {
		button.backgroundColor = [CocoaUtils colorWithRGBs:0x1aad19];
		[button setImage:[ImageUtils scaleImage:[UIImage imageNamed:@"wepay_logo_default_white_500x126"] toHeight:CGRectGetHeight(button.frame) - 5 * 2] forState:UIControlStateNormal];
		[button setTitle:nil forState:UIControlStateNormal];
    } else {
		button.backgroundColor = [Vars defaultTintColor];
		[button setImage:nil forState:UIControlStateNormal];
		[button setAttributedTitle:nil forState:UIControlStateNormal];
		[button setTitle:IMLocalizedString(@"Complete My Order") forState:UIControlStateNormal];
	}
}

- (BOOL)validateBooking {
	NSString *contactInfoValidationMessage = [Utility validationMessageWithContactInfo:self.selectedContactInfo];
	if (![StringUtils isEmpty:contactInfoValidationMessage]) {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:contactInfoValidationMessage dismissalHandler:^{
            [self performSegueForContactInfoDetail:self.selectedContactInfo];
		}];
		return NO;
	}
	if (self.creditCardSelected) {
		NSString *ccValidateionMessage = [Utility validationMessageWithCreditCard:self.selectedCreditCard];
		if (![StringUtils isEmpty:ccValidateionMessage]) {
			[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:ccValidateionMessage dismissalHandler:^{
                [self performSegueForCreditCardDetail:self.selectedCreditCard];
			}];
			return NO;
		}
	} else if (self.wechatpaySelected) {
#ifdef POD_OF_WechatOpenSDK
		if (![WXApi isWXAppInstalled]) {
			[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:[NSString stringWithFormat:IMLocalizedString(@"Please install \"%@\" first"), IMLocalizedString(@"WeChat")] otherActionTitle:IMLocalizedString(@"OK") otherActionHandler:^{
				[[UIApplication sharedApplication] openURL:[WXApi getWXAppInstallUrl]];
			}];
			return NO;
		}
		if (![WXApi isWXAppSupportApi]) {
			[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:[NSString stringWithFormat:IMLocalizedString(@"Please update \"%@\" first"), IMLocalizedString(@"WeChat")] otherActionTitle:IMLocalizedString(@"OK") otherActionHandler:^{
				[[UIApplication sharedApplication] openURL:[WXApi getWXAppInstallUrl]];
			}];
			return NO;
		}
#endif
	}
	[self.tableView endEditing:YES];
	for (int section = 0; section < self.cellDataArrays.count; section++) {
		for (int row = 0; row < [self.cellDataArrays[section] count]; row++) {
			NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
			TableViewCellData *data = self.cellDataArrays[section][row];
			if (![data validateRequired]) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[data requiredValidationMessage:NO] dismissalHandler:^{
					[UIToolkit tableView:self.tableView atIndexPath:indexPath didFocusWithData:data];
				}];
				return NO;
			}
			if (![data validateIntegrity]) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[data integrityValidationMessage:NO] dismissalHandler:^{
					[UIToolkit tableView:self.tableView atIndexPath:indexPath didFocusWithData:data];
				}];
				return NO;
			}
		}
	}
	return YES;
}

- (void)preInstallBooking {
	[self addContactInfoToBookGoods];
	[self checkDuplicatedBooking];
}

- (void)postInstallBooking {
	if (self.paypalSelected && ![StringUtils isEmpty:self.outTradeNo] && ![StringUtils isEmpty:self.paymentId]) {
		[self performRequestForGetThirdPartyPaymentState];
	} else if ((self.wechatpaySelected || self.alipaySelected || self.unionpaySelected) && ![StringUtils isEmpty:self.outTradeNo]) {
		[self performRequestForGetThirdPartyPaymentState];
	}  else {
		[self submitBooking];
	}
}

- (void)submitBooking {
	[self addContactInfoToBookGoods];
	[self addPaymentInfoToBookGoods];
	[self bookGoods];
}

- (void)addContactInfoToBookGoods {
	if (self.selectedContactInfo) {
		Address *contactInfo = [self.selectedContactInfo copy];
		contactInfo.aid = 0;
		contactInfo.isDefault = NO;
		[Vars appDelegate].shopCarts.bookGoods.contactInfo = contactInfo;
	}
}

- (void)addPaymentInfoToBookGoods {
	if (self.creditCardSelected && self.selectedCreditCard) {
		CreditCard *creditCard = [self.selectedCreditCard copy];
		creditCard.ccid = 0;
		creditCard.isDefault = NO;
		creditCard.address.aid = 0;
		[Vars appDelegate].shopCarts.bookGoods.paymentInfo.credit_card = creditCard;
	} else if (self.paypalSelected) {
#if DEBUG
		if (self.isPaypalSandbox) {
			[Vars appDelegate].shopCarts.bookGoods.paymentInfo.paypal_payment.sandbox = YES;
		} else {
			[Vars appDelegate].shopCarts.bookGoods.paymentInfo.paypal_payment.live_testing = YES;
		}
#endif
    } else if (self.wechatpaySelected) {
#if DEBUG
		[Vars appDelegate].shopCarts.bookGoods.paymentInfo.wechatpay_payment.live_testing = YES;
#endif
	} else if (self.alipaySelected) {
#if DEBUG
		[Vars appDelegate].shopCarts.bookGoods.paymentInfo.alipay_payment.live_testing = YES;
#endif
	} else if (self.unionpaySelected) {
#if DEBUG
		if (self.isUnionpaySandbox) {
			[Vars appDelegate].shopCarts.bookGoods.paymentInfo.unionpay_payment.sandbox = YES;
		} else {
			[Vars appDelegate].shopCarts.bookGoods.paymentInfo.unionpay_payment.live_testing = YES;
		}
#endif
	}
	[Vars appDelegate].shopCarts.bookGoods.paymentInfo.total_charge = [self.checkAvailabilityAndPricesResponse totalFareNumberWithCurrencyCode:[Vars appDelegate].shopCarts.currency_code];
}

#pragma mark - PayPal-iOS-SDK

- (void)createPaypalSinglePayment {
	NSDecimalNumber *total = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%g", self.checkAvailabilityAndPricesResponse.total_charge]];
	NSString *itemName = [NSString stringWithFormat:@"%@ Order", [Vars site_name]];
	PayPalConfiguration *paypalconfig = [[PayPalConfiguration alloc] init];
	paypalconfig.acceptCreditCards = NO;
	paypalconfig.languageOrLocale = @"en";
	PayPalPayment *payment = [PayPalPayment paymentWithAmount:total currencyCode:@"USD" shortDescription:itemName intent:PayPalPaymentIntentSale];
	payment.invoiceNumber = self.outTradeNo;
	if (payment.processable) {
		PayPalPaymentViewController *viewController = [[PayPalPaymentViewController alloc] initWithPayment:payment configuration:paypalconfig delegate:self];
		[self presentViewController:viewController animated:YES completion:nil];
	} else {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:[Vars responseException]];
	}
}

- (void)savePaypalProofOfPayment:(PayPalPayment *)completedPayment {
	if (completedPayment.confirmation && completedPayment.confirmation[@"response"] && completedPayment.confirmation[@"response"][@"id"]) {
		self.paymentId = completedPayment.confirmation[@"response"][@"id"];
	}
	if ([StringUtils isEmpty:self.paymentId]) {
		[CocoaUtils showConfirmWithTitle:IMLocalizedString(@"Information") message:IMLocalizedString(@"An error occurred, please try again.") otherActionTitle:IMLocalizedString(@"Retry Pay") otherActionHandler:^{
			[self submitBooking];
		}];
	} else {
		[self performRequestForGetThirdPartyPaymentState];
	}
}

#pragma mark - AlipaySDK

- (void)receivePaymentWithAlipayOrderPaymentResult:(NSDictionary *)resultDic {
	BOOL flag = NO;
	if ([resultDic[@"resultStatus"] isEqualToString:@"9000"]) {
		flag = YES;
	}
	if (flag) {
		[self performRequestForGetThirdPartyPaymentState];
	} else {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[NSString stringWithFormat:IMLocalizedString(@"Please confirm %@ transcation"), IMLocalizedString(@"Alipay")]];
	}
}

#pragma mark - WechatOpenSDK

- (void)receivePaymentWithWXPayResp:(id)obj {
	self.paySending = NO;
	BOOL flag = NO;
#ifdef POD_OF_WechatOpenSDK
	PayResp *resp = obj;
	if (resp.errCode == WXSuccess) {
		flag = YES;
	}
#endif
	if (flag) {
		[self performRequestForGetThirdPartyPaymentState];
	} else {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[NSString stringWithFormat:IMLocalizedString(@"Please confirm %@ transcation"), IMLocalizedString(@"WeChat Pay")]];
	}
}

#pragma mark - UPPaymentControl

- (void)receivePaymentWithUPPaymentResult:(NSDictionary *)dict {
	self.paySending = NO;
	BOOL flag = NO;
	if ([dict[@"code"] isEqualToString:@"success"]) {
		flag = YES;
	}
	if (flag) {
		[self performRequestForGetThirdPartyPaymentState];
	} else {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[NSString stringWithFormat:IMLocalizedString(@"Please confirm %@ transcation"), IMLocalizedString(@"UnionPay")]];
	}
}

#pragma mark - Table view methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
	return self.cellDataArrays.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
	return [self.cellDataArrays[section] count];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
	if (self.sectionHeaderTitles[section] == [NSNull null]) {
		return nil;
	}
	return self.sectionHeaderTitles[section];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
	TableViewCellData *data = self.cellDataArrays[indexPath.section][indexPath.row];
	return [UIToolkit tableView:tableView atIndexPath:indexPath rowHeightWithData:data];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	TableViewCellData *data = self.cellDataArrays[indexPath.section][indexPath.row];
	return [UIToolkit tableView:tableView atIndexPath:indexPath cellWithData:data];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	[tableView deselectRowAtIndexPath:indexPath animated:YES];
	TableViewCellData *data = self.cellDataArrays[indexPath.section][indexPath.row];
	[UIToolkit tableView:tableView atIndexPath:indexPath didSelectWithData:data];
}

#pragma mark - Text field delegate

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
	if (textField.tag == NSStringFromClass([UITextField class]).hash) {
		if (range.location >= 4) {
			return NO;
		}
	}
	return YES;
}

#pragma mark - <PayPalPaymentDelegate>

- (void)payPalPaymentViewController:(PayPalPaymentViewController *)paymentViewController didCompletePayment:(PayPalPayment *)completedPayment {
	[self dismissViewControllerAnimated:YES completion:^{
		[self savePaypalProofOfPayment:completedPayment];
	}];
}

- (void)payPalPaymentDidCancel:(PayPalPaymentViewController *)paymentViewController {
	[self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark

- (void)dealloc {
	NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
	[notificationCenter removeObserver:self name:AddressDidSelectNotification object:nil];
	[notificationCenter removeObserver:self name:CreditCardDidSelectNotification object:nil];
	if ([Vars is_cn_website]) {

		[notificationCenter removeObserver:self name:WXPayRespNotification object:nil];
		[notificationCenter removeObserver:self name:UPPaymentResultNotification object:nil];
		[notificationCenter removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
		[notificationCenter removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
	}
}

@end

