//
// SearchHotelResponseJsonMapper.m
// Project
//
// Created by Ziv on 15/12/14.
//
//

#import "SearchHotelResponseJsonMapper.h"
#import "Lang.h"
#import "BeanUtils.h"
#import "CocoaUtils.h"
#import <RestKit/RKObjectMappingOperationDataSource.h>
#import "HotelSearchData.h"
#import "Vars.h"

@implementation SearchHotelResponseJsonMapper

- (instancetype)init {
	if (self = [super init]) {
		RKObjectMapping *amenityMapping = [RKObjectMapping mappingForClass:[HotelAmenity class]];
		[amenityMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelAmenity class]]];

		RKObjectMapping *refMapping = [RKObjectMapping mappingForClass:[HotelRefPoint class]];
		[refMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelRefPoint class]]];

		RKObjectMapping *baseInfoMapping = [RKObjectMapping mappingForClass:[HotelDetailProp class]];
		[baseInfoMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelDetailProp class]]];

		RKObjectMapping *locationMapping = [RKObjectMapping mappingForClass:[HotelLocation class]];
		[locationMapping addAttributeMappingsFromDictionary:[CocoaUtils dictionaryForKeys:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelLocation class]] retainEntries:@{ @"zip" : @"zipcode", @"address" : @"street" }]];

		RKObjectMapping *roomBoardMapping = [RKObjectMapping mappingForClass:[HotelSearchRoomTypeBoardbase class]];
		[roomBoardMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelSearchRoomTypeBoardbase class]]];

		RKObjectMapping *promotionMapping = [RKObjectMapping mappingForClass:[HotelSearchRoomTypePromotion class]];
		[promotionMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelSearchRoomTypePromotion class]]];

		RKObjectMapping *facilityMapping = [RKObjectMapping mappingForClass:[HotelRoomTypeFacility class]];
		[facilityMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelRoomTypeFacility class]]];

		RKObjectMapping *detailRoomTypeMapping = [RKObjectMapping mappingForClass:[HotelSearchRoomType class]];
		[detailRoomTypeMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelSearchRoomType class]]];
		[detailRoomTypeMapping addRelationshipMappingWithSourceKeyPath:@"t_boardbases" mapping:roomBoardMapping];
		[detailRoomTypeMapping addRelationshipMappingWithSourceKeyPath:@"promotion_xml" mapping:promotionMapping];
		[detailRoomTypeMapping addRelationshipMappingWithSourceKeyPath:@"facilities" mapping:facilityMapping];

		RKObjectMapping *roomTypeMapping = [RKObjectMapping mappingForClass:[HotelSearchRoomData class]];
		[roomTypeMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelSearchRoomData class]]];
		[roomTypeMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"t_room_type" toKeyPath:@"t_room_types" withMapping:detailRoomTypeMapping]];

		RKObjectMapping *descriptionMapping = [RKObjectMapping mappingForClass:[HotelSearchDetailData class]];
		[descriptionMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelSearchDetailData class]]];
		[descriptionMapping addAttributeMappingsFromArray:@[@"images", @"general_descriptions", @"d_locations", @"location_attractions", @"recreations", @"restaurants_lounges", @"accommodations", @"services", @"meeting_facilities", @"parkings"]];
		[descriptionMapping addRelationshipMappingWithSourceKeyPath:@"hotel_base_info" mapping:baseInfoMapping];
		[descriptionMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations" toKeyPath:@"location" withMapping:locationMapping]];
		[descriptionMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"ref_points" toKeyPath:@"ref_point" withMapping:refMapping]];
		[descriptionMapping addRelationshipMappingWithSourceKeyPath:@"amenities" mapping:amenityMapping];

		RKObjectMapping *dataMapping = [RKObjectMapping mappingForClass:[HotelSearchData class]];
		[dataMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[HotelSearchData class]]];
		[dataMapping addAttributeMappingsFromArray:@[@"dateOption"]];
		[dataMapping addRelationshipMappingWithSourceKeyPath:@"hotel_description_ext" mapping:descriptionMapping];
		[dataMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"t_room_types" toKeyPath:@"t_room" withMapping:roomTypeMapping]];

		RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[SearchHotelResponse class]];
		[responseMapping addAttributeMappingsFromArray:[BeanUtils keysForAccessibleSimplePropertyWithClass:[SearchHotelResponse class]]];
		[responseMapping addRelationshipMappingWithSourceKeyPath:@"products" mapping:dataMapping];

		self.objectMapping = responseMapping;
	}
	return self;
}

#pragma mark - Public

- (NSError *)parseWithJSONObject:(id)jsonObject {
	self.response = [[SearchHotelResponse alloc] init];

	RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:jsonObject destinationObject:self.response mapping:self.objectMapping];
	RKObjectMappingOperationDataSource *mappingOperationDataSource = [[RKObjectMappingOperationDataSource alloc] init];
	mappingOperation.dataSource = mappingOperationDataSource;

	NSError *error = nil;
	if ([mappingOperation performMapping:&error]) {
		if (![Vars is_cn_website]) {
			for (HotelSearchData *product in self.response.products) {
				for (HotelSearchRoomType *roomType in product.t_room.t_room_types) {
					[self makeObjects:roomType.facilities stringEncodingForKey:@"name"];
				}
				for (NSString *key in @[@"free_text_long_description", @"voucher_remark"]) {
					[self makeObject:product.hotel_description_ext stringEncodingForKey:key];
				}
				for (NSString *key in @[@"general_descriptions", @"d_locations", @"location_attractions", @"recreations", @"restaurants_lounges", @"services", @"accommodations", @"meeting_facilities", @"parkings"]) {
					[self makeObject:product.hotel_description_ext stringsEncodingForKey:key];
				}
				[self makeObjects:product.hotel_description_ext.amenities stringEncodingForKey:@"amenity_name"];
			}
		}
	}
	return error;
}

#pragma mark - Private

- (void)makeObjects:(NSArray *)objects stringEncodingForKey:(NSString *)key {
	for (id obj in objects) {
		NSString *str = [obj valueForKey:key];
		if (str) {
			NSData *data = [str dataUsingEncoding:[Vars charset]];
			if (data) {
				NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
				if (string) {
					[obj setValue:string forKey:key];
				}
			}
		}
	}
}

- (void)makeObject:(id)object stringEncodingForKey:(NSString *)key {
	NSString *str = [object valueForKey:key];
	if (str) {
		NSData *data = [str dataUsingEncoding:[Vars charset]];
		if (data) {
			NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
			if (string) {
				[object setValue:string forKey:key];
			}
		}
	}
}

- (void)makeObject:(id)object stringsEncodingForKey:(NSString *)key {
	NSMutableArray *array = [NSMutableArray array];
	for (NSString *str in [object valueForKey:key]) {
		if (str) {
			NSData *data = [str dataUsingEncoding:[Vars charset]];
			if (data) {
				NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
				if (string) {
					[array addObject:string];
				}
			}
		}
	}
	[object setValue:[NSArray arrayWithArray:array] forKey:key];
}

@end
