<#@ 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. 

using System.Reactive.Disposables;

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

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

    #region Zip 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()"));
    var ss = string.Join(", ", Enumerable.Range(1, i).Select(j => "_source" + j));
#>
    internal sealed class Zip<<#=ts#>, TResult> : Producer<TResult, Zip<<#=ts#>, 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 _ CreateSink2(IObserver<TResult> observer, IDisposable cancel) => new _(_resultSelector, observer, cancel);

        protected override IDisposable Run(_ sink) => sink.Run(<#=ss#>);

        internal sealed class _ : ZipSink<TResult>
        {
            private readonly Func<<#=ts#>, TResult> _resultSelector;

            public _(Func<<#=ts#>, TResult> resultSelector, IObserver<TResult> observer, IDisposable cancel)
                : base(<#=i#>, observer, cancel)
            {
                _resultSelector = resultSelector;
            }

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

            public IDisposable Run(<#=os#>)
            {
                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 = 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() => _resultSelector(<#=vs#>);
        }
    }

<#
}
#>

    #endregion

    #endregion
}
