using System;
using System.Collections.Generic;

namespace System.Reactive.Linq.ObservableImpl
{
	internal sealed class MaxBy<TSource, TKey> : Producer<IList<TSource>, MaxBy<TSource, TKey>._>
	{
		public MaxBy(IObservable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
		{
			this._source = source;
			this._keySelector = keySelector;
			this._comparer = comparer;
		}

		protected override MaxBy<TSource, TKey>._ CreateSink(IObserver<IList<TSource>> observer)
		{
			return new MaxBy<TSource, TKey>._(this, observer);
		}

		protected override void Run(MaxBy<TSource, TKey>._ sink)
		{
			sink.Run(this._source);
		}

		private readonly IObservable<TSource> _source;

		private readonly Func<TSource, TKey> _keySelector;

		private readonly IComparer<TKey> _comparer;

		internal sealed class _ : Sink<TSource, IList<TSource>>
		{
			public _(MaxBy<TSource, TKey> parent, IObserver<IList<TSource>> observer)
				: base(observer)
			{
				this._keySelector = parent._keySelector;
				this._comparer = parent._comparer;
				this._list = new List<TSource>();
			}

			public override void OnNext(TSource value)
			{
				TKey tkey;
				try
				{
					tkey = this._keySelector(value);
				}
				catch (Exception ex)
				{
					this._list = null;
					this._lastKey = default(TKey);
					base.ForwardOnError(ex);
					return;
				}
				int num = 0;
				if (!this._hasValue)
				{
					this._hasValue = true;
					this._lastKey = tkey;
				}
				else
				{
					try
					{
						num = this._comparer.Compare(tkey, this._lastKey);
					}
					catch (Exception ex2)
					{
						this._list = null;
						this._lastKey = default(TKey);
						base.ForwardOnError(ex2);
						return;
					}
				}
				if (num > 0)
				{
					this._lastKey = tkey;
					this._list.Clear();
				}
				if (num >= 0)
				{
					this._list.Add(value);
				}
			}

			public override void OnError(Exception error)
			{
				this._lastKey = default(TKey);
				this._list = null;
				base.OnError(error);
			}

			public override void OnCompleted()
			{
				List<TSource> list = this._list;
				this._list = null;
				this._lastKey = default(TKey);
				base.ForwardOnNext(list);
				base.ForwardOnCompleted();
			}

			private readonly Func<TSource, TKey> _keySelector;

			private readonly IComparer<TKey> _comparer;

			private bool _hasValue;

			private TKey _lastKey;

			private List<TSource> _list;
		}
	}
}
