174 lines
6.2 KiB
C#

#if FRAMEWORK20
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.Timers;
namespace DevComponents.Schedule.Model
{
/// <summary>
/// Provides notification support for appointments.
/// </summary>
internal static class NotificationServer
{
#region Private Variables
private static Timer _Timer = null;
internal static event NotificationServerEventHandler NotifySubscribers;
private static DateTime _NextEventTime;
private static List<NotificationRequest> _RequestList = new List<NotificationRequest>();
#endregion
#region Constructor
static NotificationServer()
{
_Timer = new Timer();
_Timer.Elapsed += new ElapsedEventHandler(NotificationEventTimerTick);
SystemEvents.TimeChanged += new EventHandler(SystemEvents_TimeChanged);
_NextEventTime = DateTime.MinValue;
}
static void SystemEvents_TimeChanged(object sender, EventArgs e)
{
if (_NextEventTime > DateTime.MinValue && UtcNow.Subtract(_NextEventTime).TotalSeconds <= 0)
NotifySubscribersOnTimeEvent();
}
static void NotificationEventTimerTick(object sender, ElapsedEventArgs e)
{
NotifySubscribersOnTimeEvent();
}
private static bool _Notifying = false;
private static void NotifySubscribersOnTimeEvent()
{
try
{
_Notifying = true;
_Timer.Stop();
#if DEBUG
Console.WriteLine("{0} NotificationServer notifying subscribers count: {1}", DateTime.Now, _RequestList.Count);
#endif
// Reset next notification time...
_NextEventTime = DateTime.MinValue;
if (_RequestList.Count == 0)
{
return;
}
DateTime now = CalendarModel.GetCalendarDateTime(UtcNow);
NotificationRequest[] requestList = new NotificationRequest[_RequestList.Count];
_RequestList.CopyTo(requestList);
DateTime nextNotification = DateTime.MinValue;
foreach (NotificationRequest item in requestList)
{
if (item.NotificationTime <= now)
{
if (item.NotificationHandler != null)
{
//if (System.Threading.Thread.CurrentThread.ManagedThreadId != item.ThreadId)
//{
// //System.Threading.SendOrPostCallback callback = new System.Threading.SendOrPostCallback(SendNotification);
// //System.Windows.Threading.DispatcherSynchronizationContext.Current.Post(callback, item);
//}
//else
item.NotificationHandler(item, new NotificationServerEventArgs(now));
}
_RequestList.Remove(item);
}
else if (item.NotificationTime < nextNotification || nextNotification == DateTime.MinValue)
nextNotification = item.NotificationTime;
}
if (nextNotification > DateTime.MinValue)
{
SetNextEventTime(nextNotification);
}
//else
// Console.WriteLine("Not setting next notification time...");
}
finally
{
_Notifying = false;
}
}
private static void SendNotification(object e)
{
NotificationRequest item = (NotificationRequest)e;
if (item.NotificationHandler != null)
{
if (System.Threading.Thread.CurrentThread.ManagedThreadId != item.ThreadId)
{
Console.WriteLine("Different THREAD");
}
else
{
DateTime now = CalendarModel.GetCalendarDateTime(UtcNow);
item.NotificationHandler(item, new NotificationServerEventArgs(now));
}
}
}
private static void SetNextEventTime(DateTime dateTime)
{
DateTime now = CalendarModel.GetCalendarDateTime(UtcNow);
if (dateTime.Subtract(now).TotalSeconds <= 0)
{
if (!_Notifying)
NotifySubscribersOnTimeEvent();
else
_NextEventTime = DateTime.MinValue;
}
else if (dateTime.Subtract(now).TotalSeconds > 0 && (_NextEventTime == DateTime.MinValue || dateTime < _NextEventTime))
{
double nextEvent = dateTime.Subtract(UtcNow).TotalSeconds + 1;
if (nextEvent > int.MaxValue / 1000)
nextEvent = (int.MaxValue - 1) / 1000;
_Timer.Interval = (int)Math.Max(5, nextEvent * 1000);
#if DEBUG
Console.WriteLine("{0} NotificationServer scheduling next event on: {1}, previous scheduled event on: {2}", DateTime.Now, dateTime, _NextEventTime);
#endif
_Timer.Start();
_NextEventTime = dateTime;
}
//else
// _NextEventTime = DateTime.MinValue;
}
private static DateTime UtcNow
{
get
{
return TimeZoneInfo.ConvertTimeToUtc(CalendarModel.CurrentDateTime);
}
}
public static void UpdateNotification(NotificationRequest request)
{
SetNextEventTime(request.NotificationTime);
}
#endregion
#region Internal Implementation
public static void Register(NotificationRequest request)
{
_RequestList.Add(request);
SetNextEventTime(request.NotificationTime);
}
public static void Unregister(NotificationRequest request)
{
_RequestList.Remove(request);
}
#endregion
}
internal delegate void NotificationServerEventHandler(NotificationRequest sender, NotificationServerEventArgs e);
}
#endif