//
//  TextFieldDelegate.m
//

#import "TextFieldDelegate.h"

static NSMutableDictionary * _contentInsetBottomBeforeForView;
static CGSize _keyboardSize;
static BOOL _isAnimatingContentInset;
static UIEdgeInsets _isAnimatingToContentInset;


@implementation TextFieldDelegate {
	BOOL _isEditingTextField;
	//CGSize _keyboardSize;
}

- (void)awakeFromNib {
	[super awakeFromNib];
	_keyboardSize = CGSizeMake(0, 0);
	if (!_contentInsetBottomBeforeForView) _contentInsetBottomBeforeForView = @{}.mutableCopy;
}

- (void)registerForNotifications {
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(keyboardWillShow:)
												 name:UIKeyboardWillShowNotification
											   object:nil];
	[[NSNotificationCenter defaultCenter] addObserver:self
											 selector:@selector(keyboardWillHide:)
												 name:UIKeyboardWillHideNotification
											   object:nil];
}

- (void)unregisterForNotifications {
	[[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)dealloc {
	[self unregisterForNotifications];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
	[textField resignFirstResponder];
	return NO;
}

- (void)notifyObserversForChange {
	[self notifyObserversForKeyPath:@"contents.text"];
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
		[self notifyObserversForChange];
	});
	return YES;
}

- (BOOL)textFieldShouldClear:(UITextField *)textField {
	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
		[self notifyObserversForChange];
	});
	return YES;
}

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
	[self registerForNotifications];
	return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
	[self unregisterForNotifications];
}

- (id)valueForKeyPath:(NSString *)keyPath {
	if ([keyPath isEqualToString:@"contents.text"]) {
		return _control.text;
	}
	return [super valueForKeyPath:keyPath];
}

- (void)setValue:(id)value forKeyPath:(NSString *)keyPath {
	if ([keyPath isEqualToString:@"contents.text"]) {
		_control.text = value;
	}
	return [super setValue:value forKeyPath:keyPath];
}

- (UIScrollView *)rootScrollViewForInsetUpdates {
	if (![_viewController.view isKindOfClass:[UIScrollView class]]) return nil;
	if ([_viewController isKindOfClass:[UITableViewController class]]) return nil;
	return ((UIScrollView *)_viewController.view);
}

- (NSArray *)scrollViewsForInsetUpdates {
	if ([_viewController isKindOfClass:[UITableViewController class]]) return @[];

	UIScrollView * rootScrollView = self.rootScrollViewForInsetUpdates;
	if (rootScrollView) return @[ rootScrollView ];
	
	NSMutableArray * result = @[].mutableCopy;
	for (UIView * subview in _viewController.view.subviews) {
		if ([subview isKindOfClass:[UIScrollView class]]) {
			[result addObject:subview];
		}
	}
	
	return result;
}

- (void)updateViewsForKeyboardVisible:(BOOL)visible {

	NSArray * scrollViews = self.scrollViewsForInsetUpdates;
	
	for (UIScrollView * scrollView in scrollViews) {

		UIEdgeInsets contentInset = scrollView.contentInset;
		if (_isAnimatingContentInset) {
			contentInset = _isAnimatingToContentInset;
		}
		
		if (visible) {
			CGFloat viewDistanceFromWindowBottom = [self viewDistanceFromWindowBottom:scrollView];
			
			if (_contentInsetBottomBeforeForView[[NSNumber numberWithInteger:scrollView.tag]] == nil) {
				_contentInsetBottomBeforeForView[[NSNumber numberWithInteger:scrollView.tag]] = [NSNumber numberWithFloat:contentInset.bottom];
			}
			
			contentInset.bottom = contentInset.bottom + (_keyboardSize.height-viewDistanceFromWindowBottom);
			scrollView.contentInset = contentInset;
			
			_isAnimatingContentInset = NO;
		}
		else {
			contentInset.bottom = [_contentInsetBottomBeforeForView[[NSNumber numberWithInteger:scrollView.tag]] floatValue];
			_isAnimatingContentInset = YES;
			_isAnimatingToContentInset = contentInset;
			
			dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
				dispatch_async(dispatch_get_main_queue(), ^{
					[UIView animateWithDuration:0.25 delay:0 options:0 animations:^{
						if (!_isAnimatingContentInset) return;
						scrollView.contentInset = _isAnimatingToContentInset;
					} completion:^(BOOL finished) {
						_isAnimatingContentInset = NO;
					}];
				});
			});
		}
		
	}

}

- (CGFloat)viewDistanceFromWindowBottom:(UIView *)rootView {
	CGRect f = [rootView convertRect:rootView.bounds toView:rootView.window];
	CGFloat rootViewAbsoluteBottom = f.origin.y + f.size.height;
	// this is the height of the tab bar, if visible
	CGFloat rootViewDistanceFromWindowBottom = rootView.window.frame.size.height - rootViewAbsoluteBottom;
	return rootViewDistanceFromWindowBottom;
}

- (void)keyboardWillShow:(NSNotification *)notification
{
	if (_keyboardSize.height) {
		[self keyboardWillHide:notification];
	}
	_keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
	[self updateViewsForKeyboardVisible:YES];
}

- (void)keyboardWillHide:(NSNotification *)notification
{
	[self updateViewsForKeyboardVisible:NO];
	_keyboardSize = CGSizeMake(0, 0);
}

@end


@implementation UITextField (DataProvider)

- (void)setDataProvider:(TextFieldDelegate *)dataProvider {
	self.delegate = dataProvider;
}

- (TextFieldDelegate *)dataProvider {
	return (TextFieldDelegate *)self.delegate;
}

@end
