using System;

namespace System.Reactive.Linq.ObservableImpl
{
	internal static class Do<TSource>
	{
		internal sealed class OnNext : Producer<TSource, Do<TSource>.OnNext._>
		{
			public OnNext(IObservable<TSource> source, Action<TSource> onNext)
			{
				this._source = source;
				this._onNext = onNext;
			}

			protected override Do<TSource>.OnNext._ CreateSink(IObserver<TSource> observer)
			{
				return new Do<TSource>.OnNext._(this._onNext, observer);
			}

			protected override void Run(Do<TSource>.OnNext._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Action<TSource> _onNext;

			internal sealed class _ : IdentitySink<TSource>
			{
				public _(Action<TSource> onNext, IObserver<TSource> observer)
					: base(observer)
				{
					this._onNext = onNext;
				}

				public override void OnNext(TSource value)
				{
					try
					{
						this._onNext(value);
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					base.ForwardOnNext(value);
				}

				private readonly Action<TSource> _onNext;
			}
		}

		internal sealed class Observer : Producer<TSource, Do<TSource>.Observer._>
		{
			public Observer(IObservable<TSource> source, IObserver<TSource> observer)
			{
				this._source = source;
				this._observer = observer;
			}

			protected override Do<TSource>.Observer._ CreateSink(IObserver<TSource> observer)
			{
				return new Do<TSource>.Observer._(this._observer, observer);
			}

			protected override void Run(Do<TSource>.Observer._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly IObserver<TSource> _observer;

			internal sealed class _ : IdentitySink<TSource>
			{
				public _(IObserver<TSource> doObserver, IObserver<TSource> observer)
					: base(observer)
				{
					this._doObserver = doObserver;
				}

				public override void OnNext(TSource value)
				{
					try
					{
						this._doObserver.OnNext(value);
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					base.ForwardOnNext(value);
				}

				public override void OnError(Exception error)
				{
					try
					{
						this._doObserver.OnError(error);
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					base.ForwardOnError(error);
				}

				public override void OnCompleted()
				{
					try
					{
						this._doObserver.OnCompleted();
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					base.ForwardOnCompleted();
				}

				private readonly IObserver<TSource> _doObserver;
			}
		}

		internal sealed class Actions : Producer<TSource, Do<TSource>.Actions._>
		{
			public Actions(IObservable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
			{
				this._source = source;
				this._onNext = onNext;
				this._onError = onError;
				this._onCompleted = onCompleted;
			}

			protected override Do<TSource>.Actions._ CreateSink(IObserver<TSource> observer)
			{
				return new Do<TSource>.Actions._(this, observer);
			}

			protected override void Run(Do<TSource>.Actions._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly Action<TSource> _onNext;

			private readonly Action<Exception> _onError;

			private readonly Action _onCompleted;

			internal sealed class _ : IdentitySink<TSource>
			{
				public _(Do<TSource>.Actions parent, IObserver<TSource> observer)
					: base(observer)
				{
					this._parent = parent;
				}

				public override void OnNext(TSource value)
				{
					try
					{
						this._parent._onNext(value);
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					base.ForwardOnNext(value);
				}

				public override void OnError(Exception error)
				{
					try
					{
						this._parent._onError(error);
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					base.ForwardOnError(error);
				}

				public override void OnCompleted()
				{
					try
					{
						this._parent._onCompleted();
					}
					catch (Exception ex)
					{
						base.ForwardOnError(ex);
						return;
					}
					base.ForwardOnCompleted();
				}

				private readonly Do<TSource>.Actions _parent;
			}
		}
	}
}
