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

#import "BookingReviewViewController.h"
#import "Lang.h"
#import "SDK.h"
#import "AppTracker.h"
#import "BeanUtils.h"
#import "CocoaUtils.h"
#import "ContactsManager.h"
#import "DrawUtils.h"
#import "NetUtils.h"
#import "TextViewController.h"
#import "UIConstants.h"
#import "UIToolkit.h"
#import <BlocksKit/BlocksKit.h>
#import <BlocksKit/BlocksKit+UIKit.h>
#import <libextobjc/EXTScope.h>
#import <PureLayout/PureLayout.h>
#import <RKNotificationHub/RKNotificationHub.h>
#import "Utility.h"
#import "CartEntry.h"
#import "SalesEntryRoom.h"
#import "SoldStock.h"
#import "HotelWS.h"
#import "CheckAvailabilityAndPricesResponseJsonMapper.h"
#import "AppUnit.h"
#import "BusSearchDetailPriceView.h"
#import "BookingCheckoutViewController.h"
#import "BookingPriceDetailViewController.h"
#import "LoginViewController.h"
#import "Vars.h"
#import "BookingReviewTipsCell.h"

@interface BookingReviewViewController ()

@property (nonatomic, assign) NSInteger selectedIndex;
@property (nonatomic, strong) RKNotificationHub *circleHub;
@property (nonatomic, strong) NSArray *allCellDataArrays;
@property (nonatomic, assign) BOOL isSameDepatureAndReturn;

@property (nonatomic, strong, readonly) NSArray<NSArray *> *cellDataArrays;
@property (nonatomic, strong, readonly) UIStackView *stackView;
@property (nonatomic, strong, readonly) UISegmentedControl *segmentedControl;
@property (nonatomic, assign, readonly) BOOL allowsRoundtripAutoFill;

@end

@implementation BookingReviewViewController

- (instancetype)init {
	self = [super init];
	if (self) {
		// Custom initialization
		self.title = @"Review";
		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)];
	[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([BookingReviewTipsCell class]) bundle:[NSBundle mainBundle]] forCellReuseIdentifier:NSStringFromClass([BookingReviewTipsCell class])];
	
	
	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];
		[view.detailDisclosureButton addTarget:self action:@selector(performSegueForPriceDetail) forControlEvents:UIControlEventTouchUpInside];
		[contentView addArrangedSubview:view];

		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 autoSetDimension:ALDimensionWidth toSize:120];
		[button autoSetDimension:ALDimensionHeight toSize:[UIConstants defaultTableViewRowHeight] - 2 * ([CocoaUtils isIPhoneX] ? 5 : 0)];
		[button addTarget:self action:@selector(proceedToCheckout) forControlEvents:UIControlEventTouchUpInside];
		if ([CocoaUtils isIPhoneX]) {
			[Utility addRoundedBorderToButton:button];
		}
		[contentView addArrangedSubview:button];

		self.fixedFooterView = footerView;
	}
	[self reloadFixedFooterView];
	if ([Vars appDelegate].shopCarts.entries.count > 1) {
		UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), [UIConstants defaultSegmentedControlHeight] + 15 * 2)];
		headerView.backgroundColor = [UIColor whiteColor];
		NSMutableArray *items = [NSMutableArray arrayWithObjects:@"DEPARTURE", @"RETURN", nil];
		if ([Vars appDelegate].shopCarts.hasBusHotelPackage) {
			[items addObject:@"HOTEL"];
		}
		UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
		segmentedControl.tag = NSStringFromClass([UISegmentedControl class]).hash;
		segmentedControl.frame = CGRectMake(15, 15, CGRectGetWidth([UIScreen mainScreen].bounds) - 15 * 2, [UIConstants defaultSegmentedControlHeight]);
		segmentedControl.selectedSegmentIndex = 0;
		[segmentedControl addTarget:self action:@selector(changedRT:) forControlEvents:UIControlEventValueChanged];
		[headerView addSubview:segmentedControl];
		if (![Vars appDelegate].shopCarts.hasBusHotelPackage) {
			self.circleHub = [[RKNotificationHub alloc] initWithView:segmentedControl];
			[self.circleHub scaleCircleSizeBy:0.6];
			[self.circleHub increment];
			[self.circleHub hideCount];
		}
		self.fixedHeaderView = headerView;
	}
	if (self.isSameDepatureAndReturn) {
		[self peopleCountChange];
	}
	[self buildCellDataSource];

}

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

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

#pragma mark - Action

- (void)changedRT:(UISegmentedControl *)segmentedControl {
	[self.tableView endEditing:YES];
	[self hideNotificationHub];
	if (self.isSameDepatureAndReturn) {
		[self buildCellDataSource];
	}
	self.selectedIndex = segmentedControl.selectedSegmentIndex;
	[self.tableView reloadData];
}


-(void)peopleCountChange{
	if (self.isSameDepatureAndReturn) {
		CartEntry *departureEntry = [Vars appDelegate].shopCarts.entries[0];
		CartEntry *returnEntry = [Vars appDelegate].shopCarts.entries[1];
		if (departureEntry.stocks.count > 5) {
			[departureEntry.stocks removeObjectsInRange:NSMakeRange(5, departureEntry.stocks.count - 5)];
		}
		NSArray *allowedTypes = departureEntry.product.PPLBasedPrice.allowedTypes;
		
		for (NSString *type in allowedTypes) {
			NSArray *departureStocks = [SoldStock filteredStocks:departureEntry.stocks byBasedType:type];
			NSArray *returnStocks = [SoldStock filteredStocks:returnEntry.stocks byBasedType:type];
			if (departureStocks.count != returnStocks.count) {
				[returnEntry.stocks removeObjectsInArray:returnStocks];
				[returnEntry.stocks addObjectsFromArray:departureStocks];
			}
		}
	}
	
}

- (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)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[self.selectedIndex];
	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;
	} else if (entry.product.is_bus) {
		viewController.textView.text = entry.product.termsConditions;
	}
	[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 - Property

-(BOOL)isSameDepatureAndReturn{
	CartEntry *entry = [[Vars appDelegate].shopCarts.entries bk_match:^BOOL (CartEntry *obj) {
		return obj.product.purchasedSeparately;
	}];
	if (entry && [Vars appDelegate].shopCarts.entries.count > 1) {
		return YES;
	}
	return NO;
}

- (NSArray *)cellDataArrays {
	if (self.allCellDataArrays.count == 0) {
		return nil;
	}
	return self.allCellDataArrays[self.selectedIndex];
}

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

- (UISegmentedControl *)segmentedControl {
	return [self.fixedHeaderView viewWithTag:NSStringFromClass([UISegmentedControl class]).hash];
}

- (BOOL)allowsRoundtripAutoFill {
	BOOL autoFill = NO;
	if (self.selectedIndex == 0 && [Vars appDelegate].shopCarts.entries.count > 1) {
		CartEntry *departureEntry = [Vars appDelegate].shopCarts.entries[0];
		CartEntry *arrivalEntry = [Vars appDelegate].shopCarts.entries[1];
		if (departureEntry.PPLBasedCountData.peopleCount == arrivalEntry.PPLBasedCountData.peopleCount && departureEntry.PPLBasedCountData.adultCount == arrivalEntry.PPLBasedCountData.adultCount && departureEntry.PPLBasedCountData.childCount == arrivalEntry.PPLBasedCountData.childCount) {
			autoFill = YES;
		}
	}
	return autoFill;
}

#pragma mark - Private

- (void)buildCellDataSource {
	if (YES) {
		NSMutableArray *array = [NSMutableArray array];
		for (int i = 0; i < [Vars appDelegate].shopCarts.entries.count; i++) {
			[array addObject:[NSMutableArray array]];
		}
		self.allCellDataArrays = [NSArray arrayWithArray:array];
	}
	@weakify(self)
	for (int i = 0; i < [Vars appDelegate].shopCarts.entries.count; i++) {
		self.selectedIndex = i;
		CartEntry *entry = [Vars appDelegate].shopCarts.entries[self.selectedIndex];
		NSMutableArray *arrays = self.cellDataArrays;
		if (YES) {
			NSMutableArray *array = [NSMutableArray array];
			if (YES) {
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.text = entry.product.busRouteName ? entry.product.busRouteName : entry.product.name;
				data.allowsTextLineWrapping = YES;
				[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 if (entry.product.is_bus) {
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.text = [Utility localizedStringWithStandardDateString:[entry.options[@"date"] substringToIndex:10]];
					data.detailText = IMLocalizedString(@"Departure Date");
					data.detailTextColor = [UIColor lightGrayColor];
					[array addObject:data];
				}
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.text = entry.product.vendor_obj.short_name;
					data.detailText = @"Operator";
					data.detailTextColor = [UIColor lightGrayColor];
					[array addObject:data];
				}
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.text = entry.product.schedule_id;
					data.detailText = @"Bus ID";
					data.detailTextColor = [UIColor lightGrayColor];
					[array addObject:data];
				}
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					if ([CocoaUtils isHtmlString:entry.options[@"departure"]]) {
						data.attributedText = [Utility attributedStringWithHtmlString:entry.options[@"departure"] fixAttributes:@{ NSFontAttributeName : [UIConstants defaultTableViewCellTextLabelFont:UITableViewCellStyleSubtitle] }];
					} else {
						data.text = entry.options[@"departure"];
					}
					data.detailText = @"Departure";
					data.detailTextColor = [UIColor lightGrayColor];
					data.allowsTextLineWrapping = YES;
					[array addObject:data];
				}
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.attributedText = [Utility attributedStringWithHtmlString:entry.options[@"arrival"] fixAttributes:@{ NSFontAttributeName : [UIConstants defaultTableViewCellTextLabelFont:UITableViewCellStyleSubtitle] }];
					data.detailText = @"Arrival";
					data.detailTextColor = [UIColor lightGrayColor];
					data.allowsTextLineWrapping = YES;
					[array addObject:data];
				}
				if (entry.options[@"priceType"]) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.style = UITableViewCellStyleSubtitle;
					data.text = entry.options[@"priceType"];
					data.detailText = @"Ticket Type";
					data.detailTextColor = [UIColor lightGrayColor];
					[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 performSegueForTermsAndConditions];
				}];
				[array addObject:data];
			}
			[arrays addObject:[NSArray arrayWithArray:array]];
		}
		if (entry.product.is_hotel) {
			NSMutableArray *array = [NSMutableArray array];
			if (YES) {
				TableViewCellData *data = [[TableViewCellData alloc] init];
				data.text = entry.shortDescription;
				[array addObject:data];
			}
			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 (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];
					}
					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]];
		} else if (entry.product.is_bus) {
			if (YES) {
				NSMutableArray *array = [NSMutableArray array];
				if (self.isSameDepatureAndReturn && self.selectedIndex == 1) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					data.reuseIdentifier = NSStringFromClass([BookingReviewTipsCell class]);
					data.usesAutomaticDimension = YES;
					[array addObject:data];
				}
				if (YES) {
					TableViewCellData *data = [[TableViewCellData alloc] init];
					[data setTextBlock:^NSString * {
						return entry.shortDescription;
					}];
					[array addObject:data];
				}
				arrays[1] = array;
			}
			if (YES) {
				NSArray *allowedTypes = entry.product.PPLBasedPrice.allowedTypes;
				for (int i = 0; i < allowedTypes.count * 2; ++i) {
					[arrays addObject:@[]];
				}
				[self updateTableViewCellDataArrayForPassengerCounter];
				[self updateTableViewCellDataArrayForPassengerList];
			}
		}
	}
	self.selectedIndex = 0;
}

- (void)updateTableViewCellDataArrayForPassengerCounter {
	CartEntry *entry = [Vars appDelegate].shopCarts.entries[self.selectedIndex];
	NSMutableArray *arrays = self.cellDataArrays;
	NSArray *allowedTypes = entry.product.PPLBasedPrice.allowedTypes;
	@weakify(self)
	for (int i = 0; i < allowedTypes.count; i++) {
		NSString *type = allowedTypes[i];
		TableViewCellData *data = [[TableViewCellData alloc] init];
		data.style = UITableViewCellStyleValue1;
		data.text = type;
		data.textColor = [Vars defaultTintColor];
		data.editingType = TableViewCellEditingTypeStepper;
		if (self.isSameDepatureAndReturn && self.selectedIndex == 1) {
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITableViewCell *cell) {
				IMStepper *stepper = [cell.contentView viewWithTag:NSStringFromClass([IMStepper class]).hash];
				stepper.incrementButton.enabled = NO;
				stepper.decrementButton.enabled = NO;
			}];
		}else{
			[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITableViewCell *cell) {
				IMStepper *stepper = [cell.contentView viewWithTag:NSStringFromClass([IMStepper class]).hash];
				if (stepper.value > stepper.minimumValue) {
					stepper.decrementButton.enabled = YES;
				}
				if (stepper.value < stepper.maximumValue) {
					stepper.incrementButton.enabled = YES;
				}
			}];
		}
		[data setValueObservingGetterBlock:^id {
			NSArray *stocks = [SoldStock filteredStocks:entry.stocks byBasedType:type];
			return @(stocks.count);
		}];
		[data setValueChangedPostActionBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, IMStepper *stepper) {
			@strongify(self)
			[self changePassengerListByPPLBasedType: type toCount:(int)stepper.value];
		}];
		arrays[[self sectionForPassengerCounterByPPLBasedType:type]] = [NSMutableArray arrayWithObject:data];
	}
	for (NSString *type in allowedTypes) {
		[self setRangeOfTableViewCellDataForPassengerCounterByPPLBasedType:type];
	}
}

- (void)updateTableViewCellDataArrayForPassengerList {
	CartEntry *entry = [Vars appDelegate].shopCarts.entries[self.selectedIndex];
	NSArray *allowedTypes = entry.product.PPLBasedPrice.allowedTypes;
	for (NSString *type in allowedTypes) {
		[self updateTableViewCellDataArrayForPassengerListByPPLBasedType:type];
	}
}

- (void)setRoundtripAutoFillOfTableViewCellData:(TableViewCellData *)data byPPLBasedType:(NSString *)type  {
	@weakify(self)
	if (self.allowsRoundtripAutoFill) {
		CartEntry *departureEntry = [Vars appDelegate].shopCarts.entries[0];
		CartEntry *arrivalEntry = [Vars appDelegate].shopCarts.entries[1];
		SoldStock *departureStock = data.observedObject;
		SoldStock *arrivalStock = arrivalEntry.stocks[[departureEntry.stocks indexOfObject:departureStock]];
		NSString *departureKeyPath = data.keyPath;
		NSString *arrivalKeyPath = data.keyPath;
		[data setEditingDidEndPostActionBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITextField *textField) {
			@strongify(self)
			[self setRangeOfTableViewCellDataForPassengerCounterByPPLBasedType: type];
			[tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:[self sectionForPassengerCounterByPPLBasedType:type]]] withRowAnimation:UITableViewRowAnimationNone];
			if (![StringUtils isEmpty:[departureStock valueForKeyPath:departureKeyPath]] && [StringUtils isEmpty:[arrivalStock valueForKeyPath:arrivalKeyPath]]) {
				[arrivalStock setValue:[departureStock valueForKeyPath:departureKeyPath] forKeyPath:arrivalKeyPath];
				self.selectedIndex = 1;
				[self setRangeOfTableViewCellDataForPassengerCounterByPPLBasedType:type];
				self.selectedIndex = 0;
			}
		}];
	} else {
		[data setEditingDidEndPostActionBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITextField *textField) {
			@strongify(self)
			[self setRangeOfTableViewCellDataForPassengerCounterByPPLBasedType: type];
			[tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:[self sectionForPassengerCounterByPPLBasedType:type]]] withRowAnimation:UITableViewRowAnimationNone];
		}];
	}
}

- (void)updateTableViewCellDataArrayForPassengerListByPPLBasedType:(NSString *)type {
	CartEntry *entry = [Vars appDelegate].shopCarts.entries[self.selectedIndex];
	NSMutableArray *arrays = self.cellDataArrays;
	NSMutableArray *array = [NSMutableArray array];
	for (SoldStock *stock in entry.stocks) {
		if (![stock.people_type isEqualToString:type]) {
			continue;
		}
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.style = UITableViewCellStyleValue2;
			NSMutableString *string = [NSMutableString string];
			[string im_appendString:IMLocalizedString(stock.people_type)];
			[string im_appendString:IMLocalizedString(WORD_DIVIDER_SPACE)];
			[string appendFormat:@"%d", [[SoldStock filteredStocks:entry.stocks byBasedType:stock.people_type] indexOfObject:stock] + 1];
			data.text = [NSString stringWithString:string];
			data.editingType = TableViewCellEditingTypeTextField;
			data.autocapitalizationType = UITextAutocapitalizationTypeWords;
			data.textContentType = IMTextContentTypeGivenName;
			data.observedObject = stock;
			data.keyPath = @"firstName";
			data.placeholder = IMLocalizedString(@"First Name");
			data.isEditingRequired = YES;
			if (self.isSameDepatureAndReturn && self.selectedIndex == 1) {
				[data setEditingControlPostConfigurationBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITextField * editingControl) {
					editingControl.enabled = NO;
				}];
			}else{
				[data setEditingControlPostConfigurationBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITextField * editingControl) {
					editingControl.enabled = YES;
				}];
			[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");
			}];
			}
			[self setRoundtripAutoFillOfTableViewCellData:data byPPLBasedType:type];
			[array addObject:data];
		}
		if (YES) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.style = UITableViewCellStyleValue2;
			data.text = @"";
			data.editingType = TableViewCellEditingTypeTextField;
			data.autocapitalizationType = UITextAutocapitalizationTypeWords;
			data.textContentType = IMTextContentTypeFamilyName;
			data.placeholder = IMLocalizedString(@"Last Name");
			data.observedObject = stock;
			data.keyPath = @"lastName";
			data.isEditingRequired = YES;
			if (self.isSameDepatureAndReturn && self.selectedIndex == 1) {
				[data setEditingControlPostConfigurationBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITextField * editingControl) {
					editingControl.enabled = NO;
				}];
			}else{
				[data setEditingControlPostConfigurationBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITextField * editingControl) {
					editingControl.enabled = YES;
				}];
				[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");
				}];
			}
			[self setRoundtripAutoFillOfTableViewCellData:data byPPLBasedType:type];
			[array addObject:data];
		}
		if (entry.product.PPLBasedPrice.enable_child_age && [stock.people_type isEqualToString:@"Child"]) {
			TableViewCellData *data = [[TableViewCellData alloc] init];
			data.style = UITableViewCellStyleValue2;
			data.text = IMLocalizedString(@"Age");
			data.editingType = TableViewCellEditingTypeStepper;
			data.observedObject = stock;
			data.keyPath = @"people_age";
			data.isEditingRequired = YES;
			if (self.isSameDepatureAndReturn && self.selectedIndex == 1) {
				[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITableViewCell *cell) {
					IMStepper *stepper = [cell.contentView viewWithTag:NSStringFromClass([IMStepper class]).hash];
					stepper.enabled = NO;
				}];
			}else{
				[data setPostInstallBlock:^(UITableView *tableView, NSIndexPath *indexPath, TableViewCellData *data, UITableViewCell *cell) {
					IMStepper *stepper = [cell.contentView viewWithTag:NSStringFromClass([IMStepper class]).hash];
					stepper.enabled = YES;
				}];
			}
			data.minimumValue = @(entry.product.PPLBasedPrice.child_age_from);
			data.maximumValue = @(entry.product.PPLBasedPrice.child_age_to);
			[array addObject:data];
		}
	}
	[CocoaUtils removeObjectsInArray:arrays[[self sectionForPassengerListByPPLBasedType:type]] fromIndex:1];
	[arrays[[self sectionForPassengerListByPPLBasedType:type]] addObjectsFromArray:array];
}

- (void)changePassengerListByPPLBasedType:(NSString *)type toCount:(NSInteger)count {
	CartEntry *entry = [Vars appDelegate].shopCarts.entries[self.selectedIndex];
	NSInteger oldCount = [SoldStock filteredStocks:entry.stocks byBasedType:type].count;
	NSInteger newCount = count;
	if (oldCount != newCount) {
		NSInteger index = -1;
		for (NSString *PPLBasedType in entry.product.PPLBasedPrice.allowedTypes) {
			index += [SoldStock filteredStocks:entry.stocks byBasedType:PPLBasedType].count;
			if ([PPLBasedType isEqualToString:type]) {
				break;
			}
		}
		if (oldCount < newCount) {
			for (int i = 0; i < newCount - oldCount; i++) {
				SoldStock *stock = [[SoldStock alloc] init];
				stock.people_type = type;
				if (entry.product.PPLBasedPrice.enable_child_age && [type isEqualToString:@"Child"]) {
					stock.people_age = entry.product.PPLBasedPrice.child_age_from;
				}
				[entry.stocks insertObject:stock atIndex:index + 1 + i];
			}
		} else if (oldCount > newCount) {
			for (int i = 0; i < oldCount - newCount; i++) {
				[entry.stocks removeObjectAtIndex:index - i];
			}
		}
		[self updateTableViewCellDataArrayForPassengerListByPPLBasedType:type];
		NSMutableArray *indexPaths = [NSMutableArray array];
		if (oldCount < newCount) {
			for (NSInteger i = oldCount; i < newCount; ++i) {
				NSInteger ageFactor = 0;
				if (entry.product.PPLBasedPrice.enable_child_age && [type isEqualToString:@"Child"]) {
					 ageFactor = 1;
				}
				[indexPaths addObjectsFromArray:[CocoaUtils indexPathsForRowsWithRange:NSMakeRange((2 + ageFactor) * i + 1, 2 + ageFactor) inSection:[self sectionForPassengerListByPPLBasedType:type]]];
			}
			[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
		} else if (oldCount > newCount) {
			for (NSInteger i = oldCount; i > newCount; --i) {
				NSInteger ageFactor = 0;
				if (entry.product.PPLBasedPrice.enable_child_age && [type isEqualToString:@"Child"]) {
					ageFactor = 1;
				}
				[indexPaths addObjectsFromArray:[CocoaUtils indexPathsForRowsWithRange:NSMakeRange((2 + ageFactor) * (i - 1) + 1, 2 + ageFactor) inSection:[self sectionForPassengerListByPPLBasedType:type]]];
			}
			[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
		}
		[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
		[self peopleCountChange];
		[self calculatePrice];
	}
}

- (NSInteger)sectionForPassengerListByPPLBasedType:(NSString *)type {
	return [self sectionForPassengerCounterByPPLBasedType:type];
}

- (NSInteger)sectionForPassengerCounterByPPLBasedType:(NSString *)type {
	CartEntry *entry = [Vars appDelegate].shopCarts.entries[self.selectedIndex];
	NSArray *allowedTypes = entry.product.PPLBasedPrice.allowedTypes;
	return 2 + 2 * [allowedTypes indexOfObject:type];
}

- (void)setRangeOfTableViewCellDataForPassengerCounterByPPLBasedType:(NSString *)type {
	CartEntry *entry = [Vars appDelegate].shopCarts.entries[self.selectedIndex];
	NSArray *arrays = self.allCellDataArrays[self.selectedIndex];
	TableViewCellData *data = arrays[[self sectionForPassengerCounterByPPLBasedType:type]][0];
	data.minimumValue = @([type isEqualToString:@"Adult"] ? 1 : 0);
	data.maximumValue = @50;
	if ([entry.product.apiSchema isEqualToString:@"GTG"]) {
		data.maximumValue = @5;
	}
}

- (void)reloadFixedFooterView {
	BusSearchDetailPriceView *priceView = self.stackView.arrangedSubviews[0];
	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]];
		priceView.titleLabel.text = string;
		priceView.detailDisclosureButton.hidden = NO;
	} else {
		priceView.titleLabel.text = IMLocalizedString(@"Calculating...");
		priceView.detailDisclosureButton.hidden = YES;
	}
	if (self.checkAvailabilityAndPricesResponse.app_first_purchase_discount > 0)  {
		priceView.subtitleLabel.text = [NSString stringWithFormat:@"%@ Off Applied", [self.checkAvailabilityAndPricesResponse currencyTextFromNumber:self.checkAvailabilityAndPricesResponse.app_first_purchase_discount currencyCode:[Vars appDelegate].shopCarts.currency_code]];
	} else if (self.checkAvailabilityAndPricesResponse.app_first_purchase_discount_rate > 0) {
		priceView.subtitleLabel.text = [NSString stringWithFormat:@"%@ Off Applied", [CocoaUtils percentStringWithNumber:@(self.checkAvailabilityAndPricesResponse.app_first_purchase_discount_rate)]];
	} else {
		priceView.subtitleLabel.text = nil;
	}
}

- (void)hideNotificationHub {
	if (self.selectedIndex == 1) {
		if (self.circleHub && self.circleHub.count == 1) {
			[self.circleHub decrement];
		}
	}
}

- (BOOL)validateCheckout {
	[self.tableView endEditing:YES];
	for (int i = 0; i < [Vars appDelegate].shopCarts.entries.count; i++) {
		BOOL flip = NO;
		if (self.segmentedControl) {
			if (self.selectedIndex != i) {
				self.selectedIndex = i;
				flip = 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]) {
					if (flip) {
						self.segmentedControl.selectedSegmentIndex = i;
						[self.segmentedControl sendActionsForControlEvents:UIControlEventValueChanged];
					}
					[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[data requiredValidationMessage:NO] dismissalHandler:^{
						[UIToolkit tableView:self.tableView atIndexPath:indexPath didFocusWithData:data];
					}];
					return NO;
				}
				if (![data validateIntegrity]) {
					if (flip) {
						self.segmentedControl.selectedSegmentIndex = i;
						[self.segmentedControl sendActionsForControlEvents:UIControlEventValueChanged];
					}
					[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[data integrityValidationMessage:NO] dismissalHandler:^{
						[UIToolkit tableView:self.tableView atIndexPath:indexPath didFocusWithData:data];
					}];
					return NO;
				}
			}
		}
	}
	if (self.segmentedControl) {
		self.selectedIndex = self.segmentedControl.selectedSegmentIndex;
	}
	return YES;
}

- (BOOL)validateCalculate {
	[self.tableView endEditing:YES];
	for (int i = 0; i < [Vars appDelegate].shopCarts.entries.count; i++) {
		BOOL flip = NO;
		if (self.segmentedControl) {
			if (self.selectedIndex != i) {
				self.selectedIndex = i;
				flip = 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]) {
					if (flip) {
						self.segmentedControl.selectedSegmentIndex = i;
						[self.segmentedControl sendActionsForControlEvents:UIControlEventValueChanged];
					}
					[CocoaUtils showAlertWithTitle:IMLocalizedString(@"Information") message:[data integrityValidationMessage:NO] dismissalHandler:^{
						[UIToolkit tableView:self.tableView atIndexPath:indexPath didFocusWithData:data];
					}];
					return NO;
				}
			}
		}
	}
	if (self.segmentedControl) {
		self.selectedIndex = self.segmentedControl.selectedSegmentIndex;
	}
	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;
	}
	if (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];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
	if (section == 1 && self.selectedIndex == 0) {
		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
