#if FRAMEWORK20
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.Timers;
namespace DevComponents.Schedule.Model
{
    /// 
    /// Provides notification support for appointments.
    /// 
    internal static class NotificationServer
    {
        #region Private Variables
        private static Timer _Timer = null;
        internal static event NotificationServerEventHandler NotifySubscribers;
        private static DateTime _NextEventTime;
        private static List _RequestList = new List();
        #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