using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wordinator
{
    public class classEventController
    {
        public const long lngTicksPerMilliSecond = 10000;

        static List<classEventTicket> lstTickets = new List<classEventTicket>();

        static System.Windows.Forms.Timer timer = null;
        public delegate bool DelegateCondition();
        public delegate void Delegate_Method(object obj);

        classEventController cMyRef = null;
        public classEventController()
        {
            cMyRef = this;
            timer_Init();
            tmrTimer_RestartTimer.Interval = 10000;
            tmrTimer_RestartTimer.Tick += TmrTimer_RestartTimer_Tick;
            tmrTimer_RestartTimer.Enabled = true;
        }

        private void TmrTimer_RestartTimer_Tick(object sender, EventArgs e)
        {
            DateTime dtNow = DateTime.Now;
            TimeSpan tsElapsed = dtNow.Subtract(dt_LastTick);
            if (tsElapsed.TotalMilliseconds > 10000)
            {
                timer_Init();
            }
        }

        void timer_Init()
        {
  
            if (timer != null)
            {  // is there an alt-thread in an infinite loop ? 
                timer.Enabled = false;
                timer.Dispose();
            }
            timer = new System.Windows.Forms.Timer();

            timer.Interval = 25;
  
            timer.Tick += Timer_Tick;
            timer.Disposed += Timer_Disposed;
            timer.Enabled = true;
        }

        private void Timer_Disposed(object sender, EventArgs e)
        {
         
        }

        object _tag = null;
        public object Tag
        {
            get { return _tag; }
            set
            {
                _tag = value;
            }
        }

        public classEventTicket Ticket(string Name, long lngMilliseconds_Delay, EventHandler eventHandler)
        {
            return Init(Name, lngMilliseconds_Delay, eventHandler, null, lngMilliseconds_Delay);
        }

        public classEventTicket Ticket(string Name, long lngMilliseconds_Delay, EventHandler eventHandler, DelegateCondition condition, long lngMillisecondsCondition_RetryDelay)
        {
            return Init(Name, lngMilliseconds_Delay, eventHandler, condition, lngMillisecondsCondition_RetryDelay);
        }
        classEventTicket Init(string Name, long lngMilliseconds_Delay, EventHandler eventHandler, DelegateCondition condition, long lngMillisecondsCondition_RetryDelay)
        {
            classEventTicket cET_New = new classEventTicket(ref cMyRef, Name);
            DateTime dtNow = DateTime.Now;
            cET_New.Ticks = dtNow.Ticks + lngMilliseconds_Delay * lngTicksPerMilliSecond;
            cET_New.eventHandler = eventHandler;
            cET_New.Condition = condition;
            cET_New.Ticks_ConditionTestDelay = lngMillisecondsCondition_RetryDelay * lngTicksPerMilliSecond;

            timer.Enabled = true;

            return cET_New;
        }



        classEventTicket _cTicketBeingHandled = null;
        public classEventTicket cTicket { get { return _cTicketBeingHandled; } }
        classEventTicket cTicketBeingHandled
        {
            get { return _cTicketBeingHandled; }
            set
            {
                if (_cTicketBeingHandled != value)
                {
                    _cTicketBeingHandled = value;
                }
            }
        }


        static DateTime dt_LastTick = DateTime.Now;
        static System.Threading.Semaphore semTimer = new System.Threading.Semaphore(1, 1);
        static System.Windows.Forms.Timer tmrTimer_RestartTimer = new System.Windows.Forms.Timer();
        static int _intGraphicsRefreshLoopCounter = 0;
        static bool GraphicsRefresh_FocusedRtx()
        {
            int intGraphicsRefreshPeriod = 4; // 25ms timer - draw every 100ms 
            int intGraphicsMaxPeriod = 40;
            _intGraphicsRefreshLoopCounter++;
            if (_intGraphicsRefreshLoopCounter >= intGraphicsMaxPeriod)
                _intGraphicsRefreshLoopCounter = 0;
            return (_intGraphicsRefreshLoopCounter % intGraphicsRefreshPeriod) == 0;
        }

        static bool GraphicsRefresh_Unfocused()
        {
            return _intGraphicsRefreshLoopCounter == 0;
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            DateTime dt_DebugStart = DateTime.Now, dt_DebugEnd = DateTime.Now;

       
            dt_LastTick = DateTime.Now;

            System.Windows.Forms.Timer tmrSender = (System.Windows.Forms.Timer)sender;
            tmrSender.Enabled = false;

            {
                try
                {
                    DateTime dtNow = DateTime.Now;

                    lstTickets = lstTickets.Distinct().ToList<classEventController.classEventTicket>();
                    TimeSpan tsLongestEventDelay = new TimeSpan();
                    classEventTicket cLongestEventTicket = null;
                    while (lstTickets.Count > 0
                        && lstTickets[0].Ticks < dtNow.Ticks
                        )
                    {
                        try
                        {
                            cTicketBeingHandled = lstTickets[0];
                            lstTickets.RemoveAt(0);
                        }
                        catch (Exception errTicketBeingHandled)
                        {
                            ;
                        }

                        if (!cTicketBeingHandled.Quit)
                        {
                            try
                            {
                                cTicketBeingHandled.ExecuteEvent();
                            }
                            catch (Exception errExecute)
                            {
                                ;
                            }

                
                        }

                        try
                        {
                            if (cTicketBeingHandled.AutoRepeat)
                                cTicketBeingHandled.Reschedule();
                            else if (cTicketBeingHandled.EventTicket_FSM_Next != null)
                            {
                                cTicketBeingHandled.EventTicket_FSM_Next.Reschedule();
                            }
                        }
                        catch (Exception errAutoRepeat)
                        {
                            ;
                        }


                    }

         

                    try
                    {
                        ReorderTickets();
                    }
                    catch (Exception errReorderTickets)
                    {
                        ;
                    }


                }
                catch (Exception err)
                {
                    System.Diagnostics.Debug.Print(err.Message);
                }
            }

            timer.Enabled = lstTickets.Count > 0;
        }
    

        static void ReorderTickets()
        {
            if (!TicketsNeedReordering) return;
            lstTickets.RemoveAll(item => item == null);

            IEnumerable<classEventTicket> query = lstTickets.OrderBy(ticket => ticket.Ticks);
            lstTickets = (List<classEventTicket>)query.ToList<classEventTicket>();

            TicketsNeedReordering = false;
        }

        static bool bolTicketsNeedReordering = false;
        static public bool TicketsNeedReordering
        {
            get { return bolTicketsNeedReordering; }
            set { bolTicketsNeedReordering = value; }
        }

        void EventTicks_Changed(object sender, EventArgs e)
        {
            classEventTicket cET = (classEventTicket)sender;

            if (!lstTickets.Contains(cET))
            {
                lstTickets.Add(cET);
            }

            TicketsNeedReordering = true;

            timer.Enabled = true;
        }

        public class classEventTicket
        {
            classEventTicket _EventTicket_FSM_Next = null;
            public classEventTicket EventTicket_FSM_Next
            {
                get { return _EventTicket_FSM_Next; }
                set { _EventTicket_FSM_Next = value; }
            }

            classEventController cEventController = null;
            public classEventTicket(ref classEventController cEventController, string Name)
            {
                this.cEventController = cEventController;
                this.Name = Name;
            }
            public classEventTicket(ref classEventController cEventController)
            {
                this.cEventController = cEventController;
                this.Name = ID.ToString();
            }

            EventHandler _eventHandler = null;
            public EventHandler eventHandler
            {
                get { return _eventHandler; }
                set { _eventHandler = value; }
            }

            public bool Valid
            {
                get
                {
                    return classEventController.lstTickets.Contains(this);
                }
            }

            DelegateCondition _Condition = null;
            /// <summary>
            /// distinguishes this event as Conditional when not null.  
            /// </summary>
            public DelegateCondition Condition
            {
                get { return _Condition; }
                set { _Condition = value; }
            }


            bool bolAutoRepeat = false;
            /// <summary>
            /// when toggled true - event is rescheduled & will repeat until toggled off 
            /// </summary>
            public bool AutoRepeat
            {
                get { return bolAutoRepeat; }
                set
                {
                    if (bolAutoRepeat != value)
                    {
                        bolAutoRepeat = value;
                        if (!bolAutoRepeat)
                            Quit = true;
                        else
                            Reschedule();
                    }
                }
            }

            public void ExecuteEvent()
            {
                if (Quit) return;

                if (Condition != null)
                {
                    if (!Condition())
                    {
                        Reschedule();
                        return;
                    }
                    else
                    {
                        ;
                    }
                }

                try
                {
                    eventHandler((object)this, new EventArgs());
                }
                catch (Exception err)
                {

                }
            }

   

            public void Reschedule()
            {
                // condition has failed - reschedule event 
                if (Ticks_ConditionTestDelay == 0)
                    Ticks_ConditionTestDelay = Ticks_ConditionTestDelay;
                Ticks = DateTime.Now.Ticks + Ticks_ConditionTestDelay;
                Quit = false;
            }

            static int intID_Counter = 0;

            string strName = "";
            public string Name
            {
                get { return strName; }
                set { strName = value; }
            }

            int _intID = intID_Counter++;
            public int ID
            {
                get { return _intID; }
            }

       

            object _tag = null;
            public object Tag
            {
                get { return _tag; }
                set
                {
                    _tag = value;
                }
            }

            bool bolQuit = false;
            public bool Quit
            {
                get { return bolQuit; }
                set
                {
                    bolQuit = value;
                }
            }
            
            bool bolDieAfterExecution = false;
            public bool DieAfterExecution
            {
                get { return bolDieAfterExecution; }
                set
                {
                    bolDieAfterExecution = value;
                }
            }

            public void quit()
            {
                Quit = true;
                AutoRepeat = false;
            }

            long lngTicks = 0;
            /// <summary>
            /// time at which event is to occur - changing Ticks inserts it into the Controller's list 
            /// </summary>
            public long Ticks
            {
                get { return lngTicks; }
                set
                {
                    lngTicks = value;
                    cEventController.EventTicks_Changed((object)this, new EventArgs());
                }
            }


            long lngTicks_ConditionTestDelay = 0;
            /// <summary>
            /// time at which event is to occur
            /// </summary>
            public long Ticks_ConditionTestDelay
            {
                get { return lngTicks_ConditionTestDelay; }
                set { lngTicks_ConditionTestDelay = value; }
            }


            public long Milliseconds_ConditionTestDelay
            {
                get { return lngTicks_ConditionTestDelay / lngTicksPerMilliSecond; }
                set
                {
                    lngTicks_ConditionTestDelay = lngTicksPerMilliSecond * value;
                }
            }

        }
    }
}