// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Reactive.Concurrency;
using System.Threading;
#if !NO_TPL
using System.Threading.Tasks;
#endif
namespace System.Reactive.Linq
{
    public static partial class Observable
    {
        #region - Create -
        /// 
        /// Creates an observable sequence from a specified Subscribe method implementation.
        /// 
        /// The type of the elements in the produced sequence.
        /// Implementation of the resulting observable sequence's Subscribe method.
        /// The observable sequence with the specified implementation for the Subscribe method.
        ///  is null.
        /// 
        /// Use of this operator is preferred over manual implementation of the IObservable<T> interface. In case
        /// you need a type implementing IObservable<T> rather than an anonymous implementation, consider using
        /// the  abstract base class.
        /// 
        public static IObservable Create(Func, IDisposable> subscribe)
        {
            if (subscribe == null)
                throw new ArgumentNullException("subscribe");
            return s_impl.Create(subscribe);
        }
        /// 
        /// Creates an observable sequence from a specified Subscribe method implementation.
        /// 
        /// The type of the elements in the produced sequence.
        /// Implementation of the resulting observable sequence's Subscribe method, returning an Action delegate that will be wrapped in an IDisposable.
        /// The observable sequence with the specified implementation for the Subscribe method.
        ///  is null.
        /// 
        /// Use of this operator is preferred over manual implementation of the IObservable<T> interface. In case
        /// you need a type implementing IObservable<T> rather than an anonymous implementation, consider using
        /// the  abstract base class.
        /// 
        public static IObservable Create(Func, Action> subscribe)
        {
            if (subscribe == null)
                throw new ArgumentNullException("subscribe");
            return s_impl.Create(subscribe);
        }
        #endregion
        #region - CreateAsync -
#if !NO_TPL
        /// 
        /// Creates an observable sequence from a specified cancellable asynchronous Subscribe method.
        /// The CancellationToken passed to the asynchronous Subscribe method is tied to the returned disposable subscription, allowing best-effort cancellation.
        /// 
        /// The type of the elements in the produced sequence.
        /// Asynchronous method used to produce elements.
        /// The observable sequence surfacing the elements produced by the asynchronous method.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        /// When a subscription to the resulting sequence is disposed, the CancellationToken that was fed to the asynchronous subscribe function will be signaled.
        public static IObservable Create(Func, CancellationToken, Task> subscribeAsync)
        {
            if (subscribeAsync == null)
                throw new ArgumentNullException("subscribeAsync");
            return s_impl.Create(subscribeAsync);
        }
        /// 
        /// Creates an observable sequence from a specified asynchronous Subscribe method.
        /// 
        /// The type of the elements in the produced sequence.
        /// Asynchronous method used to produce elements.
        /// The observable sequence surfacing the elements produced by the asynchronous method.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        public static IObservable Create(Func, Task> subscribeAsync)
        {
            if (subscribeAsync == null)
                throw new ArgumentNullException("subscribeAsync");
            return s_impl.Create(subscribeAsync);
        }
        /// 
        /// Creates an observable sequence from a specified cancellable asynchronous Subscribe method.
        /// The CancellationToken passed to the asynchronous Subscribe method is tied to the returned disposable subscription, allowing best-effort cancellation.
        /// 
        /// The type of the elements in the produced sequence.
        /// Asynchronous method used to implemented the resulting sequence's Subscribe method.
        /// The observable sequence with the specified implementation for the Subscribe method.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        /// When a subscription to the resulting sequence is disposed, the CancellationToken that was fed to the asynchronous subscribe function will be signaled.
        public static IObservable Create(Func, CancellationToken, Task> subscribeAsync)
        {
            if (subscribeAsync == null)
                throw new ArgumentNullException("subscribeAsync");
            return s_impl.Create(subscribeAsync);
        }
        /// 
        /// Creates an observable sequence from a specified asynchronous Subscribe method.
        /// 
        /// The type of the elements in the produced sequence.
        /// Asynchronous method used to implemented the resulting sequence's Subscribe method.
        /// The observable sequence with the specified implementation for the Subscribe method.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        public static IObservable Create(Func, Task> subscribeAsync)
        {
            if (subscribeAsync == null)
                throw new ArgumentNullException("subscribeAsync");
            return s_impl.Create(subscribeAsync);
        }
        /// 
        /// Creates an observable sequence from a specified cancellable asynchronous Subscribe method.
        /// The CancellationToken passed to the asynchronous Subscribe method is tied to the returned disposable subscription, allowing best-effort cancellation.
        /// 
        /// The type of the elements in the produced sequence.
        /// Asynchronous method used to implemented the resulting sequence's Subscribe method, returning an Action delegate that will be wrapped in an IDisposable.
        /// The observable sequence with the specified implementation for the Subscribe method.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        /// When a subscription to the resulting sequence is disposed, the CancellationToken that was fed to the asynchronous subscribe function will be signaled.
        public static IObservable Create(Func, CancellationToken, Task> subscribeAsync)
        {
            if (subscribeAsync == null)
                throw new ArgumentNullException("subscribeAsync");
            return s_impl.Create(subscribeAsync);
        }
        /// 
        /// Creates an observable sequence from a specified asynchronous Subscribe method.
        /// 
        /// The type of the elements in the produced sequence.
        /// Asynchronous method used to implemented the resulting sequence's Subscribe method, returning an Action delegate that will be wrapped in an IDisposable.
        /// The observable sequence with the specified implementation for the Subscribe method.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        public static IObservable Create(Func, Task> subscribeAsync)
        {
            if (subscribeAsync == null)
                throw new ArgumentNullException("subscribeAsync");
            return s_impl.Create(subscribeAsync);
        }
#endif
        #endregion
        #region + Defer +
        /// 
        /// Returns an observable sequence that invokes the specified factory function whenever a new observer subscribes.
        /// 
        /// The type of the elements in the sequence returned by the factory function, and in the resulting sequence.
        /// Observable factory function to invoke for each observer that subscribes to the resulting sequence.
        /// An observable sequence whose observers trigger an invocation of the given observable factory function.
        ///  is null.
        public static IObservable Defer(Func> observableFactory)
        {
            if (observableFactory == null)
                throw new ArgumentNullException("observableFactory");
            return s_impl.Defer(observableFactory);
        }
        #endregion
        #region + DeferAsync +
#if !NO_TPL
        /// 
        /// Returns an observable sequence that starts the specified asynchronous factory function whenever a new observer subscribes.
        /// 
        /// The type of the elements in the sequence returned by the factory function, and in the resulting sequence.
        /// Asynchronous factory function to start for each observer that subscribes to the resulting sequence.
        /// An observable sequence whose observers trigger the given asynchronous observable factory function to be started.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        public static IObservable Defer(Func>> observableFactoryAsync)
        {
            if (observableFactoryAsync == null)
                throw new ArgumentNullException("observableFactoryAsync");
            return s_impl.Defer(observableFactoryAsync);
        }
        /// 
        /// Returns an observable sequence that starts the specified cancellable asynchronous factory function whenever a new observer subscribes.
        /// The CancellationToken passed to the asynchronous factory function is tied to the returned disposable subscription, allowing best-effort cancellation.
        /// 
        /// The type of the elements in the sequence returned by the factory function, and in the resulting sequence.
        /// Asynchronous factory function to start for each observer that subscribes to the resulting sequence.
        /// An observable sequence whose observers trigger the given asynchronous observable factory function to be started.
        ///  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        /// When a subscription to the resulting sequence is disposed, the CancellationToken that was fed to the asynchronous observable factory function will be signaled.
        public static IObservable DeferAsync(Func>> observableFactoryAsync)
        {
            if (observableFactoryAsync == null)
                throw new ArgumentNullException("observableFactoryAsync");
            return s_impl.Defer(observableFactoryAsync);
        }
#endif
        #endregion
        #region + Empty +
        /// 
        /// Returns an empty observable sequence.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// An observable sequence with no elements.
        public static IObservable Empty()
        {
            return s_impl.Empty();
        }
        /// 
        /// Returns an empty observable sequence.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Object solely used to infer the type of the  type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.
        /// An observable sequence with no elements.
        public static IObservable Empty(TResult witness)
        {
            return s_impl.Empty(); // Pure inference - no specialized target method.
        }
        /// 
        /// Returns an empty observable sequence, using the specified scheduler to send out the single OnCompleted message.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Scheduler to send the termination call on.
        /// An observable sequence with no elements.
        ///  is null.
        public static IObservable Empty(IScheduler scheduler)
        {
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Empty(scheduler);
        }
        /// 
        /// Returns an empty observable sequence, using the specified scheduler to send out the single OnCompleted message.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Scheduler to send the termination call on.
        /// Object solely used to infer the type of the  type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.
        /// An observable sequence with no elements.
        ///  is null.
        public static IObservable Empty(IScheduler scheduler, TResult witness)
        {
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Empty(scheduler); // Pure inference - no specialized target method.
        }
        #endregion
        #region + Generate +
        /// 
        /// Generates an observable sequence by running a state-driven loop producing the sequence's elements.
        /// 
        /// The type of the state used in the generator loop.
        /// The type of the elements in the produced sequence.
        /// Initial state.
        /// Condition to terminate generation (upon returning false).
        /// Iteration step function.
        /// Selector function for results produced in the sequence.
        /// The generated sequence.
        ///  or  or  is null.
        public static IObservable Generate(TState initialState, Func condition, Func iterate, Func resultSelector)
        {
            if (condition == null)
                throw new ArgumentNullException("condition");
            if (iterate == null)
                throw new ArgumentNullException("iterate");
            if (resultSelector == null)
                throw new ArgumentNullException("resultSelector");
            return s_impl.Generate(initialState, condition, iterate, resultSelector);
        }
        /// 
        /// Generates an observable sequence by running a state-driven loop producing the sequence's elements, using the specified scheduler to send out observer messages.
        /// 
        /// The type of the state used in the generator loop.
        /// The type of the elements in the produced sequence.
        /// Initial state.
        /// Condition to terminate generation (upon returning false).
        /// Iteration step function.
        /// Selector function for results produced in the sequence.
        /// Scheduler on which to run the generator loop.
        /// The generated sequence.
        ///  or  or  or  is null.
        public static IObservable Generate(TState initialState, Func condition, Func iterate, Func resultSelector, IScheduler scheduler)
        {
            if (condition == null)
                throw new ArgumentNullException("condition");
            if (iterate == null)
                throw new ArgumentNullException("iterate");
            if (resultSelector == null)
                throw new ArgumentNullException("resultSelector");
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Generate(initialState, condition, iterate, resultSelector, scheduler);
        }
        #endregion
        #region + Never +
        /// 
        /// Returns a non-terminating observable sequence, which can be used to denote an infinite duration (e.g. when using reactive joins).
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// An observable sequence whose observers will never get called.
        public static IObservable Never()
        {
            return s_impl.Never();
        }
        /// 
        /// Returns a non-terminating observable sequence, which can be used to denote an infinite duration (e.g. when using reactive joins).
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Object solely used to infer the type of the  type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.
        /// An observable sequence whose observers will never get called.
        public static IObservable Never(TResult witness)
        {
            return s_impl.Never(); // Pure inference - no specialized target method.
        }
        #endregion
        #region + Range +
        /// 
        /// Generates an observable sequence of integral numbers within a specified range.
        /// 
        /// The value of the first integer in the sequence.
        /// The number of sequential integers to generate.
        /// An observable sequence that contains a range of sequential integral numbers.
        ///  is less than zero. -or-  +  - 1 is larger than .
        public static IObservable Range(int start, int count)
        {
            var max = ((long)start) + count - 1;
            if (count < 0 || max > int.MaxValue)
                throw new ArgumentOutOfRangeException("count");
            return s_impl.Range(start, count);
        }
        /// 
        /// Generates an observable sequence of integral numbers within a specified range, using the specified scheduler to send out observer messages.
        /// 
        /// The value of the first integer in the sequence.
        /// The number of sequential integers to generate.
        /// Scheduler to run the generator loop on.
        /// An observable sequence that contains a range of sequential integral numbers.
        ///  is less than zero. -or-  +  - 1 is larger than .
        ///  is null.
        public static IObservable Range(int start, int count, IScheduler scheduler)
        {
            var max = ((long)start) + count - 1;
            if (count < 0 || max > int.MaxValue)
                throw new ArgumentOutOfRangeException("count");
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Range(start, count, scheduler);
        }
        #endregion
        #region + Repeat +
        /// 
        /// Generates an observable sequence that repeats the given element infinitely.
        /// 
        /// The type of the element that will be repeated in the produced sequence.
        /// Element to repeat.
        /// An observable sequence that repeats the given element infinitely.
        public static IObservable Repeat(TResult value)
        {
            return s_impl.Repeat(value);
        }
        /// 
        /// Generates an observable sequence that repeats the given element infinitely, using the specified scheduler to send out observer messages.
        /// 
        /// The type of the element that will be repeated in the produced sequence.
        /// Element to repeat.
        /// Scheduler to run the producer loop on.
        /// An observable sequence that repeats the given element infinitely.
        ///  is null.
        public static IObservable Repeat(TResult value, IScheduler scheduler)
        {
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Repeat(value, scheduler);
        }
        /// 
        /// Generates an observable sequence that repeats the given element the specified number of times.
        /// 
        /// The type of the element that will be repeated in the produced sequence.
        /// Element to repeat.
        /// Number of times to repeat the element.
        /// An observable sequence that repeats the given element the specified number of times.
        ///  is less than zero.
        public static IObservable Repeat(TResult value, int repeatCount)
        {
            if (repeatCount < 0)
                throw new ArgumentOutOfRangeException("repeatCount");
            return s_impl.Repeat(value, repeatCount);
        }
        /// 
        /// Generates an observable sequence that repeats the given element the specified number of times, using the specified scheduler to send out observer messages.
        /// 
        /// The type of the element that will be repeated in the produced sequence.
        /// Element to repeat.
        /// Number of times to repeat the element.
        /// Scheduler to run the producer loop on.
        /// An observable sequence that repeats the given element the specified number of times.
        ///  is less than zero.
        ///  is null.
        public static IObservable Repeat(TResult value, int repeatCount, IScheduler scheduler)
        {
            if (repeatCount < 0)
                throw new ArgumentOutOfRangeException("repeatCount");
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Repeat(value, repeatCount, scheduler);
        }
        #endregion
        #region + Return +
        /// 
        /// Returns an observable sequence that contains a single element.
        /// 
        /// The type of the element that will be returned in the produced sequence.
        /// Single element in the resulting observable sequence.
        /// An observable sequence containing the single specified element.
        public static IObservable Return(TResult value)
        {
            return s_impl.Return(value);
        }
        /// 
        /// Returns an observable sequence that contains a single element, using the specified scheduler to send out observer messages.
        /// 
        /// The type of the element that will be returned in the produced sequence.
        /// Single element in the resulting observable sequence.
        /// Scheduler to send the single element on.
        /// An observable sequence containing the single specified element.
        ///  is null.
        public static IObservable Return(TResult value, IScheduler scheduler)
        {
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Return(value, scheduler);
        }
        #endregion
        #region + Throw +
        /// 
        /// Returns an observable sequence that terminates with an exception.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Exception object used for the sequence's termination.
        /// The observable sequence that terminates exceptionally with the specified exception object.
        ///  is null.
        public static IObservable Throw(Exception exception)
        {
            if (exception == null)
                throw new ArgumentNullException("exception");
            return s_impl.Throw(exception);
        }
        /// 
        /// Returns an observable sequence that terminates with an exception.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Exception object used for the sequence's termination.
        /// Object solely used to infer the type of the  type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.
        /// The observable sequence that terminates exceptionally with the specified exception object.
        ///  is null.
        public static IObservable Throw(Exception exception, TResult witness)
        {
            if (exception == null)
                throw new ArgumentNullException("exception");
            return s_impl.Throw(exception); // Pure inference - no specialized target method.
        }
        /// 
        /// Returns an observable sequence that terminates with an exception, using the specified scheduler to send out the single OnError message.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Exception object used for the sequence's termination.
        /// Scheduler to send the exceptional termination call on.
        /// The observable sequence that terminates exceptionally with the specified exception object.
        ///  or  is null.
        public static IObservable Throw(Exception exception, IScheduler scheduler)
        {
            if (exception == null)
                throw new ArgumentNullException("exception");
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Throw(exception, scheduler);
        }
        /// 
        /// Returns an observable sequence that terminates with an exception, using the specified scheduler to send out the single OnError message.
        /// 
        /// The type used for the IObservable<T> type parameter of the resulting sequence.
        /// Exception object used for the sequence's termination.
        /// Scheduler to send the exceptional termination call on.
        /// Object solely used to infer the type of the  type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.
        /// The observable sequence that terminates exceptionally with the specified exception object.
        ///  or  is null.
        public static IObservable Throw(Exception exception, IScheduler scheduler, TResult witness)
        {
            if (exception == null)
                throw new ArgumentNullException("exception");
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return s_impl.Throw(exception, scheduler); // Pure inference - no specialized target method.
        }
        #endregion
        #region + Using +
        /// 
        /// Constructs an observable sequence that depends on a resource object, whose lifetime is tied to the resulting observable sequence's lifetime.
        /// 
        /// The type of the elements in the produced sequence.
        /// The type of the resource used during the generation of the resulting sequence. Needs to implement .
        /// Factory function to obtain a resource object.
        /// Factory function to obtain an observable sequence that depends on the obtained resource.
        /// An observable sequence whose lifetime controls the lifetime of the dependent resource object.
        ///  or  is null.
        public static IObservable Using(Func resourceFactory, Func> observableFactory) where TResource : IDisposable
        {
            if (resourceFactory == null)
                throw new ArgumentNullException("resourceFactory");
            if (observableFactory == null)
                throw new ArgumentNullException("observableFactory");
            return s_impl.Using(resourceFactory, observableFactory);
        }
        #endregion
        #region - UsingAsync -
#if !NO_TPL
        /// 
        /// Constructs an observable sequence that depends on a resource object, whose lifetime is tied to the resulting observable sequence's lifetime. The resource is obtained and used through asynchronous methods.
        /// The CancellationToken passed to the asynchronous methods is tied to the returned disposable subscription, allowing best-effort cancellation at any stage of the resource acquisition or usage.
        /// 
        /// The type of the elements in the produced sequence.
        /// The type of the resource used during the generation of the resulting sequence. Needs to implement .
        /// Asynchronous factory function to obtain a resource object.
        /// Asynchronous factory function to obtain an observable sequence that depends on the obtained resource.
        /// An observable sequence whose lifetime controls the lifetime of the dependent resource object.
        ///  or  is null.
        /// This operator is especially useful in conjunction with the asynchronous programming features introduced in C# 5.0 and Visual Basic 11.
        /// When a subscription to the resulting sequence is disposed, the CancellationToken that was fed to the asynchronous resource factory and observable factory functions will be signaled.
        public static IObservable Using(Func> resourceFactoryAsync, Func>> observableFactoryAsync) where TResource : IDisposable
        {
            if (resourceFactoryAsync == null)
                throw new ArgumentNullException("resourceFactoryAsync");
            if (observableFactoryAsync == null)
                throw new ArgumentNullException("observableFactoryAsync");
            return s_impl.Using(resourceFactoryAsync, observableFactoryAsync);
        }
#endif
        #endregion
    }
}