using System;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using System.Runtime.CompilerServices;

namespace System.Reactive.Linq.ObservableImpl
{
	internal abstract class EventProducer<T, TArgs> : BasicProducer<TArgs>
	{
		protected EventProducer(IScheduler scheduler)
		{
			this._scheduler = scheduler;
			this._gate = new object();
		}

		protected abstract T GetHandler(Action<TArgs> onNext);

		protected abstract IDisposable AddHandler(T handler);

		protected override IDisposable Run(IObserver<TArgs> observer)
		{
			IDisposable disposable = null;
			object gate = this._gate;
			lock (gate)
			{
				if (this._session == null)
				{
					this._session = new EventProducer<T, TArgs>.Session(this);
				}
				disposable = this._session.Connect(observer);
			}
			return disposable;
		}

		private readonly IScheduler _scheduler;

		private readonly object _gate;

		private EventProducer<T, TArgs>.Session _session;

		private sealed class Session
		{
			public Session(EventProducer<T, TArgs> parent)
			{
				this._parent = parent;
				this._subject = new Subject<TArgs>();
			}

			public IDisposable Connect(IObserver<TArgs> observer)
			{
				IDisposable disposable = this._subject.Subscribe(observer);
				int num = this._count + 1;
				this._count = num;
				if (num == 1)
				{
					IDisposable empty;
					try
					{
						this.Initialize();
						goto IL_004F;
					}
					catch (Exception ex)
					{
						this._count--;
						disposable.Dispose();
						observer.OnError(ex);
						empty = Disposable.Empty;
					}
					return empty;
				}
				IL_004F:
				return Disposable.Create<ValueTuple<EventProducer<T, TArgs>.Session, EventProducer<T, TArgs>, IDisposable>>(new ValueTuple<EventProducer<T, TArgs>.Session, EventProducer<T, TArgs>, IDisposable>(this, this._parent, disposable), delegate([TupleElementNames(new string[] { null, "_parent", "connection" })] ValueTuple<EventProducer<T, TArgs>.Session, EventProducer<T, TArgs>, IDisposable> tuple)
				{
					EventProducer<T, TArgs>.Session item = tuple.Item1;
					EventProducer<T, TArgs> item2 = tuple.Item2;
					tuple.Item3.Dispose();
					object gate = item2._gate;
					lock (gate)
					{
						EventProducer<T, TArgs>.Session session = item;
						int num2 = session._count - 1;
						session._count = num2;
						if (num2 == 0)
						{
							item2._scheduler.ScheduleAction(item._removeHandler, delegate(SingleAssignmentDisposable handler)
							{
								handler.Dispose();
							});
							item2._session = null;
						}
					}
				});
			}

			private void Initialize()
			{
				this._removeHandler = new SingleAssignmentDisposable();
				T handler = this._parent.GetHandler(new Action<TArgs>(this._subject.OnNext));
				this._parent._scheduler.ScheduleAction(handler, new Action<T>(this.AddHandler));
			}

			private void AddHandler(T onNext)
			{
				IDisposable disposable;
				try
				{
					disposable = this._parent.AddHandler(onNext);
				}
				catch (Exception ex)
				{
					this._subject.OnError(ex);
					return;
				}
				this._removeHandler.Disposable = disposable;
			}

			private readonly EventProducer<T, TArgs> _parent;

			private readonly Subject<TArgs> _subject;

			private SingleAssignmentDisposable _removeHandler;

			private int _count;
		}
	}
}
