// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
namespace System.Reactive
{
    /// 
    /// Represents an object that retains the elements of the observable sequence and signals the end of the sequence.
    ///  
    /// The type of elements received from the source sequence. 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "By design; Observable suffix takes precedence.")]
    [Experimental]
    public class ListObservable : IList, IObservable
    {
        IDisposable subscription;
        AsyncSubject subject = new AsyncSubject();
        List results = new List();
        /// 
        /// Constructs an object that retains the values of source and signals the end of the sequence.
        ///  
        ///  The observable sequence whose elements will be retained in the list.
        ///   is null. 
        public ListObservable(IObservable source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            subscription = source.Subscribe(results.Add, subject.OnError, subject.OnCompleted);
        }
        void Wait()
        {
            subject.DefaultIfEmpty().Wait();
        }
        /// 
        /// Returns the last value of the observable sequence.
        ///  
        public T Value
        {
            get
            {
                Wait();
                if (results.Count == 0)
                    throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS);
                return results[results.Count - 1];
            }
        }
        /// 
        /// Determines the index of a specific item in the ListObservable.
        ///  
        ///  The element to determine the index for.
        /// The index of the specified item in the list; -1 if not found. 
        public int IndexOf(T item)
        {
            Wait();
            return results.IndexOf(item);
        }
        /// 
        /// Inserts an item to the ListObservable at the specified index.
        ///  
        ///  The index to insert the item at.
        ///  The item to insert in the list.
        public void Insert(int index, T item)
        {
            Wait();
            results.Insert(index, item);
        }
        /// 
        /// Removes the ListObservable item at the specified index.
        ///  
        ///  The index of the item to remove.
        public void RemoveAt(int index)
        {
            Wait();
            results.RemoveAt(index);
        }
        /// 
        /// Gets or sets the element at the specified index.
        ///  
        ///  The index of the item to retrieve or set.
        public T this[int index]
        {
            get
            {
                Wait();
                return results[index];
            }
            set
            {
                Wait();
                results[index] = value;
            }
        }
        /// 
        /// Adds an item to the ListObservable.
        ///  
        ///  The item to add to the list.
        public void Add(T item)
        {
            Wait();
            results.Add(item);
        }
        /// 
        /// Removes all items from the ListObservable.
        ///  
        public void Clear()
        {
            Wait();
            results.Clear();
        }
        /// 
        /// Determines whether the ListObservable contains a specific value.
        ///  
        ///  The item to search for in the list.
        /// true if found; false otherwise. 
        public bool Contains(T item)
        {
            Wait();
            return results.Contains(item);
        }
        /// 
        /// Copies the elements of the ListObservable to an System.Array, starting at a particular System.Array index.
        ///  
        ///  The array to copy elements to.
        ///  The start index in the array to start copying elements to.
        public void CopyTo(T[] array, int arrayIndex)
        {
            Wait();
            results.CopyTo(array, arrayIndex);
        }
        /// 
        /// Gets the number of elements contained in the ListObservable.
        ///  
        public int Count
        {
            get
            {
                Wait();
                return results.Count;
            }
        }
        /// 
        /// Gets a value that indicates whether the ListObservable is read-only.
        ///  
        public bool IsReadOnly
        {
            get { return false; }
        }
        /// 
        /// Removes the first occurrence of a specific object from the ListObservable.
        ///  
        ///  The item to remove from the list.
        /// true if the item was found; false otherwise. 
        public bool Remove(T item)
        {
            Wait();
            return results.Remove(item);
        }
        /// 
        /// Returns an enumerator that iterates through the collection.
        ///  
        /// Enumerator over the list. 
        public IEnumerator GetEnumerator()
        {
            Wait();
            return results.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        /// 
        /// Subscribes an observer to the ListObservable which will be notified upon completion.
        ///  
        ///  The observer to send completion or error messages to.
        /// The disposable resource that can be used to unsubscribe. 
        ///   is null. 
        public IDisposable Subscribe(IObserver observer)
        {
            if (observer == null)
                throw new ArgumentNullException("observer");
            return StableCompositeDisposable.Create(subscription, subject.Subscribe(observer));
        }
    }
}