/*
© 2017 Altavant Technologies Inc.
Web: http://www.altavant.com
*/

using Foundation;

namespace Altavant.Fusion.Core
{
	using System;

	public delegate void OnTimerDelegate(Timer sender);

	public class Timer
	{
		private float _interval;
		private bool _repeating;
		private OnTimerDelegate _onTimer;
		private NSTimer _timer;
		private DateTime _timestamp;
		private float _delta;
		private bool _paused;
		private bool _active;

		public Timer()
			: this(1F, true, null)
		{

		}

		public Timer(float interval)
			: this(interval, true, null)
		{

		}

		public Timer(bool repeating)
			: this(1F, repeating, null)
		{

		}

		public Timer(float interval, bool repeating)
			: this(interval, repeating, null)
		{

		}

		public Timer(float interval, OnTimerDelegate onTimer)
			: this(interval, true, onTimer)
		{

		}

		public Timer(float interval, bool repeating, OnTimerDelegate onTimer)
		{
			if (interval <= 0F)
				throw new ArgumentOutOfRangeException(nameof(interval), "(0.0, ...]");

			_interval = interval;
			_onTimer = onTimer;
			_repeating = repeating;
		}

		public float Interval
		{
			get
			{
				return _interval;
			}
			set
			{
				if (value <= 0F)
					throw new ArgumentOutOfRangeException(null, "(0.0, ...]");

				_interval = value;
			}
		}

		public bool Repeating
		{
			get
			{
				return _repeating;
			}
			set
			{
				_repeating = value;
			}
		}

		public OnTimerDelegate OnTimer
		{
			get
			{
				return _onTimer;
			}
			set
			{
				_onTimer = value;
			}
		}

		public bool Paused
		{
			get
			{
				return _paused;
			}
		}

		public bool Active
		{
			get
			{
				return _active;
			}
		}

		private void OnAction(NSTimer timer)
		{
			if (_active && !_paused)
			{
				if (_repeating)
				{
					if (_delta == 0F)
					{
						_timestamp = DateTime.UtcNow;
					}
					else
					{
						ReleaseTimer();

						CreateTimer(_interval);
					}
				}
				else
				{
					ReleaseTimer();

					_active = false;
				}

				_delta = 0F;

				if (_onTimer != null)
					_onTimer(this);
			}
		}

		public void Start()
		{
			if (!_active)
			{
				if (!_paused)
					CreateTimer(_interval);

				_active = true;
			}
		}

		public void Pause()
		{
			if (_active && !_paused)
			{
				_paused = true;

				ReleaseTimer();

				TimeSpan ts = DateTime.UtcNow - _timestamp;

				_delta = _interval - (float)(ts.TotalMilliseconds / 1000F);

				if (_delta < 0.001F)
					_delta = _interval;
			}
		}

		public void Resume()
		{
			if (_active && _paused)
			{
				CreateTimer(_delta);

				_paused = false;
			}
		}

		public void Stop()
		{
			if (_active)
			{
				_active = false;

				if (!_paused)
					ReleaseTimer();
			}
		}

		private void CreateTimer(float delay)
		{
			_timer = NSTimer.CreateRepeatingScheduledTimer(delay, OnAction);

			_timestamp = DateTime.UtcNow;
		}

		private void ReleaseTimer()
		{
			if (_timer != null)
			{
				_timer.Invalidate();

				_timer = null;
			}
		}
	}
}