<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information. 

#if !NO_PERF
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Disposables;

namespace System.Reactive.Linq.ObservableImpl
{
	#region [3,16]-ary

    /* The following code is generated by a T4 template. */

    #region CombineLatest auto-generated code (<#=DateTime.Now.ToString()#>)

<#
for (var i = 3; i <= 16; i++)
{
	var ts = string.Join(", ", Enumerable.Range(1, i).Select(j => "T" + j));
	var os = string.Join(", ", Enumerable.Range(1, i).Select(j => "IObservable<T" + j + "> source" + j));
	var vs = string.Join(", ", Enumerable.Range(1, i).Select(j => "_observer" + j + ".Values.Dequeue()"));

	if (i == 5)
	{
#>
#if !NO_LARGEARITY

<#
	}
#>
	class Zip<<#=ts#>, TResult> : Producer<TResult>
    {
<#
for (var j = 1; j <= i; j++)
{
#>
        private readonly IObservable<T<#=j#>> _source<#=j#>;
<#
}
#>
        private readonly Func<<#=ts#>, TResult> _resultSelector;

        public Zip(<#=os#>, Func<<#=ts#>, TResult> resultSelector)
        {
<#
for (var j = 1; j <= i; j++)
{
#>
            _source<#=j#> = source<#=j#>;
<#
}
#>
            _resultSelector = resultSelector;
        }

        protected override IDisposable Run(IObserver<TResult> observer, IDisposable cancel, Action<IDisposable> setSink)
        {
            var sink = new _(this, observer, cancel);
            setSink(sink);
            return sink.Run();
        }

        class _ : ZipSink<TResult>
        {
            private readonly Zip<<#=ts#>, TResult> _parent;

            public _(Zip<<#=ts#>, TResult> parent, IObserver<TResult> observer, IDisposable cancel)
                : base(<#=i#>, observer, cancel)
            {
                _parent = parent;
            }

<#
for (var j = 1; j <= i; j++)
{
#>
            private ZipObserver<T<#=j#>> _observer<#=j#>;
<#
}
#>

            public IDisposable Run()
            {
				var disposables = new IDisposable[<#=i + 1#>];

<#
for (var j = 1; j <= i; j++)
{
#>
				var d<#=j#> = new SingleAssignmentDisposable();
				disposables[<#=j - 1#>] = d<#=j#>;
				_observer<#=j#> = new ZipObserver<T<#=j#>>(_gate, this, <#=j - 1#>, d<#=j#>);
				base.Queues[<#= j - 1#>] = _observer<#=j#>.Values;

<#
}

for (var j = 1; j <= i; j++)
{
#>
                d<#=j#>.Disposable = _parent._source<#=j#>.SubscribeSafe(_observer<#=j#>);
<#
}
#>

				disposables[<#=i#>] = Disposable.Create(() =>
                {
<#
for (var j = 1; j <= i; j++)
{
#>
                    _observer<#=j#>.Values.Clear();
<#
}
#>
                });

                return StableCompositeDisposable.Create(disposables);
            }

            protected override TResult GetResult()
            {
                return _parent._resultSelector(<#=vs#>);
            }
        }
    }

<#
}
#>

#endif

	#endregion

	#endregion
}
#endif