//
//  UIControlRACSupportSpec.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-06-15.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//

#import "RACTestUIButton.h"

#import "EXTKeyPathCoding.h"
#import "NSObject+RACDeallocating.h"
#import "RACChannelExamples.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "UIControl+RACSupport.h"
#import "UISlider+RACSupport.h"

SpecBegin(UIControlRACSupport)

void (^setViewValueBlock)(UISlider *, NSNumber *) = ^(UISlider *view, NSNumber *value) {
	view.value = value.floatValue;

	// UIControlEvents don't trigger from programmatic modification. Do it
	// manually.
	for (id target in view.allTargets) {
		// Control events are a mask, but UIControlEventAllEvents doesn't seem to
		// match anything, 0 does.
		for (NSString *selectorString in [view actionsForTarget:target forControlEvent:0]) {
			SEL selector = NSSelectorFromString(selectorString);

			NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
			invocation.selector = selector;
			UIEvent *event = nil;
			[invocation setArgument:&event atIndex:2];

			[invocation invokeWithTarget:target];
		}
	}
};

itShouldBehaveLike(RACViewChannelExamples, ^{
	return @{
		RACViewChannelExampleCreateViewBlock: ^{
			return [[UISlider alloc] init];
		},
		RACViewChannelExampleCreateTerminalBlock: ^(UISlider *view) {
			return [view rac_newValueChannelWithNilValue:@0.0];
		},
		RACViewChannelExampleKeyPath: @keypath(UISlider.new, value),
		RACViewChannelExampleSetViewValueBlock: setViewValueBlock
	};
});

it(@"should send on the returned signal when matching actions are sent", ^{
	UIControl *control = [RACTestUIButton button];
	expect(control).notTo.beNil();

	__block NSUInteger receivedCount = 0;
	[[control
		rac_signalForControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside]
		subscribeNext:^(UIControl *value) {
			expect(value).to.beIdenticalTo(control);
			receivedCount++;
		}];

	expect(receivedCount).to.equal(0);
	
	[control sendActionsForControlEvents:UIControlEventTouchUpInside];
	expect(receivedCount).to.equal(1);

	// Should do nothing.
	[control sendActionsForControlEvents:UIControlEventTouchDown];
	expect(receivedCount).to.equal(1);
	
	[control sendActionsForControlEvents:UIControlEventTouchUpOutside];
	expect(receivedCount).to.equal(2);
});

it(@"should send completed when the control is deallocated", ^{
	__block BOOL completed = NO;
	__block BOOL deallocated = NO;

	@autoreleasepool {
		UIControl *control __attribute__((objc_precise_lifetime)) = [RACTestUIButton button];
		[control.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
			deallocated = YES;
		}]];

		[[control
			rac_signalForControlEvents:UIControlEventTouchDown]
			subscribeCompleted:^{
				completed = YES;
			}];

		expect(deallocated).to.beFalsy();
		expect(completed).to.beFalsy();
	}

	expect(deallocated).to.beTruthy();
	expect(completed).to.beTruthy();
});

SpecEnd
