//
//  UIRefreshControl+RACSupport.m
//  ReactiveCocoa
//
//  Created by Dave Lee on 2013-10-17.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//

#import "UIRefreshControl+RACSupport.h"
#import "EXTKeyPathCoding.h"
#import "NSObject+RACSelectorSignal.h"
#import "RACAction.h"
#import "RACDisposable.h"
#import "RACCommand.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "RACSignal+Operations.h"
#import "UIControl+RACSupport.h"
#import <objc/runtime.h>

static void *UIRefreshControlActionKey = &UIRefreshControlActionKey;
static void *UIRefreshControlActionDisposableKey = &UIRefreshControlActionDisposableKey;

@implementation UIRefreshControl (RACSupport)

- (RACAction *)rac_action {
	return objc_getAssociatedObject(self, UIRefreshControlActionKey);
}

- (void)setRac_action:(RACAction *)action {
	RACAction *previousAction = self.rac_action;
	if (action == previousAction) return;

	objc_setAssociatedObject(self, UIRefreshControlActionKey, action, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
	[objc_getAssociatedObject(self, UIRefreshControlActionDisposableKey) dispose];

	if (action == nil) return;

	RACDisposable *enabledDisposable = [action.enabled setKeyPath:@keypath(self.enabled) onObject:self];
	RACDisposable *actionDisposable = [[[[[self
		rac_signalForControlEvents:UIControlEventValueChanged]
		doDisposed:^{
			[enabledDisposable dispose];
		}]
		map:^(UIRefreshControl *control) {
			return [[[[action
				signalWithValue:control]
				catchTo:[RACSignal empty]]
				ignoreValues]
				concat:[RACSignal return:control]];
		}]
		concat]
		subscribeNext:^(UIRefreshControl *control) {
			[control endRefreshing];
		}];

	objc_setAssociatedObject(self, UIRefreshControlActionDisposableKey, actionDisposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#pragma clang diagnostic ignored "-Wdeprecated-implementations"

static void *UIRefreshControlRACCommandKey = &UIRefreshControlRACCommandKey;
static void *UIRefreshControlDisposableKey = &UIRefreshControlDisposableKey;

@implementation UIRefreshControl (RACSupportDeprecated)

- (RACCommand *)rac_command {
	return objc_getAssociatedObject(self, UIRefreshControlRACCommandKey);
}

- (void)setRac_command:(RACCommand *)command {
	objc_setAssociatedObject(self, UIRefreshControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

	// Dispose of any active command associations.
	[objc_getAssociatedObject(self, UIRefreshControlDisposableKey) dispose];

	if (command == nil) return;

	// Like RAC(self, enabled) = command.enabled; but with access to disposable.
	RACDisposable *enabledDisposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self];

	RACDisposable *executionDisposable = [[[[self
		rac_signalForControlEvents:UIControlEventValueChanged]
		map:^(UIRefreshControl *x) {
			return [[[command
				execute:x]
				catchTo:[RACSignal empty]]
				then:^{
					return [RACSignal return:x];
				}];
		}]
		concat]
		subscribeNext:^(UIRefreshControl *x) {
			[x endRefreshing];
		}];

	RACDisposable *commandDisposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ enabledDisposable, executionDisposable ]];
	objc_setAssociatedObject(self, UIRefreshControlDisposableKey, commandDisposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

#pragma clang diagnostic pop
