using System;
using System.Collections.Generic;
using System.Linq;

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

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

        public 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();
            }
        }

        public void timer_Init()
        {
            if (timer != null)
            {
                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)
        {
            //if (!formWords.bolClosing)
            //{
            //    //    timer_Init();
            //}
        }

        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;
            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();
        
        private void Timer_Tick(object sender, EventArgs e)
        {
            dt_LastTick = DateTime.Now;

            System.Windows.Forms.Timer tmrSender = (System.Windows.Forms.Timer)sender;
            tmrSender.Enabled = false;
            try
            {
                DateTime dtNow = DateTime.Now;
                DateTime dtDebug = DateTime.Now;

                lstTickets = lstTickets.Distinct().ToList<classEventController.classEventTicket>();

                while (lstTickets.Count > 0 && lstTickets[0].Ticks < dtNow.Ticks)
                {
                    dtDebug = DateTime.Now;

                    cTicketBeingHandled = lstTickets[0];
                    lstTickets.RemoveAt(0);
                    if (!cTicketBeingHandled.Quit)
                    {
                        cTicketBeingHandled.ExecuteEvent();
                    }
                    if (cTicketBeingHandled.AutoRepeat)
                        cTicketBeingHandled.Reschedule();
                    else if (cTicketBeingHandled.EventTicket_FSM_Next != null)
                    {
                        cTicketBeingHandled.EventTicket_FSM_Next.Reschedule();
                    }

                    TimeSpan tsElapsed = dtNow - dtDebug;
                }

                ReorderTickets();

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

            //DateTime dtNow = DateTime.Now;
            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 = ptAddress.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 intptAddress_Counter = 0;

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

            int _intptAddress = intptAddress_Counter++;
            public int ptAddress
            {
                get { return _intptAddress; }
            }

            //public classKeyCommand _KeyCommand = null;
            //public classKeyCommand cKeyCommand
            //{
            //    get { return _KeyCommand; }
            //    set { _KeyCommand = value; }
            //}

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

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

        }
    }
}