using System;
using System.Collections.Generic;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;

namespace System.Reactive.Linq.ObservableImpl
{
	internal static class Buffer<TSource>
	{
		internal sealed class CountExact : Producer<IList<TSource>, Buffer<TSource>.CountExact.ExactSink>
		{
			public CountExact(IObservable<TSource> source, int count)
			{
				this._source = source;
				this._count = count;
			}

			protected override Buffer<TSource>.CountExact.ExactSink CreateSink(IObserver<IList<TSource>> observer)
			{
				return new Buffer<TSource>.CountExact.ExactSink(observer, this._count);
			}

			protected override void Run(Buffer<TSource>.CountExact.ExactSink sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly int _count;

			internal sealed class ExactSink : Sink<TSource, IList<TSource>>
			{
				internal ExactSink(IObserver<IList<TSource>> observer, int count)
					: base(observer)
				{
					this._count = count;
				}

				public override void OnNext(TSource value)
				{
					IList<TSource> list = this._buffer;
					if (list == null)
					{
						list = new List<TSource>();
						this._buffer = list;
					}
					list.Add(value);
					int num = this._index + 1;
					if (num == this._count)
					{
						this._buffer = null;
						this._index = 0;
						base.ForwardOnNext(list);
						return;
					}
					this._index = num;
				}

				public override void OnError(Exception error)
				{
					this._buffer = null;
					base.ForwardOnError(error);
				}

				public override void OnCompleted()
				{
					IList<TSource> buffer = this._buffer;
					this._buffer = null;
					if (buffer != null)
					{
						base.ForwardOnNext(buffer);
					}
					base.ForwardOnCompleted();
				}

				private readonly int _count;

				private int _index;

				private IList<TSource> _buffer;
			}
		}

		internal sealed class CountSkip : Producer<IList<TSource>, Buffer<TSource>.CountSkip.SkipSink>
		{
			public CountSkip(IObservable<TSource> source, int count, int skip)
			{
				this._source = source;
				this._count = count;
				this._skip = skip;
			}

			protected override Buffer<TSource>.CountSkip.SkipSink CreateSink(IObserver<IList<TSource>> observer)
			{
				return new Buffer<TSource>.CountSkip.SkipSink(observer, this._count, this._skip);
			}

			protected override void Run(Buffer<TSource>.CountSkip.SkipSink sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly int _count;

			private readonly int _skip;

			internal sealed class SkipSink : Sink<TSource, IList<TSource>>
			{
				internal SkipSink(IObserver<IList<TSource>> observer, int count, int skip)
					: base(observer)
				{
					this._count = count;
					this._skip = skip;
				}

				public override void OnNext(TSource value)
				{
					int num = this._index;
					IList<TSource> list = this._buffer;
					if (num == 0)
					{
						list = new List<TSource>();
						this._buffer = list;
					}
					if (list != null)
					{
						list.Add(value);
					}
					if (++num == this._count)
					{
						this._buffer = null;
						base.ForwardOnNext(list);
					}
					if (num == this._skip)
					{
						this._index = 0;
						return;
					}
					this._index = num;
				}

				public override void OnError(Exception error)
				{
					this._buffer = null;
					base.ForwardOnError(error);
				}

				public override void OnCompleted()
				{
					IList<TSource> buffer = this._buffer;
					this._buffer = null;
					if (buffer != null)
					{
						base.ForwardOnNext(buffer);
					}
					base.ForwardOnCompleted();
				}

				private readonly int _count;

				private readonly int _skip;

				private int _index;

				private IList<TSource> _buffer;
			}
		}

		internal sealed class CountOverlap : Producer<IList<TSource>, Buffer<TSource>.CountOverlap.OverlapSink>
		{
			public CountOverlap(IObservable<TSource> source, int count, int skip)
			{
				this._source = source;
				this._count = count;
				this._skip = skip;
			}

			protected override Buffer<TSource>.CountOverlap.OverlapSink CreateSink(IObserver<IList<TSource>> observer)
			{
				return new Buffer<TSource>.CountOverlap.OverlapSink(observer, this._count, this._skip);
			}

			protected override void Run(Buffer<TSource>.CountOverlap.OverlapSink sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly int _count;

			private readonly int _skip;

			internal sealed class OverlapSink : Sink<TSource, IList<TSource>>
			{
				public OverlapSink(IObserver<IList<TSource>> observer, int count, int skip)
					: base(observer)
				{
					this._queue = new Queue<IList<TSource>>();
					this._count = count;
					this._skip = skip;
					this.CreateWindow();
				}

				private void CreateWindow()
				{
					List<TSource> list = new List<TSource>();
					this._queue.Enqueue(list);
				}

				public override void OnNext(TSource value)
				{
					foreach (IList<TSource> list in this._queue)
					{
						list.Add(value);
					}
					int num = this._n - this._count + 1;
					if (num >= 0 && num % this._skip == 0)
					{
						IList<TSource> list2 = this._queue.Dequeue();
						if (list2.Count > 0)
						{
							base.ForwardOnNext(list2);
						}
					}
					this._n++;
					if (this._n % this._skip == 0)
					{
						this.CreateWindow();
					}
				}

				public override void OnError(Exception error)
				{
					this._queue.Clear();
					base.ForwardOnError(error);
				}

				public override void OnCompleted()
				{
					while (this._queue.Count > 0)
					{
						IList<TSource> list = this._queue.Dequeue();
						if (list.Count > 0)
						{
							base.ForwardOnNext(list);
						}
					}
					base.ForwardOnCompleted();
				}

				private readonly Queue<IList<TSource>> _queue;

				private readonly int _count;

				private readonly int _skip;

				private int _n;
			}
		}

		internal sealed class TimeSliding : Producer<IList<TSource>, Buffer<TSource>.TimeSliding._>
		{
			public TimeSliding(IObservable<TSource> source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler)
			{
				this._source = source;
				this._timeSpan = timeSpan;
				this._timeShift = timeShift;
				this._scheduler = scheduler;
			}

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

			protected override void Run(Buffer<TSource>.TimeSliding._ sink)
			{
				sink.Run(this);
			}

			private readonly IObservable<TSource> _source;

			private readonly TimeSpan _timeSpan;

			private readonly TimeSpan _timeShift;

			private readonly IScheduler _scheduler;

			internal sealed class _ : Sink<TSource, IList<TSource>>
			{
				public _(Buffer<TSource>.TimeSliding parent, IObserver<IList<TSource>> observer)
					: base(observer)
				{
					this._timeShift = parent._timeShift;
					this._scheduler = parent._scheduler;
				}

				public void Run(Buffer<TSource>.TimeSliding parent)
				{
					this._totalTime = TimeSpan.Zero;
					this._nextShift = parent._timeShift;
					this._nextSpan = parent._timeSpan;
					this.CreateWindow();
					this.CreateTimer();
					this.Run(parent._source);
				}

				protected override void Dispose(bool disposing)
				{
					if (disposing)
					{
						Disposable.TryDispose(ref this._timerSerial);
					}
					base.Dispose(disposing);
				}

				private void CreateWindow()
				{
					List<TSource> list = new List<TSource>();
					this._q.Enqueue(list);
				}

				private void CreateTimer()
				{
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					Disposable.TrySetSerial(ref this._timerSerial, singleAssignmentDisposable);
					bool flag = false;
					bool flag2 = false;
					if (this._nextSpan == this._nextShift)
					{
						flag = true;
						flag2 = true;
					}
					else if (this._nextSpan < this._nextShift)
					{
						flag = true;
					}
					else
					{
						flag2 = true;
					}
					TimeSpan timeSpan = (flag ? this._nextSpan : this._nextShift);
					TimeSpan timeSpan2 = timeSpan - this._totalTime;
					this._totalTime = timeSpan;
					if (flag)
					{
						this._nextSpan += this._timeShift;
					}
					if (flag2)
					{
						this._nextShift += this._timeShift;
					}
					singleAssignmentDisposable.Disposable = this._scheduler.ScheduleAction(new ValueTuple<Buffer<TSource>.TimeSliding._, bool, bool>(this, flag, flag2), timeSpan2, delegate([TupleElementNames(new string[] { "this", "isSpan", "isShift" })] ValueTuple<Buffer<TSource>.TimeSliding._, bool, bool> tuple)
					{
						tuple.Item1.Tick(tuple.Item2, tuple.Item3);
					});
				}

				private void Tick(bool isSpan, bool isShift)
				{
					object gate = this._gate;
					lock (gate)
					{
						if (isSpan)
						{
							List<TSource> list = this._q.Dequeue();
							base.ForwardOnNext(list);
						}
						if (isShift)
						{
							this.CreateWindow();
						}
					}
					this.CreateTimer();
				}

				public override void OnNext(TSource value)
				{
					object gate = this._gate;
					lock (gate)
					{
						foreach (List<TSource> list in this._q)
						{
							list.Add(value);
						}
					}
				}

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						while (this._q.Count > 0)
						{
							this._q.Dequeue().Clear();
						}
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					object gate = this._gate;
					lock (gate)
					{
						while (this._q.Count > 0)
						{
							base.ForwardOnNext(this._q.Dequeue());
						}
						base.ForwardOnCompleted();
					}
				}

				private readonly TimeSpan _timeShift;

				private readonly IScheduler _scheduler;

				private readonly object _gate = new object();

				private readonly Queue<List<TSource>> _q = new Queue<List<TSource>>();

				private IDisposable _timerSerial;

				private TimeSpan _totalTime;

				private TimeSpan _nextShift;

				private TimeSpan _nextSpan;
			}
		}

		internal sealed class TimeHopping : Producer<IList<TSource>, Buffer<TSource>.TimeHopping._>
		{
			public TimeHopping(IObservable<TSource> source, TimeSpan timeSpan, IScheduler scheduler)
			{
				this._source = source;
				this._timeSpan = timeSpan;
				this._scheduler = scheduler;
			}

			protected override Buffer<TSource>.TimeHopping._ CreateSink(IObserver<IList<TSource>> observer)
			{
				return new Buffer<TSource>.TimeHopping._(observer);
			}

			protected override void Run(Buffer<TSource>.TimeHopping._ sink)
			{
				sink.Run(this);
			}

			private readonly IObservable<TSource> _source;

			private readonly TimeSpan _timeSpan;

			private readonly IScheduler _scheduler;

			internal sealed class _ : Sink<TSource, IList<TSource>>
			{
				public _(IObserver<IList<TSource>> observer)
					: base(observer)
				{
				}

				public void Run(Buffer<TSource>.TimeHopping parent)
				{
					this._list = new List<TSource>();
					Disposable.SetSingle(ref this._periodicDisposable, parent._scheduler.SchedulePeriodic(this, parent._timeSpan, delegate(Buffer<TSource>.TimeHopping._ @this)
					{
						@this.Tick();
					}));
					this.Run(parent._source);
				}

				protected override void Dispose(bool disposing)
				{
					if (disposing)
					{
						Disposable.TryDispose(ref this._periodicDisposable);
					}
					base.Dispose(disposing);
				}

				private void Tick()
				{
					object gate = this._gate;
					lock (gate)
					{
						base.ForwardOnNext(this._list);
						this._list = new List<TSource>();
					}
				}

				public override void OnNext(TSource value)
				{
					object gate = this._gate;
					lock (gate)
					{
						this._list.Add(value);
					}
				}

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						this._list.Clear();
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					object gate = this._gate;
					lock (gate)
					{
						base.ForwardOnNext(this._list);
						base.ForwardOnCompleted();
					}
				}

				private readonly object _gate = new object();

				private List<TSource> _list;

				private IDisposable _periodicDisposable;
			}
		}

		internal sealed class Ferry : Producer<IList<TSource>, Buffer<TSource>.Ferry._>
		{
			public Ferry(IObservable<TSource> source, TimeSpan timeSpan, int count, IScheduler scheduler)
			{
				this._source = source;
				this._timeSpan = timeSpan;
				this._count = count;
				this._scheduler = scheduler;
			}

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

			protected override void Run(Buffer<TSource>.Ferry._ sink)
			{
				sink.Run();
			}

			private readonly IObservable<TSource> _source;

			private readonly int _count;

			private readonly TimeSpan _timeSpan;

			private readonly IScheduler _scheduler;

			internal sealed class _ : Sink<TSource, IList<TSource>>
			{
				public _(Buffer<TSource>.Ferry parent, IObserver<IList<TSource>> observer)
					: base(observer)
				{
					this._parent = parent;
				}

				public void Run()
				{
					this._s = new List<TSource>();
					this._n = 0;
					this._windowId = 0;
					this.CreateTimer(0);
					base.SetUpstream(this._parent._source.SubscribeSafe(this));
				}

				protected override void Dispose(bool disposing)
				{
					if (disposing)
					{
						Disposable.TryDispose(ref this._timerSerial);
					}
					base.Dispose(disposing);
				}

				private void CreateTimer(int id)
				{
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					Disposable.TrySetSerial(ref this._timerSerial, singleAssignmentDisposable);
					singleAssignmentDisposable.Disposable = this._parent._scheduler.ScheduleAction(new ValueTuple<Buffer<TSource>.Ferry._, int>(this, id), this._parent._timeSpan, delegate([TupleElementNames(new string[] { "this", "id" })] ValueTuple<Buffer<TSource>.Ferry._, int> tuple)
					{
						tuple.Item1.Tick(tuple.Item2);
					});
				}

				private void Tick(int id)
				{
					object gate = this._gate;
					lock (gate)
					{
						if (id == this._windowId)
						{
							this._n = 0;
							int num = this._windowId + 1;
							this._windowId = num;
							int num2 = num;
							IList<TSource> s = this._s;
							this._s = new List<TSource>();
							base.ForwardOnNext(s);
							this.CreateTimer(num2);
						}
					}
				}

				public override void OnNext(TSource value)
				{
					bool flag = false;
					int num = 0;
					object gate = this._gate;
					lock (gate)
					{
						this._s.Add(value);
						this._n++;
						if (this._n == this._parent._count)
						{
							flag = true;
							this._n = 0;
							int num2 = this._windowId + 1;
							this._windowId = num2;
							num = num2;
							IList<TSource> s = this._s;
							this._s = new List<TSource>();
							base.ForwardOnNext(s);
						}
						if (flag)
						{
							this.CreateTimer(num);
						}
					}
				}

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						this._s.Clear();
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					object gate = this._gate;
					lock (gate)
					{
						base.ForwardOnNext(this._s);
						base.ForwardOnCompleted();
					}
				}

				private readonly Buffer<TSource>.Ferry _parent;

				private readonly object _gate = new object();

				private IDisposable _timerSerial;

				private IList<TSource> _s;

				private int _n;

				private int _windowId;
			}
		}
	}
}
