using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace Senthil.Utilities
{
    public static class Itertools
    {
        public static IEnumerable<T> Chain<T>(params IEnumerable<T>[] iterables)
        {
            foreach(IEnumerable<T> iterable in iterables)
            {
                foreach (T t in iterable)
                {
                    yield return t;
                }
            }
        }        public static IEnumerable<T> Cycle<T>(IEnumerable<T> iterable)
        {
            while (true)
            {
                foreach (T t in iterable)
                {
                    yield return t;
                }
            }
        }        public static IEnumerable<T[]> Zip<T>(params IEnumerable<T>[] iterables)
        {
            IEnumerator<T>[] enumerators = Array.ConvertAll(iterables, (iterable) => iterable.GetEnumerator());            T[] values = new T[enumerators.Length];            while (true)
            {
                int index = 0;                foreach (IEnumerator<T> enumerator in enumerators)
                {
                    if (!enumerator.MoveNext())
                        yield break;                    values[index++] = enumerator.Current;
                }                yield return values;
            }
        }
       
        public static IEnumerator<T>[] Tee<T>(IEnumerator<T> source, int count)
        {
            List<T> tValues = new List<T>();
            IEnumerator<T>[] results = new IEnumerator<T>[count];            for (int i = 0; i < count; ++i)
            {
                int currentLocation = 0;                results[i] = CreateEnumerator(source, new EnumeratorState<T>() { CurrentLocation = currentLocation, TValues = tValues });
            }            return results;
        }        private static IEnumerator<T> CreateEnumerator<T>(IEnumerator<T> source, EnumeratorState<T> state)
        {
            while (true)
            {
                if (state.CurrentLocation < state.TValues.Count)
                {
                    yield return state.TValues[state.CurrentLocation++];
                }
                else
                {
                    if (source.MoveNext())
                    {
                        state.TValues.Add(source.Current);
                        state.CurrentLocation = state.TValues.Count;
                        yield return source.Current;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }        class EnumeratorState<T>
        {
            internal int CurrentLocation { get; set; }
            internal List<T> TValues { get; set; }
        }
    }
}