using System;
using System.Reactive.Linq;

namespace System.Reactive.Subjects
{
	internal class ConnectableObservable<TSource, TResult> : IConnectableObservable<TResult>, IObservable<TResult>
	{
		public ConnectableObservable(IObservable<TSource> source, ISubject<TSource, TResult> subject)
		{
			this._subject = subject;
			this._source = source.AsObservable<TSource>();
			this._gate = new object();
		}

		public IDisposable Connect()
		{
			object gate = this._gate;
			IDisposable connection;
			lock (gate)
			{
				if (this._connection == null)
				{
					IDisposable disposable = this._source.SubscribeSafe(this._subject);
					this._connection = new ConnectableObservable<TSource, TResult>.Connection(this, disposable);
				}
				connection = this._connection;
			}
			return connection;
		}

		public IDisposable Subscribe(IObserver<TResult> observer)
		{
			if (observer == null)
			{
				throw new ArgumentNullException("observer");
			}
			return this._subject.SubscribeSafe(observer);
		}

		private readonly ISubject<TSource, TResult> _subject;

		private readonly IObservable<TSource> _source;

		private readonly object _gate;

		private ConnectableObservable<TSource, TResult>.Connection _connection;

		private sealed class Connection : IDisposable
		{
			public Connection(ConnectableObservable<TSource, TResult> parent, IDisposable subscription)
			{
				this._parent = parent;
				this._subscription = subscription;
			}

			public void Dispose()
			{
				object gate = this._parent._gate;
				lock (gate)
				{
					if (this._subscription != null)
					{
						this._subscription.Dispose();
						this._subscription = null;
						this._parent._connection = null;
					}
				}
			}

			private readonly ConnectableObservable<TSource, TResult> _parent;

			private IDisposable _subscription;
		}
	}
}
