//
// BookingReviewViewController.m
// GoToBus
//
// Created by iphone development on 7/24/14.
//
//

#import "BookingReviewViewController.h"
#import "Lang.h"
#import "SDK.h"
#import "BeanUtils.h"
#import "CocoaUtils.h"
#import "ContactsManager.h"
#import "DrawUtils.h"
#import "ImageUtils.h"
#import "TextViewController.h"
#import "UIConstants.h"
#import "UIToolkit.h"
#import "DTAttributedTextViewController.h"
#import <BlocksKit/BlocksKit.h>
#import <BlocksKit/BlocksKit+UIKit.h>
#import <libextobjc/EXTScope.h>
#import <PureLayout/PureLayout.h>
#import "Utility.h"
#import "CartEntry.h"
#import "Label.h"
#import "SalesEntryRoom.h"
#import "SoldStock.h"
#import "HotelWS.h"
#import "PerlWS.h"
#import "CheckAvailabilityAndPricesResponseJsonMapper.h"
#import "AppTracker.h"
#import "BusSearchDetailPriceCell.h"
#import "BusSearchDetailPriceView.h"
#import "BookingCheckoutViewController.h"
#import "BookingPriceDetailViewController.h"
#import "FlightInfoViewController.h"
#import "LoginViewController.h"
#import "PassportViewController.h"
#import "Vars.h"

@interface BookingReviewViewController () {
	NSString *_restorationCurrencyCode;
}
@property (nonatomic, strong) NSArray *cellDataArrays;
@property (nonatomic, strong, readonly) UIStackView *stackView;
@end

@implementation BookingReviewViewController

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

- (void)viewDidLoad {
	[super viewDidLoad];
	// Do any additional setup after loading the view from its nib.
	
	[[AppTracker sharedInstance] sendView:[self class]];
	
	self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(calculatePrice)];

	if (YES) {
		UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), [UIConstants defaultTableViewRowHeight])];
		footerView.backgroundColor = [UIColor whiteColor];

		UIStackView *contentView = [[UIStackView alloc] initWithFrame:footerView.frame];
		contentView.tag = NSStringFromClass([UIStackView class]).hash;
		contentView.axis = UILayoutConstraintAxisHorizontal;
		contentView.alignment = UIStackViewAlignmentCenter;
		contentView.distribution = UIStackViewDistributionFill;
		contentView.spacing = 15;
		if ([CocoaUtils isIPhoneX]) {
			contentView.frame = CGRectSetWidth(contentView.frame, CGRectGetWidth(contentView.frame) - 15);
		}
		[footerView addSubview:contentView];

		BusSearchDetailPriceView *view = [BusSearchDetailPriceView viewFromNib];
		view.titleLabel.textColor = [Vars defaultTintColor];
		view.subtitleLabel.textColor = [UIColor blackColor];
		[contentView addArrangedSubview:view];
		if ([Vars is_cn_website]) {
			UIButton *currencyButton = [UIButton buttonWithType:UIButtonTypeCustom];
			currencyButton.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
			currencyButton.contentEdgeInsets = UIEdgeInsetsMake(5, 5, 5, 5);
			[currencyButton setTitleColor:[Vars defaultTintColor] forState:UIControlStateNormal];
			[currencyButton setImage:[DrawUtils imageWithFAKIcon:[FAKFontAwesome exchangeIconWithSize:currencyButton.titleLabel.font.pointSize] fillColor:[Vars defaultTintColor]] forState:UIControlStateNormal];
			[currencyButton bk_addEventHandler:^(id sender) {
				[Vars appDelegate].shopCarts.rmb_selected = ![Vars appDelegate].shopCarts.rmb_selected;
				[self reloadFixedFooterView];
			} forControlEvents:UIControlEventTouchUpInside];
			[Utility addRoundedBorderToView:currencyButton];
			[contentView addArrangedSubview:currencyButton];
		}

		BOOL hasHotel = [[Vars appDelegate].shopCarts.entries bk_any:^BOOL (CartEntry *obj) {
			return obj.product.is_hotel;
		}];
		if (hasHotel) {
			[view.detailDisclosureButton addTarget:self action:@selector(performSegueForPriceDetail) forControlEvents:UIControlEventTouchUpInside];
		}

		UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
		button.backgroundColor = [Vars defaultTintColor];
		button.titleLabel.font = [UIFont boldSystemFontOfSize:[UIFont buttonFontSize]];
		[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
		[button setTitle:IMLocalizedString(@"Checkout") forState:UIControlStateNormal];
		[button addTarget:self action:@selector(proceedToCheckout) forControlEvents:UIControlEventTouchUpInside];
		[button autoSetDimension:ALDimensionWidth toSize:[Vars is_cn_website] ? 80 : 120];
		[button autoSetDimension:ALDimensionHeight toSize:[UIConstants defaultTableViewRowHeight] - 2 * ([CocoaUtils isIPhoneX] ? 5 : 0)];
		if ([CocoaUtils isIPhoneX]) {
			[Utility addRoundedBorderToButton:button];
		}
		[contentView addArrangedSubview:button];

		self.fixedFooterView = footerView;
	}
	[self buildCellDataSource];
	
//	if (self.checkAvailabilityAndPricesResponse) {
//		[[AppTracker sharedInstance] sendCartUpdateTransactionWithResponse:self.checkAvailabilityAndPricesResponse];
//	}
}

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

	if (![_restorationCurrencyCode isEqualToString:[Vars appDelegate].shopCarts.currency_code]) {
		[self reloadFixedFooterView];
	}
}

- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];
	// ajax
	if (!self.checkAvailabilityAndPricesResponse) {
		[self calculatePrice];
	}
}

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

	_restorationCurrencyCode = [Vars appDelegate].shopCarts.currency_code;
}

#pragma mark - Property

- (UIStackView *)stackView {
	return [self.fixedFooterView viewWithTag:NSStringFromClass([UIStackView class]).hash];
}

#pragma mark - Action

- (void)calculatePrice {
	if ([self validateCalculate]) {
		[self checkAvailabilityAndPrices:nil];
	}
}

- (void)proceedToCheckout {
	if (![self validateCheckAvailabilityAndPricesResponse]) {
		return;
	}
	if (![self validateCheckout]) {
		return;
	}
	if (![Vars appDelegate].loginUser) {
		LoginViewController *viewController = [[LoginViewController alloc] init];
		viewController.pushFromBook = YES;
		[viewController performSegueWithObject:nil popAnimated:NO];
		[viewController setDestructiveBlock:^{
			if ([Vars appDelegate].loginUser) {
				[self checkAvailabilityAndPrices:^{
					[self performSegueForCheckout];
				}];
			} else {
				[self performSegueForCheckout];
			}
		}];
		[self.navigationController pushViewController:viewController animated:YES];
	} else {
		[self performSegueForCheckout];
	}
}

#pragma mark - Segue

- (void)performSegueForHTMLString:(NSString *)HTMLString andTitle:(NSString *)title isListStyle:(BOOL)isListStyle {
	DTAttributedTextViewController *viewController = [[DTAttributedTextViewController alloc] init];
	viewController.title = title;
	[[Vars appDelegate] applyDefaultConfigurationForViewController:viewController];
	viewController.textView.attributedTextContentView.edgeInsets = isListStyle ? UIEdgeInsetsMake(5, 5, 15, 15) : UIEdgeInsetsMake(15, 20, 5, 15);
	viewController.textView.attributedString = [[NSAttributedString alloc] initWithHTMLData:[HTMLString dataUsingEncoding:NSUTF8StringEncoding] options:[self optionsForDisplayingHTMLString] documentAttributes:NULL];
	[self.navigationController pushViewController:viewController animated:YES];
}

- (void)performSegueForPassportOfSoldStock:(SoldStock *)stock withLabel:(Label *)label onTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
	PassportViewController *viewController = [[PassportViewController alloc] initWithPassport:stock.passport];
	viewController.title = IMLocalizedString(label.name);
	viewController.readonly = NO;
	[viewController setDidCancelBlock:^{
		[self.navigationController popViewControllerAnimated:YES];
	}];
	[viewController setDidDoneBlock:^(Passport *passport) {
		[self.navigationController popViewControllerAnimated:YES];
		stock.passport = passport;
		stock.sold_to_name = passport.fullName;
		if (passport.distinguish_passport && passport.is_us_citizen) {
			if ([passport.us_gender isEqualToString:@"Male"]) {
				stock.gender = @"Mr.";
			} else if ([passport.us_gender isEqualToString:@"Female"]) {
				stock.gender = @"Ms.";
			}
		} else {
			if ([passport.gender isEqualToString:@"Male"]) {
				stock.gender = @"Mr.";
			} else if ([passport.gender isEqualToString:@"Female"]) {
				stock.gender = @"Ms.";
			}
		}
		[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
	}];
	[self.navigationController pushViewController:viewController animated:YES];
}

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

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

- (void)performSegueForTermsAndConditions {
	CartEntry *entry = [Vars appDelegate].shopCarts.entries[0];
	TextViewController *viewController = [[TextViewController alloc] init];
	viewController.title = IMLocalizedString(@"Terms and Conditions");
	[[Vars appDelegate] applyDefaultConfigurationForViewController:viewController];
	if (entry.product.is_hotel) {
		UIFont *font1 = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
		UIFont *font2 = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
		NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
		NSDictionary *titleAttributes = @{ NSForegroundColorAttributeName : [UIColor blackColor], NSFontAttributeName : font1 };
		NSDictionary *contentAttributes = @{ NSForegroundColorAttributeName : [UIColor darkGrayColor], NSFontAttributeName : font2 };
		if (![StringUtils isEmpty:entry.product.cancellationPolicies]) {
			if (attributedString.length > 0) {
				[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:@"\n\n"]];
			}
			[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:IMLocalizedString(@"Cancellation Policies") attributes:titleAttributes]];
			[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:@"\n"]];
			[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:entry.product.cancellationPolicies attributes:contentAttributes]];
		}
		if (![StringUtils isEmpty:entry.product.voucherRemark]) {
			if (attributedString.length > 0) {
				[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:@"\n\n"]];
			}
			[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:IMLocalizedString(@"Special Remarks") attributes:titleAttributes]];
			[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:@"\n"]];
			[attributedString appendAttributedString:[[NSAttributedString alloc] im_initWithString:entry.product.voucherRemark attributes:contentAttributes]];
		}
		viewController.textView.attributedText = attributedString;
	}
	[self.navigationController pushViewController:viewController animated:YES];
}

#pragma mark - Network

- (void)checkAvailabilityAndPrices:(void (^)(void))completion  {
	if (self.checkAvailabilityAndPricesResponse) {
		self.checkAvailabilityAndPricesResponse = nil;
		[self reloadFixedFooterView];
	}

	CheckAvailabilityAndPrices *checkAvailabilityAndPrices = [[CheckAvailabilityAndPrices alloc] init];
	checkAvailabilityAndPrices.travelerDetails = [WebService travelerDetailsWithCartEntries:[Vars appDelegate].shopCarts.entries];
	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];
				[self reloadFixedFooterView];
				if (completion) {
					completion();
				}
			}
		}
	}];
}

- (void)getHotelPolicy:(CartEntry *)entry {
	GetHotelPolicy *hotelPolicy = [[GetHotelPolicy alloc] init];
	hotelPolicy.hotelId = entry.product.hotel_id;
	hotelPolicy.roomTypeId = [entry.options[@"roomTypeId"] integerValue];
	hotelPolicy.checkIn = [entry.options[@"date"][@"checkIn"] substringToIndex:10];
	hotelPolicy.checkOut = [entry.options[@"date"][@"checkOut"] substringToIndex:10];

	NSDictionary *requestDict = [BeanUtils describeAccessibleSimple:hotelPolicy];

	[Utility performSOAPRequestWithUrl:hotelPolicy.address namespace:hotelPolicy.namespace name:hotelPolicy.name parameters:requestDict success:^(NSString *xml) {
		NSString *responseStr = xml;
		// NSLog(@"%@", responseStr);
		NSString *ret = [CocoaUtils firstValueMatchedInString:responseStr forElement:@"return"];
		if (ret) {
			NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[ret dataUsingEncoding:NSUTF8StringEncoding] options:0 error:NULL];
			// NSLog(@"%@", responseDict);
			if (jsonDict) {
				WebServiceResponseJsonMapper *mapper = [[WebServiceResponseJsonMapper alloc] initWithClass:[GetHotelPolicyResponse class]];
				if (![mapper parseWithJSONObject:jsonDict]) {
					GetHotelPolicyResponse *response = mapper.response;
					if (![StringUtils isEmpty:response.error]) {
						[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:response.error];
					} else {
						NSArray *values = [CocoaUtils allValuesMatchedInString:response.cancell_policy forElement:@"li"];
						entry.product.cancellationPolicies = [values componentsJoinedByString:@"\n"];
						[self performSegueForTermsAndConditions];
					}
				}
			}
		}
	}];
}

#pragma mark - Private

- (void)buildCellDataSource {
	@weakify(self)
	for (int i = 0; i < [Vars appDelegate].shopCarts.entries.count; i++) {
		CartEntry *entry = [Vars appDelegate].shopCarts.entries[i];

		NSMutableArray *arrays = [NSMutableArray array];
		if (YES) {
			NSMutableArray *array = [NSMutableArray array];
			if (YES) {
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.text = entry.product.name;
				data.allowsTextLineWrapping = YES;
				[array addObject:data];
			}
			if (entry.product.tour_code) {
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.style = UITableViewCellStyleSubtitle;
				data.text = entry.product.tour_code;
				data.detailText = IMLocalizedString(@"Tour Code");
				data.detailTextColor = [UIColor lightGrayColor];
				[array addObject:data];
			}
			if (entry.product.is_hotel) {
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.text = [Utility localizedStringWithStandardDateString:[entry.options[@"date"][@"checkIn"] substringToIndex:10]];
					data.detailText = IMLocalizedString(@"Check-in Date");
					data.detailTextColor = [UIColor lightGrayColor];
					[array addObject:data];
				}
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.text = [Utility localizedStringWithStandardDateString:[entry.options[@"date"][@"checkOut"] substringToIndex:10]];
					data.detailText = IMLocalizedString(@"Check-out Date");
					data.detailTextColor = [UIColor lightGrayColor];
					[array addObject:data];
				}
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.allowsTextLineWrapping = YES;
					data.text = entry.options[@"roomType"];
					data.detailText = IMLocalizedString(@"Room Type");
					data.detailTextColor = [UIColor lightGrayColor];
					[array addObject:data];
				}
			} else {
				for (Label *label in entry.product.literalLabels) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					if (label.isKindOfDate) {
						data.text = [Utility localizedStringWithStandardDateString:[entry.options[label.alias] substringToIndex:10]];
					} else {
						if (label.isKindAsStop) {
							data.attributedText = [Utility attributedStringWithHtmlString:entry.options[label.alias] fixAttributes:@{ NSFontAttributeName : [UIConstants defaultTableViewCellTextLabelFont:UITableViewCellStyleSubtitle] }];
						} else {
							data.text = entry.options[label.alias];
						}
						data.allowsTextLineWrapping = YES;
					}
					data.detailText = label.name;
					data.detailTextColor = [UIColor lightGrayColor];
					[array addObject:data];
				}
			}
			if (entry.product.have_filght_info) {
				Label *label = [entry.product.labels bk_match:^BOOL (Label *label) {
					return [label isTypeOfFlightInfo];
				}];
				FlightInfo *flightInfo = entry.options[label.alias];
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.style = UITableViewCellStyleSubtitle;
				data.text = flightInfo.shortDescription;
				data.detailText = label.name;
				data.detailTextColor = [UIColor lightGrayColor];
				data.allowsTextLineWrapping = YES;
				if (flightInfo.isExplicit) {
					data.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
					[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
						@strongify(self)
						FlightInfoViewController *viewController = [[FlightInfoViewController alloc] initWithFlightInfo:flightInfo];
						viewController.title = label.name;
						viewController.readonly = YES;
						[self.navigationController pushViewController:viewController animated:YES];
					}];
				}
				[array addObject:data];
			}
			if (entry.product.is_hotel) {
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.text = IMLocalizedString(@"Terms and Conditions");
				data.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
				[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
					@strongify(self)
					if ([StringUtils isEmpty:entry.product.cancellationPolicies]) {
						[self getHotelPolicy:entry];
					} else {
						[self performSegueForTermsAndConditions];
					}
				}];
				[array addObject:data];
			} else if (![StringUtils isEmpty:entry.product.termsConditions]) {
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.text = IMLocalizedString(@"Terms and Conditions");
				data.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
				[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
					@strongify(self)
					[self performSegueForHTMLString: entry.product.termsConditions andTitle:IMLocalizedString(@"Terms and Conditions") isListStyle: NO];
				}];
				[array addObject:data];
			}
			[arrays addObject:[NSArray arrayWithArray:array]];
		}
		if (YES) {
			NSMutableArray *array = [NSMutableArray array];
			if (YES) {
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.text = entry.shortDescription;
				[array addObject:data];
			}
			Label *passportLabel = [entry.product.labels bk_match:^BOOL (Label *label) {
				return [label isTypeAsPassport];
			}];
			NSMutableArray *objs = [NSMutableArray array];
			if (entry.rooms.count > 0) {
				for (SalesEntryRoom *room in entry.rooms) {
					[objs addObject:room];
					if (room.checkin_guest) {
						[objs addObject:room.checkin_guest];
					} else {
						[objs addObjectsFromArray:room.stocks];
					}
				}
			} else {
				[objs addObjectsFromArray:entry.stocks];
			}
			for (id obj in objs) {
				if ([obj class] == [SalesEntryRoom class]) {
					SalesEntryRoom *room = obj;
					if (YES) {
						TableViewCellData *data = [[TableViewCellData alloc] init];
						data.text = room.shortDescription;
						[array addObject:data];
					}
				} else if ([obj class] == [SoldStock class]) {
					SoldStock *stock = obj;
					if (entry.product.is_need_passport) {
						TableViewCellData *data = [[TableViewCellData alloc] init];
						data.style = UITableViewCellStyleValue2;
						data.showsRequiredAsteriskDuringEditing = YES;
						data.text = IMLocalizedString(stock.people_type);
						[data setDetailTextBlock:^NSString *     {
							return stock.sold_to_name;
						}];
						[data setAccessoryViewBlock:^UIView *(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data){
							return [[UIImageView alloc] initWithImage:[ImageUtils imageNamed:@"icon_passport" tintColor:[UIColor lightGrayColor]]];
						}];
						data.validationMessageCaption = IMLocalizedString(passportLabel.name);
						[data setRequiredValidationRuleBlock:^BOOL {
							return ![StringUtils isEmpty:stock.passport.shortDescription];
						}];
						[data setDidSelectBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data) {
							@strongify(self)
							[self performSegueForPassportOfSoldStock: stock withLabel:passportLabel onTableView: tableView atIndexPath: indexPath];
						}];
						[array addObject:data];
					} else {
						if (entry.product.is_hotel) {
							if (YES) {
								TableViewCellData *data = [[TableViewCellData alloc] init];
								data.showsRequiredAsteriskDuringEditing = YES;
								data.editingType = TableViewCellEditingTypeTextField;
								data.placeholder = IMLocalizedString(@"First Name");
								data.autocapitalizationType = UITextAutocapitalizationTypeWords;
								data.textContentType = IMTextContentTypeGivenName;
								data.observedObject = stock;
								data.keyPath = @"firstName";
								[data setKeyboardToolbarActionForSelectionOfContactWithDisplayedPropertyKeys:@[CMContactGivenNameKey, CMContactFamilyNameKey] completion:^id (CMContact *contact) {
									stock.firstName = contact.givenName;
									stock.lastName = contact.familyName;
									return nil;
								}];
								[data addIntegrityValidationRuleBlock:^BOOL {
									return [Utility canBeConvertedToUrlEncodedFromString:stock.firstName];
								} withMessageBlock:^NSString *{
									return IMLocalizedString(@"Please enter alphabetic characters only");
								}];
								[array addObject:data];
							}
							if (YES) {
								TableViewCellData *data = [[TableViewCellData alloc] init];
								data.showsRequiredAsteriskDuringEditing = YES;
								data.editingType = TableViewCellEditingTypeTextField;
								data.placeholder = IMLocalizedString(@"Last Name");
								data.autocapitalizationType = UITextAutocapitalizationTypeWords;
								data.textContentType = IMTextContentTypeFamilyName;
								data.observedObject = stock;
								data.keyPath = @"lastName";
								[data setKeyboardToolbarActionForSelectionOfContactWithDisplayedPropertyKeys:@[CMContactGivenNameKey, CMContactFamilyNameKey] completion:^id (CMContact *contact) {
									stock.firstName = contact.givenName;
									stock.lastName = contact.familyName;
									return nil;
								}];
								[data addIntegrityValidationRuleBlock:^BOOL {
									return [Utility canBeConvertedToUrlEncodedFromString:stock.lastName];
								} withMessageBlock:^NSString *{
									return IMLocalizedString(@"Please enter alphabetic characters only");
								}];
								[array addObject:data];
							}
						} else {
							TableViewCellData *data = [[TableViewCellData alloc] init];
							data.style = UITableViewCellStyleValue2;
							data.showsRequiredAsteriskDuringEditing = YES;
							data.text = IMLocalizedString(stock.people_type);
							data.editingType = TableViewCellEditingTypeTextField;
							data.autocapitalizationType = UITextAutocapitalizationTypeWords;
							data.textContentType = IMTextContentTypeName;
							data.observedObject = stock;
							data.keyPath = @"sold_to_name";
							data.placeholder = IMLocalizedString(@"Traveler Name");
							[data setKeyboardToolbarActionForSelectionOfContactWithDisplayedPropertyKeys:@[CMContactGivenNameKey, CMContactFamilyNameKey] completion:^id (CMContact *contact) {
								stock.sold_to_name = contact.fullName;
								return nil;
							}];
							[data addIntegrityValidationRuleBlock:^BOOL {
								return [Utility canBeConvertedToUrlEncodedFromString:stock.sold_to_name];
							} withMessageBlock:^NSString *{
								return IMLocalizedString(@"Please enter alphabetic characters only");
							}];
							[array addObject:data];
						}
						if (entry.product.need_gender) {
							TableViewCellData *data = [[TableViewCellData alloc] init];
							data.style = entry.product.is_hotel ? UITableViewCellStyleValue1 : UITableViewCellStyleValue2;
							data.showsRequiredAsteriskDuringEditing = YES;
							data.text = IMLocalizedString(@"Gender");
							data.editingType = entry.product.is_hotel ? TableViewCellEditingTypePickerView : TableViewCellEditingTypeSegmentedControl;
							data.observedObject = stock;
							data.keyPath = @"gender";
							data.optionTexts = @[IMLocalizedString(@"Male"), IMLocalizedString(@"Female")];
							data.optionValues = @[@"Mr.", @"Ms."];
							[array addObject:data];
						}
					}
				}
			}
			[arrays addObject:[NSArray arrayWithArray:array]];
		}
		self.cellDataArrays = [NSArray arrayWithArray:arrays];
	}
}

- (NSDictionary *)optionsForDisplayingHTMLString {
	UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
	return @{ DTUseiOS6Attributes : @YES, DTDefaultFontFamily : font.familyName, DTDefaultFontSize : @(font.pointSize), DTDefaultLinkDecoration : @NO };
}

- (NSString *)replaceComputedStyleToHTMLString:(NSString *)htmlString {
	NSMutableString *string = [NSMutableString im_stringWithString:htmlString];
	NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"style=\".*?\"" options:NSRegularExpressionDotMatchesLineSeparators error:NULL];
	[regex replaceMatchesInString:string options:0 range:NSMakeRange(0, string.length) withTemplate:@""];
	[string replaceOccurrencesOfString:@"<p>" withString:@"" options:0 range:NSMakeRange(0, string.length)];
	[string replaceOccurrencesOfString:@"</p>" withString:@"" options:0 range:NSMakeRange(0, string.length)];
	return [NSString stringWithString:string];
}

- (void)reloadFixedFooterView {
	BusSearchDetailPriceView *view = self.stackView.arrangedSubviews[0];
	BOOL hasHotel = [[Vars appDelegate].shopCarts.entries bk_any:^BOOL (CartEntry *obj) {
		return obj.product.is_hotel;
	}];
	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]];
		view.titleLabel.text = string;
		view.detailDisclosureButton.hidden = !hasHotel;
	} else {
		view.titleLabel.text = IMLocalizedString(@"Calculating...");
		view.detailDisclosureButton.hidden = YES;
	}
	if ([Vars appDelegate].shopCarts.rmb_selected && self.checkAvailabilityAndPricesResponse.second_currency_discount > 0) {
		NSMutableString *string = [NSMutableString string];
		[string im_appendString:IMLocalizedString(@"RMB Discount")];
		[string im_appendString:IMLocalizedString(WORD_DIVIDER_SPACE)];
		[string im_appendString:self.checkAvailabilityAndPricesResponse.secondCurrencyDiscountText];
		view.subtitleLabel.text = string;
	} else {
		view.subtitleLabel.text = nil;
	}
	if ([Vars is_cn_website]) {
		UIButton *currencyButton = self.stackView.arrangedSubviews[1];
		currencyButton.hidden = !self.checkAvailabilityAndPricesResponse;
		if (self.checkAvailabilityAndPricesResponse) {
			[currencyButton setTitle:[@" " im_stringByAppendingString:[Vars appDelegate].shopCarts.rmb_selected ? IMLocalizedString(@"USD") : IMLocalizedString(@"CNY")] forState:UIControlStateNormal];
			[currencyButton sizeToFit];
		}
	}
}

- (BOOL)validateCheckout {
	[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;
}

- (BOOL)validateCalculate {
	[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 validateIntegrity]) {
				[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[data integrityValidationMessage:NO] dismissalHandler:^{
					[UIToolkit tableView:self.tableView atIndexPath:indexPath didFocusWithData:data];
				}];
				return NO;
			}
		}
	}
	return YES;
}

- (BOOL)validateCheckAvailabilityAndPricesResponse {
	if (self.checkAvailabilityAndPricesResponse.error_code > 0) {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:self.checkAvailabilityAndPricesResponse.error_message];
		return NO;
	}
	if (self.checkAvailabilityAndPricesResponse.total_charge <= 0) {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:[Vars responseException]];
		return NO;
	}
	BOOL hasHotel = [[Vars appDelegate].shopCarts.entries bk_any:^BOOL (CartEntry *obj) {
		return obj.product.is_hotel;
	}];
	if (hasHotel && self.checkAvailabilityAndPricesResponse.entries.count != [Vars appDelegate].shopCarts.entries.count) {
		[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Error") message:[Vars responseException]];
		return NO;
	}
	return YES;
}

#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];
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
	if (section == 1) {
		return [UIConstants defaultTableViewSectionHeight:tableView.style];
	}
	return 0;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
	if (section == 1) {
		return @" ";
	}
	return nil;
}

- (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];
}

@end
