// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
#if !NO_EXPRESSIONS
#pragma warning disable 1591
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reactive.Concurrency;
namespace System.Reactive.Linq
{
    /// 
    /// Provides a set of static methods for writing queries over observable sequences, allowing translation to a target query language.
    /// 
    public static partial class Qbservable
    {
        /// 
        /// Returns the input typed as an IObservable<TSource>.
        /// This operator is used to separate the part of the query that's captured as an expression tree from the part that's executed locally.
        /// 
        /// The type of the elements in the source sequence.
        /// An IQbservable<TSource> sequence to convert to an IObservable<TSource> sequence.
        /// The original source object, but typed as an IObservable<TSource>.
        ///  is null.
        public static IObservable AsObservable(this IQbservable source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            return source;
        }
        /// 
        /// Converts an enumerable sequence to an observable sequence.
        /// 
        /// The type of the elements in the source sequence.
        /// Enumerable sequence to convert to an observable sequence.
        /// The observable sequence whose elements are pulled from the given enumerable sequence.
        ///  is null.
        /// This operator requires the source's  object (see ) to implement .
        public static IQbservable ToQbservable(this IQueryable source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            return ((IQbservableProvider)source.Provider).CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => Qbservable.ToQbservable(default(IQueryable))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    source.Expression
                )
            );
        }
        /// 
        /// Converts an enumerable sequence to an observable sequence, using the specified scheduler to run the enumeration loop.
        /// 
        /// The type of the elements in the source sequence.
        /// Enumerable sequence to convert to an observable sequence.
        /// Scheduler to run the enumeration of the input sequence on.
        /// The observable sequence whose elements are pulled from the given enumerable sequence.
        ///  or  is null.
        /// This operator requires the source's  object (see ) to implement .
        public static IQbservable ToQbservable(this IQueryable source, IScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (scheduler == null)
                throw new ArgumentNullException("scheduler");
            return ((IQbservableProvider)source.Provider).CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => Qbservable.ToQbservable(default(IQueryable))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    source.Expression,
                    Expression.Constant(scheduler)
                )
            );
        }
        internal static Expression GetSourceExpression(IObservable source)
        {
            var q = source as IQbservable;
            if (q != null)
                return q.Expression;
            return Expression.Constant(source, typeof(IObservable));
        }
        internal static Expression GetSourceExpression(IEnumerable source)
        {
            var q = source as IQueryable;
            if (q != null)
                return q.Expression;
            return Expression.Constant(source, typeof(IEnumerable));
        }
        internal static Expression GetSourceExpression(IObservable[] sources)
        {
            return Expression.NewArrayInit(
                typeof(IObservable),
                sources.Select(source => GetSourceExpression(source))
            );
        }
        internal static Expression GetSourceExpression(IEnumerable[] sources)
        {
            return Expression.NewArrayInit(
                typeof(IEnumerable),
                sources.Select(source => GetSourceExpression(source))
            );
        }
        internal static MethodInfo InfoOf(Expression> f)
        {
            return ((MethodCallExpression)f.Body).Method;
        }
    }
}
#pragma warning restore 1591
#endif