using System;
using System.Threading;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class ForEach<TSource>
	{
		public sealed class Observer : IObserver<TSource>
		{
			public Observer(Action<TSource> onNext, Action done)
			{
				this._onNext = onNext;
				this._done = done;
			}

			public Exception Error
			{
				get
				{
					return this._exception;
				}
			}

			public void OnNext(TSource value)
			{
				if (this._stopped == 0)
				{
					try
					{
						this._onNext(value);
					}
					catch (Exception ex)
					{
						this.OnError(ex);
					}
				}
			}

			public void OnError(Exception error)
			{
				if (Interlocked.Exchange(ref this._stopped, 1) == 0)
				{
					this._exception = error;
					this._done();
				}
			}

			public void OnCompleted()
			{
				if (Interlocked.Exchange(ref this._stopped, 1) == 0)
				{
					this._done();
				}
			}

			private readonly Action<TSource> _onNext;

			private readonly Action _done;

			private Exception _exception;

			private int _stopped;
		}

		public sealed class ObserverIndexed : IObserver<TSource>
		{
			public ObserverIndexed(Action<TSource, int> onNext, Action done)
			{
				this._onNext = onNext;
				this._done = done;
			}

			public Exception Error
			{
				get
				{
					return this._exception;
				}
			}

			public void OnNext(TSource value)
			{
				if (this._stopped == 0)
				{
					try
					{
						Action<TSource, int> onNext = this._onNext;
						int index = this._index;
						this._index = checked(index + 1);
						onNext(value, index);
					}
					catch (Exception ex)
					{
						this.OnError(ex);
					}
				}
			}

			public void OnError(Exception error)
			{
				if (Interlocked.Exchange(ref this._stopped, 1) == 0)
				{
					this._exception = error;
					this._done();
				}
			}

			public void OnCompleted()
			{
				if (Interlocked.Exchange(ref this._stopped, 1) == 0)
				{
					this._done();
				}
			}

			private readonly Action<TSource, int> _onNext;

			private readonly Action _done;

			private int _index;

			private Exception _exception;

			private int _stopped;
		}
	}
}
