/****************************** Module Header ******************************\
* Module Name:  classEventController.cs 
* Christ King Kennedy, B.Eng.
* 20250111 1321 
* 
* This class tries to mimick Microsoft's System.Forms.Timer object 
*             it uses 2x MS Timers to control 
*             and a list of subclass classEventTicket 
*              1) the first MS _Tick() event handler 
*                    cycles through existing 'tickets'  
*                    executing events siimler to system.forms.timer _Tick
*              2) crash catcher to reset 1) timer when in forever loop 
*   - centralizes all your project's MS Timer's 
*           - simplifies their event scheduling and debugging.
* 
* This sourcecode is open source 
* See www.ChristKennedy.com 
\***************************************************************************/

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

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.Interval = 100;
            // */

            timer.Tick += Timer_Tick;
            timer.Disposed += Timer_Disposed;
        }

        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.Windows.Forms.Timer tmrTimer_RestartTimer = new System.Windows.Forms.Timer();
        static int _intGraphicsRefreshLoopCounter = 0;
     

        bool bolCapsLockState = false;
        int intLoopCounter = 0;
        private void Timer_Tick(object sender, EventArgs e)
        {
            intLoopCounter = (intLoopCounter + 1) % 10;

            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;
                //foreach (panelEditor pnl in panelEditor.lst)
                //    pnl.NeedsRefresh = false;

                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;
                }
            }

        }
    }
}