//
//  YSRACEagerSequence.m
//  ReactiveObjC
//
//  Created by Uri Baghin on 02/01/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//

#import "YSRACEagerSequence.h"
#import "NSObject+YSRACDescription.h"
#import "YSRACArraySequence.h"

@implementation YSRACEagerSequence

#pragma mark YSRACStream

+ (YSRACSequence *)return:(id)value {
	return [[self sequenceWithArray:@[ value ] offset:0] setNameWithFormat:@"+return: %@", YSRACDescription(value)];
}

- (YSRACSequence *)bind:(YSRACSequenceBindBlock (^)(void))block {
	NSCParameterAssert(block != nil);
	YSRACStreamBindBlock bindBlock = block();
	NSArray *currentArray = self.array;
	NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:currentArray.count];
	
	for (id value in currentArray) {
		BOOL stop = NO;
		YSRACSequence *boundValue = (id)bindBlock(value, &stop);
		if (boundValue == nil) break;

		for (id x in boundValue) {
			[resultArray addObject:x];
		}

		if (stop) break;
	}
	
	return [[self.class sequenceWithArray:resultArray offset:0] setNameWithFormat:@"[%@] -bind:", self.name];
}

- (YSRACSequence *)concat:(YSRACSequence *)sequence {
	NSCParameterAssert(sequence != nil);
	NSCParameterAssert([sequence isKindOfClass:YSRACSequence.class]);

	NSArray *array = [self.array arrayByAddingObjectsFromArray:sequence.array];
	return [[self.class sequenceWithArray:array offset:0] setNameWithFormat:@"[%@] -concat: %@", self.name, sequence];
}

#pragma mark Extended methods

- (YSRACSequence *)eagerSequence {
	return self;
}

- (YSRACSequence *)lazySequence {
	return [YSRACArraySequence sequenceWithArray:self.array offset:0];
}

- (id)foldRightWithStart:(id)start reduce:(id (^)(id, YSRACSequence *rest))reduce {
	return [super foldRightWithStart:start reduce:^(id first, YSRACSequence *rest) {
		return reduce(first, rest.eagerSequence);
	}];
}

@end
