using System;
using System.Collections.Generic;
using System.Threading;

namespace System.Reactive.Disposables
{
	public abstract class StableCompositeDisposable : ICancelable, IDisposable
	{
		public static ICancelable Create(IDisposable disposable1, IDisposable disposable2)
		{
			if (disposable1 == null)
			{
				throw new ArgumentNullException("disposable1");
			}
			if (disposable2 == null)
			{
				throw new ArgumentNullException("disposable2");
			}
			return new StableCompositeDisposable.Binary(disposable1, disposable2);
		}

		public static ICancelable Create(params IDisposable[] disposables)
		{
			if (disposables == null)
			{
				throw new ArgumentNullException("disposables");
			}
			return new StableCompositeDisposable.NAryArray(disposables);
		}

		internal static ICancelable CreateTrusted(params IDisposable[] disposables)
		{
			return new StableCompositeDisposable.NAryTrustedArray(disposables);
		}

		public static ICancelable Create(IEnumerable<IDisposable> disposables)
		{
			if (disposables == null)
			{
				throw new ArgumentNullException("disposables");
			}
			return new StableCompositeDisposable.NAryEnumerable(disposables);
		}

		public abstract void Dispose();

		public abstract bool IsDisposed { get; }

		private sealed class Binary : StableCompositeDisposable
		{
			public Binary(IDisposable disposable1, IDisposable disposable2)
			{
				Volatile.Write<IDisposable>(ref this._disposable1, disposable1);
				Volatile.Write<IDisposable>(ref this._disposable2, disposable2);
			}

			public override bool IsDisposed
			{
				get
				{
					return Disposable.GetIsDisposed(ref this._disposable1);
				}
			}

			public override void Dispose()
			{
				Disposable.TryDispose(ref this._disposable1);
				Disposable.TryDispose(ref this._disposable2);
			}

			private object _disposable1;

			private object _disposable2;
		}

		private sealed class NAryEnumerable : StableCompositeDisposable
		{
			public NAryEnumerable(IEnumerable<IDisposable> disposables)
			{
				this._disposables = new List<IDisposable>(disposables);
				if (this._disposables.Contains(null))
				{
					throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables");
				}
			}

			public override bool IsDisposed
			{
				get
				{
					return this._disposables == null;
				}
			}

			public override void Dispose()
			{
				List<IDisposable> list = Interlocked.Exchange<List<IDisposable>>(ref this._disposables, null);
				if (list != null)
				{
					foreach (IDisposable disposable in list)
					{
						disposable.Dispose();
					}
				}
			}

			private object _disposables;
		}

		private sealed class NAryArray : StableCompositeDisposable
		{
			public NAryArray(IDisposable[] disposables)
			{
				int num = disposables.Length;
				IDisposable[] array = new IDisposable[num];
				Array.Copy(disposables, 0, array, 0, num);
				if (Array.IndexOf<IDisposable>(array, null) != -1)
				{
					throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables");
				}
				Volatile.Write<IDisposable[]>(ref this._disposables, array);
			}

			public override bool IsDisposed
			{
				get
				{
					return Volatile.Read<IDisposable[]>(ref this._disposables) == null;
				}
			}

			public override void Dispose()
			{
				IDisposable[] array = Interlocked.Exchange<IDisposable[]>(ref this._disposables, null);
				if (array != null)
				{
					IDisposable[] array2 = array;
					for (int i = 0; i < array2.Length; i++)
					{
						array2[i].Dispose();
					}
				}
			}

			private object _disposables;
		}

		private sealed class NAryTrustedArray : StableCompositeDisposable
		{
			public NAryTrustedArray(IDisposable[] disposables)
			{
				Volatile.Write<IDisposable[]>(ref this._disposables, disposables);
			}

			public override bool IsDisposed
			{
				get
				{
					return Volatile.Read<IDisposable[]>(ref this._disposables) == null;
				}
			}

			public override void Dispose()
			{
				IDisposable[] array = Interlocked.Exchange<IDisposable[]>(ref this._disposables, null);
				if (array != null)
				{
					IDisposable[] array2 = array;
					for (int i = 0; i < array2.Length; i++)
					{
						array2[i].Dispose();
					}
				}
			}

			private object _disposables;
		}
	}
}
