// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace System.Linq
{
    public static partial class EnumerableEx
    {
        /// 
        /// Concatenates the input sequences.
        /// 
        /// Source sequence element type.
        /// Source sequences.
        /// Sequence with the elements of the source sequences concatenated.
        public static IEnumerable Concat(this IEnumerable> sources)
        {
            if (sources == null)
                throw new ArgumentNullException("sources");
            return sources.Concat_();
        }
        /// 
        /// Concatenates the input sequences.
        /// 
        /// Source sequence element type.
        /// Source sequences.
        /// Sequence with the elements of the source sequences concatenated.
        public static IEnumerable Concat(params IEnumerable[] sources)
        {
            if (sources == null)
                throw new ArgumentNullException("sources");
            return sources.Concat_();
        }
        private static IEnumerable Concat_(this IEnumerable> sources)
        {
            foreach (var source in sources)
                foreach (var item in source)
                    yield return item;
        }
        /// 
        /// Projects each element of a sequence to an given sequence and flattens the resulting sequences into one sequence.
        /// 
        /// First source sequence element type.
        /// Second source sequence element type.
        /// A sequence of values to project.
        /// Inner sequence each source sequenec element is projected onto.
        /// Sequence flattening the sequences that result from projecting elements in the source sequence.
        public static IEnumerable SelectMany(this IEnumerable source, IEnumerable other)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (other == null)
                throw new ArgumentNullException("other");
            return source.SelectMany(_ => other);
        }
#if NO_ZIP
        /// 
        /// Merges two sequences by applying the specified selector function on index-based corresponding element pairs from both sequences.
        /// 
        /// The type of the elements of the first input sequence.
        /// The type of the elements of the second input sequence.
        /// The type of the elements of the result sequence.
        /// The first sequence to merge.
        /// The second sequence to merge.
        /// Function to apply to each pair of elements from both sequences.
        /// Sequence consisting of the result of pairwise application of the selector function over pairs of elements from the source sequences.
        public static IEnumerable Zip(this IEnumerable first, IEnumerable second, Func resultSelector)
        {
            if (first == null)
                throw new ArgumentNullException("first");
            if (second == null)
                throw new ArgumentNullException("second");
            if (resultSelector == null)
                throw new ArgumentNullException("resultSelector");
            return Zip_(first, second, resultSelector);
        }
        private static IEnumerable Zip_(this IEnumerable first, IEnumerable second, Func resultSelector)
        {
            using (var e1 = first.GetEnumerator())
            using (var e2 = second.GetEnumerator())
                while (e1.MoveNext() && e2.MoveNext())
                    yield return resultSelector(e1.Current, e2.Current);
        }
#endif
    }
}