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

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

@interface YSRACChannelTerminal<ValueType> ()

/// The values for this terminal.
@property (nonatomic, strong, readonly) YSRACSignal<ValueType> *values;

/// A subscriber will will send values to the other terminal.
@property (nonatomic, strong, readonly) id<YSRACSubscriber> otherTerminal;

- (instancetype)initWithValues:(YSRACSignal<ValueType> *)values otherTerminal:(id<YSRACSubscriber>)otherTerminal;

@end

@implementation YSRACChannel

- (instancetype)init {
	self = [super init];

	// We don't want any starting value from the leadingSubject, but we do want
	// error and completion to be replayed.
	YSRACReplaySubject *leadingSubject = [[YSRACReplaySubject replaySubjectWithCapacity:0] setNameWithFormat:@"leadingSubject"];
	YSRACReplaySubject *followingSubject = [[YSRACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"followingSubject"];

	// Propagate errors and completion to everything.
	[[leadingSubject ignoreValues] subscribe:followingSubject];
	[[followingSubject ignoreValues] subscribe:leadingSubject];

	_leadingTerminal = [[[YSRACChannelTerminal alloc] initWithValues:leadingSubject otherTerminal:followingSubject] setNameWithFormat:@"leadingTerminal"];
	_followingTerminal = [[[YSRACChannelTerminal alloc] initWithValues:followingSubject otherTerminal:leadingSubject] setNameWithFormat:@"followingTerminal"];

	return self;
}

@end

@implementation YSRACChannelTerminal

#pragma mark Lifecycle

- (instancetype)initWithValues:(YSRACSignal *)values otherTerminal:(id<YSRACSubscriber>)otherTerminal {
	NSCParameterAssert(values != nil);
	NSCParameterAssert(otherTerminal != nil);

	self = [super init];

	_values = values;
	_otherTerminal = otherTerminal;

	return self;
}

#pragma mark YSRACSignal

- (YSRACDisposable *)subscribe:(id<YSRACSubscriber>)subscriber {
	return [self.values subscribe:subscriber];
}

#pragma mark <YSRACSubscriber>

- (void)sendNext:(id)value {
	[self.otherTerminal sendNext:value];
}

- (void)sendError:(NSError *)error {
	[self.otherTerminal sendError:error];
}

- (void)sendCompleted {
	[self.otherTerminal sendCompleted];
}

- (void)didSubscribeWithDisposable:(YSRACCompoundDisposable *)disposable {
	[self.otherTerminal didSubscribeWithDisposable:disposable];
}

@end
