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

namespace System.Reactive.Linq.ObservableImpl
{
	internal static class Window<TSource>
	{
		internal sealed class Count : Producer<IObservable<TSource>, Window<TSource>.Count._>
		{
			public Count(IObservable<TSource> source, int count, int skip)
			{
				this._source = source;
				this._count = count;
				this._skip = skip;
			}

			protected override Window<TSource>.Count._ CreateSink(IObserver<IObservable<TSource>> observer)
			{
				return new Window<TSource>.Count._(this, observer);
			}

			protected override void Run(Window<TSource>.Count._ sink)
			{
				sink.Run(this._source);
			}

			private readonly IObservable<TSource> _source;

			private readonly int _count;

			private readonly int _skip;

			internal sealed class _ : Sink<TSource, IObservable<TSource>>
			{
				public _(Window<TSource>.Count parent, IObserver<IObservable<TSource>> observer)
					: base(observer)
				{
					this._refCountDisposable = new RefCountDisposable(this._m);
					this._count = parent._count;
					this._skip = parent._skip;
				}

				public override void Run(IObservable<TSource> source)
				{
					IObservable<TSource> observable = this.CreateWindow();
					base.ForwardOnNext(observable);
					this._m.Disposable = source.SubscribeSafe(this);
					base.SetUpstream(this._refCountDisposable);
				}

				private IObservable<TSource> CreateWindow()
				{
					Subject<TSource> subject = new Subject<TSource>();
					this._queue.Enqueue(subject);
					return new WindowObservable<TSource>(subject, this._refCountDisposable);
				}

				public override void OnNext(TSource value)
				{
					foreach (ISubject<TSource> subject in this._queue)
					{
						subject.OnNext(value);
					}
					int num = this._n - this._count + 1;
					if (num >= 0 && num % this._skip == 0)
					{
						this._queue.Dequeue().OnCompleted();
					}
					this._n++;
					if (this._n % this._skip == 0)
					{
						IObservable<TSource> observable = this.CreateWindow();
						base.ForwardOnNext(observable);
					}
				}

				public override void OnError(Exception error)
				{
					while (this._queue.Count > 0)
					{
						this._queue.Dequeue().OnError(error);
					}
					base.ForwardOnError(error);
				}

				public override void OnCompleted()
				{
					while (this._queue.Count > 0)
					{
						this._queue.Dequeue().OnCompleted();
					}
					base.ForwardOnCompleted();
				}

				private readonly Queue<ISubject<TSource>> _queue = new Queue<ISubject<TSource>>();

				private readonly SingleAssignmentDisposable _m = new SingleAssignmentDisposable();

				private readonly RefCountDisposable _refCountDisposable;

				private readonly int _count;

				private readonly int _skip;

				private int _n;
			}
		}

		internal sealed class TimeSliding : Producer<IObservable<TSource>, Window<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 Window<TSource>.TimeSliding._ CreateSink(IObserver<IObservable<TSource>> observer)
			{
				return new Window<TSource>.TimeSliding._(this, observer);
			}

			protected override void Run(Window<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, IObservable<TSource>>
			{
				public _(Window<TSource>.TimeSliding parent, IObserver<IObservable<TSource>> observer)
					: base(observer)
				{
					this._scheduler = parent._scheduler;
					this._timeShift = parent._timeShift;
				}

				public void Run(Window<TSource>.TimeSliding parent)
				{
					this._totalTime = TimeSpan.Zero;
					this._nextShift = parent._timeShift;
					this._nextSpan = parent._timeSpan;
					CompositeDisposable compositeDisposable = new CompositeDisposable(2) { this._timerD };
					this._refCountDisposable = new RefCountDisposable(compositeDisposable);
					this.CreateWindow();
					this.CreateTimer();
					compositeDisposable.Add(parent._source.SubscribeSafe(this));
					base.SetUpstream(this._refCountDisposable);
				}

				private void CreateWindow()
				{
					Subject<TSource> subject = new Subject<TSource>();
					this._q.Enqueue(subject);
					base.ForwardOnNext(new WindowObservable<TSource>(subject, this._refCountDisposable));
				}

				private void CreateTimer()
				{
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					this._timerD.Disposable = 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<Window<TSource>.TimeSliding._, bool, bool>(this, flag, flag2), timeSpan2, delegate([TupleElementNames(new string[] { "this", "isSpan", "isShift" })] ValueTuple<Window<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)
						{
							this._q.Dequeue().OnCompleted();
						}
						if (isShift)
						{
							this.CreateWindow();
						}
					}
					this.CreateTimer();
				}

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

				public override void OnError(Exception error)
				{
					object gate = this._gate;
					lock (gate)
					{
						foreach (ISubject<TSource> subject in this._q)
						{
							subject.OnError(error);
						}
						base.ForwardOnError(error);
					}
				}

				public override void OnCompleted()
				{
					object gate = this._gate;
					lock (gate)
					{
						foreach (ISubject<TSource> subject in this._q)
						{
							subject.OnCompleted();
						}
						base.ForwardOnCompleted();
					}
				}

				private readonly object _gate = new object();

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

				private readonly SerialDisposable _timerD = new SerialDisposable();

				private readonly IScheduler _scheduler;

				private readonly TimeSpan _timeShift;

				private RefCountDisposable _refCountDisposable;

				private TimeSpan _totalTime;

				private TimeSpan _nextShift;

				private TimeSpan _nextSpan;
			}
		}

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

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

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

			private readonly IObservable<TSource> _source;

			private readonly TimeSpan _timeSpan;

			private readonly IScheduler _scheduler;

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

				public void Run(Window<TSource>.TimeHopping parent)
				{
					CompositeDisposable compositeDisposable = new CompositeDisposable(2);
					this._refCountDisposable = new RefCountDisposable(compositeDisposable);
					this.CreateWindow();
					compositeDisposable.Add(parent._scheduler.SchedulePeriodic(this, parent._timeSpan, delegate(Window<TSource>.TimeHopping._ @this)
					{
						@this.Tick();
					}));
					compositeDisposable.Add(parent._source.SubscribeSafe(this));
					base.SetUpstream(this._refCountDisposable);
				}

				private void Tick()
				{
					object gate = this._gate;
					lock (gate)
					{
						this._subject.OnCompleted();
						this.CreateWindow();
					}
				}

				private void CreateWindow()
				{
					this._subject = new Subject<TSource>();
					base.ForwardOnNext(new WindowObservable<TSource>(this._subject, this._refCountDisposable));
				}

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

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

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

				private readonly object _gate = new object();

				private Subject<TSource> _subject;

				private RefCountDisposable _refCountDisposable;
			}
		}

		internal sealed class Ferry : Producer<IObservable<TSource>, Window<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 Window<TSource>.Ferry._ CreateSink(IObserver<IObservable<TSource>> observer)
			{
				return new Window<TSource>.Ferry._(this, observer);
			}

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

			private readonly IObservable<TSource> _source;

			private readonly int _count;

			private readonly TimeSpan _timeSpan;

			private readonly IScheduler _scheduler;

			internal sealed class _ : Sink<TSource, IObservable<TSource>>
			{
				public _(Window<TSource>.Ferry parent, IObserver<IObservable<TSource>> observer)
					: base(observer)
				{
					this._count = parent._count;
					this._timeSpan = parent._timeSpan;
					this._scheduler = parent._scheduler;
				}

				public override void Run(IObservable<TSource> source)
				{
					CompositeDisposable compositeDisposable = new CompositeDisposable(2) { this._timerD };
					this._refCountDisposable = new RefCountDisposable(compositeDisposable);
					this._s = new Subject<TSource>();
					base.ForwardOnNext(new WindowObservable<TSource>(this._s, this._refCountDisposable));
					this.CreateTimer(this._s);
					compositeDisposable.Add(source.SubscribeSafe(this));
					base.SetUpstream(this._refCountDisposable);
				}

				private void CreateTimer(Subject<TSource> window)
				{
					SingleAssignmentDisposable singleAssignmentDisposable = new SingleAssignmentDisposable();
					this._timerD.Disposable = singleAssignmentDisposable;
					singleAssignmentDisposable.Disposable = this._scheduler.ScheduleAction(new ValueTuple<Window<TSource>.Ferry._, Subject<TSource>>(this, window), this._timeSpan, delegate([TupleElementNames(new string[] { "this", "window" })] ValueTuple<Window<TSource>.Ferry._, Subject<TSource>> tuple)
					{
						tuple.Item1.Tick(tuple.Item2);
					});
				}

				private void Tick(Subject<TSource> window)
				{
					Subject<TSource> subject = null;
					object gate = this._gate;
					lock (gate)
					{
						if (window != this._s)
						{
							return;
						}
						this._n = 0;
						subject = new Subject<TSource>();
						this._s.OnCompleted();
						this._s = subject;
						base.ForwardOnNext(new WindowObservable<TSource>(this._s, this._refCountDisposable));
					}
					this.CreateTimer(subject);
				}

				public override void OnNext(TSource value)
				{
					Subject<TSource> subject = null;
					object gate = this._gate;
					lock (gate)
					{
						this._s.OnNext(value);
						this._n++;
						if (this._n == this._count)
						{
							this._n = 0;
							subject = new Subject<TSource>();
							this._s.OnCompleted();
							this._s = subject;
							base.ForwardOnNext(new WindowObservable<TSource>(this._s, this._refCountDisposable));
						}
					}
					if (subject != null)
					{
						this.CreateTimer(subject);
					}
				}

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

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

				private readonly object _gate = new object();

				private readonly SerialDisposable _timerD = new SerialDisposable();

				private readonly int _count;

				private readonly TimeSpan _timeSpan;

				private readonly IScheduler _scheduler;

				private Subject<TSource> _s;

				private int _n;

				private RefCountDisposable _refCountDisposable;
			}
		}
	}
}
