using System;
using System.Collections;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;

namespace System.Reactive
{
	[Experimental]
	public class ListObservable<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IObservable<object>
	{
		public ListObservable(IObservable<T> source)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			this._subscription = source.Subscribe(new Action<T>(this._results.Add), new Action<Exception>(this._subject.OnError), new Action(this._subject.OnCompleted));
		}

		private void Wait()
		{
			this._subject.DefaultIfEmpty<object>().Wait<object>();
		}

		public T Value
		{
			get
			{
				this.Wait();
				if (this._results.Count == 0)
				{
					throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS);
				}
				return this._results[this._results.Count - 1];
			}
		}

		public int IndexOf(T item)
		{
			this.Wait();
			return this._results.IndexOf(item);
		}

		public void Insert(int index, T item)
		{
			this.Wait();
			this._results.Insert(index, item);
		}

		public void RemoveAt(int index)
		{
			this.Wait();
			this._results.RemoveAt(index);
		}

		public T this[int index]
		{
			get
			{
				this.Wait();
				return this._results[index];
			}
			set
			{
				this.Wait();
				this._results[index] = value;
			}
		}

		public void Add(T item)
		{
			this.Wait();
			this._results.Add(item);
		}

		public void Clear()
		{
			this.Wait();
			this._results.Clear();
		}

		public bool Contains(T item)
		{
			this.Wait();
			return this._results.Contains(item);
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			this.Wait();
			this._results.CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get
			{
				this.Wait();
				return this._results.Count;
			}
		}

		public bool IsReadOnly
		{
			get
			{
				return false;
			}
		}

		public bool Remove(T item)
		{
			this.Wait();
			return this._results.Remove(item);
		}

		public IEnumerator<T> GetEnumerator()
		{
			this.Wait();
			return this._results.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		public IDisposable Subscribe(IObserver<object> observer)
		{
			if (observer == null)
			{
				throw new ArgumentNullException("observer");
			}
			return StableCompositeDisposable.Create(this._subscription, this._subject.Subscribe(observer));
		}

		private readonly IDisposable _subscription;

		private readonly AsyncSubject<object> _subject = new AsyncSubject<object>();

		private readonly List<T> _results = new List<T>();
	}
}
