//
//  YSRACSignalSequence.m
//  ReactiveObjC
//
//  Created by Justin Spahr-Summers on 2012-11-09.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//

#import "YSRACSignalSequence.h"
#import "YSRACDisposable.h"
#import "YSRACReplaySubject.h"
#import "YSRACSignal+Operations.h"

@interface YSRACSignalSequence ()

// Replays the signal given on initialization.
@property (nonatomic, strong, readonly) YSRACReplaySubject *subject;

@end

@implementation YSRACSignalSequence

#pragma mark Lifecycle

+ (YSRACSequence *)sequenceWithSignal:(YSRACSignal *)signal {
	YSRACSignalSequence *seq = [[self alloc] init];

	YSRACReplaySubject *subject = [YSRACReplaySubject subject];
	[signal subscribeNext:^(id value) {
		[subject sendNext:value];
	} error:^(NSError *error) {
		[subject sendError:error];
	} completed:^{
		[subject sendCompleted];
	}];

	seq->_subject = subject;
	return seq;
}

#pragma mark YSRACSequence

- (id)head {
	id value = [self.subject firstOrDefault:self];

	if (value == self) {
		return nil;
	} else {
		return value ?: NSNull.null;
	}
}

- (YSRACSequence *)tail {
	YSRACSequence *sequence = [self.class sequenceWithSignal:[self.subject skip:1]];
	sequence.name = self.name;
	return sequence;
}

- (NSArray *)array {
	return self.subject.toArray;
}

#pragma mark NSObject

- (NSString *)description {
	// Synchronously accumulate the values that have been sent so far.
	NSMutableArray *values = [NSMutableArray array];
	YSRACDisposable *disposable = [self.subject subscribeNext:^(id value) {
		@synchronized (values) {
			[values addObject:value ?: NSNull.null];
		}
	}];

	[disposable dispose];

	return [NSString stringWithFormat:@"<%@: %p>{ name = %@, values = %@ … }", self.class, self, self.name, values];
}

@end
