tvolodimir
9/14/2014 - 7:28 AM

TimeAction Wrapper

TimeAction Wrapper

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Timer = System.Timers.Timer;

public class TimerAction
{
	private readonly Action action;
	private readonly Timer timer;
	private bool stopInvoked = false;
	private bool stopped = true;
	private bool inAction = false;
	private readonly ManualResetEvent mre = new ManualResetEvent(true);

	public TimerAction(Action action, int intervalMilliseconds)
	{
		this.action = action;
		this.timer = new Timer {Interval = intervalMilliseconds};
		this.timer.Elapsed += timer_Elapsed;
	}

	public void Start()
	{
		lock (this)
		{
			if (stopped)
			{
				stopped = false;
				stopInvoked = false;
				if (!inAction)
				{
					mre.Reset();
					timer.Start();
				}
			}
			else if (stopInvoked)
			{
				// disable this feature (mre set only on "stopped" and after stop invoking, mre not setted - its a problem maybe)
				// Timer cancel stoping and start
				//stopInvoked = false;
			}
		}
	}

	public void StopInvoke()
	{
		lock (this)
		{
			if (stopped) return;
			if (stopInvoked) return;

			stopInvoked = true;
			timer.Stop();

			if (!inAction)
			{
				stopped = true;
				OnStopped();
			}
		}
	}

	public Task Stop()
	{
		StopInvoke();

		return new TaskFactory().StartNew(() =>
		{
			mre.WaitOne();
		});
	}

	private void timer_Elapsed(object sender, ElapsedEventArgs e)
	{
		lock (this)
		{
			timer.Stop();

			if (stopped) return;

			if (stopInvoked)
			{
				stopped = true;
				OnStopped();
				return;
			}

			inAction = true;
		}

		try
		{
			action();
		}
		catch (Exception exception)
		{
		}

		lock (this)
		{
			inAction = false;

			if (stopped) return;

			if (stopInvoked)
			{
				stopped = true;
				OnStopped();
			}
			else
			{
				timer.Start();
			}
		}
	}

	private void OnStopped()
	{
		mre.Set();
	}
}