using System;
using System.Collections.Generic;
using System.Linq;

namespace Aqua877.WinApp.IronLivetube
{
	public sealed class ObservableTimer : IObservable<long>, IDisposable
	{
		public TimeSpan Interval
		{
			get
			{
				return this.WhenPeriodChanges.First();
			}
			set
			{
				this.WhenPeriodChanges.OnNext(value);
			}
		}

		private readonly BehaviorSubject<TimeSpan> WhenPeriodChanges;
		private readonly IConnectableObservable<long> Timer;
		private IDisposable Connection;

		public ObservableTimer(TimeSpan dueTime, TimeSpan period)
		{
			this.WhenPeriodChanges = new BehaviorSubject<TimeSpan>(period);
			this.Timer = Start(dueTime, WhenPeriodChanges).Publish();
		}

		private static IObservable<long> Start(TimeSpan dueTime, IObservable<TimeSpan> whenPeriodChanges)
		{
			var nextPeriod = whenPeriodChanges.Skip(1);

			return (from period in whenPeriodChanges.Take(1) from time in Observable.Timer(dueTime, period) select time).TakeUntil(nextPeriod).Concat(from period in whenPeriodChanges from time in Observable.Interval(period).TakeUntil(nextPeriod) select time);
		}

		public void Start()
		{
			if (this.Connection == null)
			{
				lock (this.Timer)
				{
					if (this.Connection == null)
					{
						this.Connection = this.Timer.Connect();
					}
				}
			}
		}

		public void Stop()
		{
			lock (this.Timer)
			{
				if (this.Connection != null)
				{
					this.Connection.Dispose();
				}
			}
		}

		public IDisposable Subscribe(IObserver<long> observer)
		{
			return this.Timer.ObserveOnDispatcher().Subscribe(observer);
		}

		void IDisposable.Dispose()
		{
			this.Stop();
		}
	}

}
