using System;
using System.Collections.Generic;

namespace System.Reactive
{
	internal sealed class EventSource<T> : IEventSource<T>
	{
		public EventSource(IObservable<T> source, Action<Action<T>, T> invokeHandler)
		{
			this._source = source;
			this._invokeHandler = invokeHandler;
			this._subscriptions = new Dictionary<Delegate, Stack<IDisposable>>();
		}

		public event Action<T> OnNext
		{
			add
			{
				object gate = new object();
				bool isAdded = false;
				bool isDone = false;
				Action remove = delegate
				{
					object gate2 = gate;
					lock (gate2)
					{
						if (isAdded)
						{
							this.Remove(value);
						}
						else
						{
							isDone = true;
						}
					}
				};
				IDisposable disposable = this._source.Subscribe(delegate(T x)
				{
					this._invokeHandler(value, x);
				}, delegate(Exception ex)
				{
					remove();
					ex.Throw();
				}, remove);
				object gate3 = gate;
				lock (gate3)
				{
					if (!isDone)
					{
						this.Add(value, disposable);
						isAdded = true;
					}
				}
			}
			remove
			{
				this.Remove(value);
			}
		}

		private void Add(Delegate handler, IDisposable disposable)
		{
			Dictionary<Delegate, Stack<IDisposable>> subscriptions = this._subscriptions;
			lock (subscriptions)
			{
				Stack<IDisposable> stack;
				if (!this._subscriptions.TryGetValue(handler, out stack))
				{
					stack = (this._subscriptions[handler] = new Stack<IDisposable>());
				}
				stack.Push(disposable);
			}
		}

		private void Remove(Delegate handler)
		{
			IDisposable disposable = null;
			Dictionary<Delegate, Stack<IDisposable>> subscriptions = this._subscriptions;
			lock (subscriptions)
			{
				Stack<IDisposable> stack = new Stack<IDisposable>();
				if (this._subscriptions.TryGetValue(handler, out stack))
				{
					disposable = stack.Pop();
					if (stack.Count == 0)
					{
						this._subscriptions.Remove(handler);
					}
				}
			}
			if (disposable != null)
			{
				disposable.Dispose();
			}
		}

		private readonly IObservable<T> _source;

		private readonly Dictionary<Delegate, Stack<IDisposable>> _subscriptions;

		private readonly Action<Action<T>, T> _invokeHandler;
	}
}
