using System; using ICD.Common.EventArguments; using ICD.Common.Utils.Extensions; namespace ICD.Common.Utils.Timers { /// /// IcdTimer provides events for time increments as well as timer elapsed. /// public sealed class IcdTimer : IDisposable { private const long DEFAULT_HEARTBEAT_INTERVAL = 500; /// /// Called when the timer is restarted/stopped. /// public event EventHandler OnIsRunningChanged; /// /// Called when the timer has elapsed. /// public event EventHandler OnElapsed; /// /// Called when the milliseconds count changes. Useful for updating UIs. /// public event EventHandler OnMillisecondsChanged; private readonly IcdStopwatch m_Stopwatch; private readonly SafeTimer m_Heartbeat; private long m_LastHeartbeatMilliseconds; #region Properties /// /// Returns true if the timer is stopped. /// public bool IsStopped { get { return !m_Stopwatch.IsRunning; } } /// /// Returns true if the timer is running. /// public bool IsRunning { get { return m_Stopwatch.IsRunning; } } /// /// Returns true if the timer has elapsed. /// public bool IsElapsed { get { return Milliseconds > Length; } } /// /// Returns the number of milliseconds that have passed since the timer started. /// public long Milliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } } /// /// The number of milliseconds before the timer is elapsed. /// public long Length { get; private set; } /// /// Gets the remaining number of milliseconds until the timer is elapsed. Returns 0 if the timer has elapsed. /// public long Remaining { get { return Math.Max(Length - Milliseconds, 0); } } /// /// Gets the remaining number of seconds until the timer is elapsed. Returns 0 if the timer has elapsed. /// public long RemainingSeconds { get { return (long)Math.Ceiling(Remaining / 1000.0f); } } #endregion #region Constructors /// /// Constructor. /// public IcdTimer() : this(DEFAULT_HEARTBEAT_INTERVAL) { } /// /// Creates an IcdTimer with the specified heartbeat interval for the internal timer. /// This allows a finer resolution for timing than the default 500ms. /// /// public IcdTimer(long heartbeatInterval) { m_Heartbeat = new SafeTimer(HeartbeatCallback, heartbeatInterval, heartbeatInterval); m_Stopwatch = new IcdStopwatch(); Stop(); } #endregion #region Methods /// /// Release resources. /// public void Dispose() { OnIsRunningChanged = null; OnElapsed = null; OnMillisecondsChanged = null; m_Stopwatch.Stop(); m_Heartbeat.Dispose(); } /// /// Restarts the timer. /// public void Restart(long length) { Length = length; m_Stopwatch.Reset(); m_Stopwatch.Start(); RaiseOnIsRunningChanged(); } /// /// Stops the timer. /// public void Stop() { m_Stopwatch.Stop(); RaiseOnIsRunningChanged(); } #endregion #region Private Methods /// /// Called when the heartbeat timer elapses. /// private void HeartbeatCallback() { if (Milliseconds == m_LastHeartbeatMilliseconds) return; OnMillisecondsChanged.Raise(this); if (m_LastHeartbeatMilliseconds <= Length && IsElapsed) OnElapsed.Raise(this); m_LastHeartbeatMilliseconds = Milliseconds; } /// /// Raises the OnIsRunningChanged event. /// private void RaiseOnIsRunningChanged() { OnIsRunningChanged.Raise(this, new BoolEventArgs(IsRunning)); } #endregion } }