//
// TourSearchDetailRichCell.m
// Project
//
// Created by haibara on 10/26/15.
//
//

#import "TourSearchDetailRichFoldingCell.h"
#import <objc/message.h>
#import "SDK.h"
#import "CocoaUtils.h"
#import "DrawUtils.h"
#import "UIConstants.h"
#import <DTCoreText/DTCoreText.h>
#import "Vars.h"

@interface DTAttributedFoldingLabel : DTAttributedTextContentView
@property (nonatomic, assign) NSInteger collapseLines;
@property (nonatomic, assign, readwrite) BOOL linesExpanded;
@property (nonatomic, assign, readonly) BOOL needsFolding;
@property (nonatomic, strong, readonly) DTCoreTextLayoutFrame *expandLayoutFrame;
@property (nonatomic, strong, readonly) DTCoreTextLayoutFrame *collapseLayoutFrame;
@end

@implementation DTAttributedFoldingLabel

+ (Class)layerClass {
	return [CATiledLayer class];
}

- (void)setBounds:(CGRect)bounds {
	struct objc_super s;
	s.receiver = self;
	s.super_class = [UIView class];
	objc_msgSendSuper(&s, @selector(setBounds:), bounds);
}

#pragma mark - Protected

- (DTCoreTextLayouter *)layouter {
	if (!self.attributedString) {
		return nil;
	}
	DTCoreTextLayouter *layoutor = [[DTAttributedFoldingLabel sharedLayoutorCache] objectForKey:@(self.attributedString.hash)];
	if (!layoutor) {
		layoutor = [[DTCoreTextLayouter alloc] initWithAttributedString:self.attributedString];
		if (layoutor) {
			[[DTAttributedFoldingLabel sharedLayoutorCache] setObject:layoutor forKey:@(self.attributedString.hash)];
		}
	}
	return layoutor;
}

- (void)setAttributedString:(NSAttributedString *)string {
	if (_attributedString != string) {
		_attributedString = string;
	}
}

#pragma mark - Property

- (BOOL)linesExpanded {
	return self.layoutFrame == self.expandLayoutFrame;
}

- (void)setLinesExpanded:(BOOL)linesExpanded {
	if (linesExpanded) {
		self.layoutFrame = self.expandLayoutFrame;
	} else {
		self.layoutFrame = self.collapseLayoutFrame;
	}
}

- (BOOL)needsFolding {
	return CGRectGetHeight(self.expandLayoutFrame.frame) != CGRectGetHeight(self.collapseLayoutFrame.frame);
}

- (DTCoreTextLayoutFrame *)expandLayoutFrame {
	if (!self.attributedString || !self.layouter) {
		return nil;
	}
	DTCoreTextLayoutFrame *layoutFrame = [[DTAttributedFoldingLabel sharedExpandLayoutFrameCache] objectForKey:@(self.attributedString.hash)];
	if (!layoutFrame) {
		layoutFrame = [self.layouter layoutFrameWithRect:CGRectMake(0, 0, CGRectGetWidth(self.frame) + [CocoaUtils deltaRetinaDisplayScreenWidth], CGFLOAT_HEIGHT_UNKNOWN) range:NSMakeRange(0, 0)];
		if (layoutFrame) {
			[[DTAttributedFoldingLabel sharedExpandLayoutFrameCache] setObject:layoutFrame forKey:@(self.attributedString.hash)];
		}
	}
	return layoutFrame;
}

- (DTCoreTextLayoutFrame *)collapseLayoutFrame {
	if (!self.attributedString || !self.layouter) {
		return nil;
	}
	DTCoreTextLayoutFrame *layoutFrame = [[DTAttributedFoldingLabel sharedCollapseLayoutFrameCache] objectForKey:@(self.attributedString.hash)];
	if (!layoutFrame) {
		layoutFrame = [self.layouter layoutFrameWithRect:CGRectMake(0, 0, CGRectGetWidth(self.frame) + [CocoaUtils deltaRetinaDisplayScreenWidth], CGFLOAT_HEIGHT_UNKNOWN) range:NSMakeRange(0, 0)];
		layoutFrame.numberOfLines = self.collapseLines;
		if (layoutFrame) {
			[[DTAttributedFoldingLabel sharedCollapseLayoutFrameCache] setObject:layoutFrame forKey:@(self.attributedString.hash)];
		}
	}
	return layoutFrame;
}

#pragma mark - Private

+ (NSCache *)sharedLayoutorCache {
	static dispatch_once_t onceToken;
	static NSCache *cache;
	dispatch_once(&onceToken, ^{
		cache = [[NSCache alloc] init];
		cache.countLimit = 10;
	});
	return cache;
}

+ (NSCache *)sharedExpandLayoutFrameCache {
	static dispatch_once_t onceToken;
	static NSCache *cache;
	dispatch_once(&onceToken, ^{
		cache = [[NSCache alloc] init];
		cache.countLimit = 10;
	});
	return cache;
}

+ (NSCache *)sharedCollapseLayoutFrameCache {
	static dispatch_once_t onceToken;
	static NSCache *cache;
	dispatch_once(&onceToken, ^{
		cache = [[NSCache alloc] init];
		cache.countLimit = 10;
	});
	return cache;
}

@end

@interface TourSearchDetailRichFoldingCell ()

@property (nonatomic, strong) NSAttributedString *attributedString;
@property (nonatomic, weak) IBOutlet DTAttributedFoldingLabel *contentLabel;
@property (nonatomic, weak) IBOutlet UIButton *toggleButton;
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *toggleConstraint;
@property (nonatomic, copy) void (^toggleHandler) (BOOL folding);

- (IBAction)toggleFolding:(id)sender;

@end

static NSInteger const defaultFoldingNumberOfLines = 4;

@implementation TourSearchDetailRichFoldingCell

- (void)awakeFromNib {
	[super awakeFromNib];
	// Initialization code
	self.titleLabel.text = nil;
	self.subtitleLabel.text = nil;
	self.contentLabel.shouldDrawImages = NO;
	self.contentLabel.collapseLines = defaultFoldingNumberOfLines;

	[CocoaUtils fillSeparatorOfCell:self];
}

#pragma mark - Public

- (void)setHTMLString:(NSString *)html options:(NSDictionary *)options {
	self.contentLabel.attributedString = [[NSAttributedString alloc] initWithHTMLData:[html dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:NULL];
}

- (void)ready {
	[self bindFolding];
	[self triggerFolding];
}

#pragma mark - Action

- (IBAction)toggleFolding:(id)sender {
	if (self.toggleHandler) {
		self.toggleHandler(!self.folding);
	}
}

#pragma mark - Private

- (void)bindFolding {
	if (self.contentLabel.needsFolding) {
		self.toggleConstraint.constant = [UIConstants defaultButtonHeight];
		self.toggleButton.hidden = NO;
	} else {
		self.toggleConstraint.constant = self.additionalPaddingAtBottom;
		self.toggleButton.hidden = YES;
	}
}

- (void)triggerFolding {
	if (self.folding) {
		[self.toggleButton setAttributedTitle:[DrawUtils attributedStringWithFAKIcon:[FAKFontAwesome angleUpIconWithSize:32] fillColor:[Vars defaultTintColor]] forState:UIControlStateNormal];
	} else {
		[self.toggleButton setAttributedTitle:[DrawUtils attributedStringWithFAKIcon:[FAKFontAwesome angleDownIconWithSize:32] fillColor:[Vars defaultTintColor]] forState:UIControlStateNormal];
	}
	self.contentLabel.linesExpanded = self.folding;
	[self.contentLabel invalidateIntrinsicContentSize];
}

@end

