private void Model_ClockRemoved(object sender, ClockEventArgs e)
        {
            var td = e.Clock as TimerData;

            if (td == null)
            {
                return;
            }

            ClockVM vm = MyDataFile.ClockVMCollection.VMForM(td);

            bool          active = true;
            ClockMenuItem tmi    = ExistingClockMenuItemInActiveMenu(vm);

            if (tmi == null)
            {
                active = false;
                //tmi = ExistingClockMenuItemInInactiveMenu(vm);
            }
            if (tmi != null)
            {
                if (active)
                {
                    Items.Remove(tmi);
                }
                else
                {
                    //MyInactiveMenuItem.Items.Remove(tmi);
                }
            }

            UpdateSeparatorsVisibility();
        }
 internal void UnsubscribeFromClock(ClockVM cd)
 {
     if (cd.Model is TimerData td)
     {
         td.TimerStopped -= Td_TimerStopped;
     }
     cd.ClockTypeChanged -= Cd_ClockTypeChanged;
 }
 internal void SubscribeToClock(ClockVM cd)
 {
     if (cd.Model is TimerData td)
     {
         td.TimerStopped += Td_TimerStopped;
     }
     cd.ClockTypeChanged += Cd_ClockTypeChanged;
 }
        internal ClockVM ClockMin(ClockVM a, ClockVM b)
        {
            if (a == null)
            {
                return(b);
            }
            if (b == null)
            {
                return(a);
            }

            if (a.ClockType == b.ClockType &&
                a.ClockType == ClockVM.ClockTypes.Timer)
            {
                if (a.CurrentTimeSpan < b.CurrentTimeSpan)
                {
                    return(a);
                }
                return(b);
            }

            if (a.ClockType == ClockVM.ClockTypes.Timer &&
                b.ClockType == ClockVM.ClockTypes.Alarm)
            {
                if (DateTime.Now + a.CurrentTimeSpan < b.CurrentDateTime)
                {
                    return(a);
                }
                if (b.CurrentDateTime < DateTime.Now)
                {
                    return(a);
                }
                return(b);
            }

            if (b.ClockType == ClockVM.ClockTypes.Alarm &&
                a.ClockType == ClockVM.ClockTypes.Timer)
            {
                if (DateTime.Now + b.CurrentTimeSpan < a.CurrentDateTime)
                {
                    return(b);
                }
                if (a.CurrentDateTime < DateTime.Now)
                {
                    return(b);
                }
                return(a);
            }

            return(a);
        }
        internal bool AlreadyExistsInMenus(ClockVM cd)
        {
            if (ExistingClockMenuItemInActiveMenu(cd) != null)
            {
                return(true);
            }

            //if (ExistingClockMenuItemInInactiveMenu(cd) != null)
            //{
            //    return true;
            //}

            return(false);
        }
        //private ClockMenuItem ExistingClockMenuItemInInactiveMenu(ClockVM td)
        //{
        //for (int i = 0; i < MyInactiveMenuItem.Items.Count; ++i)
        //{
        //    if (MyInactiveMenuItem.Items[i] is ClockMenuItem tmi)
        //    {
        //        if (ReferenceEquals(td, tmi.DataContext))
        //        {
        //            return tmi;
        //        }
        //    }
        //}
        //return null;
        //}

        private ClockMenuItem ExistingClockMenuItemInActiveMenu(ClockVM td)
        {
            for (int i = 0; i < Items.Count; ++i)
            {
                if (Items[i] is ClockMenuItem tmi)
                {
                    if (ReferenceEquals(td, tmi.DataContext))
                    {
                        return(tmi);
                    }
                }
            }
            return(null);
        }
        private void Model_ClockMoved(object sender, ClockMovedEventArgs e)
        {
            var td = e.Clock as TimerData;

            if (td == null)
            {
                return;
            }

            ClockVM vm = MyDataFile.ClockVMCollection.VMForM(td);

            bool          active = true;
            ClockMenuItem tmi    = ExistingClockMenuItemInActiveMenu(vm);

            //if (tmi == null)
            //{
            //    active = false;
            //    tmi = ExistingClockMenuItemInInactiveMenu(vm);
            //}
            if (tmi != null)
            {
                // TODO: What if e.NewIndex does not care about FilteredOut property of ClockData?

                //if (active)
                //{
                Items.Remove(tmi);

                int idx = Math.Min(e.NewIndex, Items.Count);

                Items.Insert(idx, tmi);
                //}
                //else
                //{
                //    MyInactiveMenuItem.Items.Remove(tmi);

                //    int idx = Math.Min(e.NewIndex, MyInactiveMenuItem.Items.Count);

                //    MyInactiveMenuItem.Items.Insert(idx, tmi);
                //}
            }
        }
        internal void FullUpdateOfClosestRingingMomentClock()
        {
            ClockVM cvm = null;

            for (int i = 0; i < Model.Count; ++i)
            {
                ClockVM vm = VMForM(Model.Ms[i]);
                if (vm == null)
                {
                    // TODO: this case should not exist (verify:
                    // change timer to alarm in menu of a
                    // ClockUserControl.xaml) after a file is loaded.
                    continue;
                }
                if (vm.IsActive)
                {
                    cvm = ClockMin(cvm, vm);
                }
            }
            ClosestRingingMomentClockVM = cvm;
        }
        private void Model_ClockAdded(object sender, ClockEventArgs e)
        {
            if (e.Clock is TimerData tdd)
            {
                ClockVM vm = MyDataFile.ClockVMCollection.VMForM(tdd);

                var tmi = new ClockMenuItem();
                tmi.DataContext = vm;
                if (tdd.Running)
                {
                    AddTimerMenuItemToMainMenu(tmi);
                }
                else
                {
                    AddTimerMenuItemToMainMenu(tmi);
                    //MyInactiveMenuItem.Items.Insert(0, tmi);
                }
            }

            UpdateSeparatorsVisibility();
        }
        internal void RingPassedAlarms()
        {
            if (VMs == null)
            {
                return;
            }

            for (int i = VMs.Count - 1; i >= 0; --i)
            {
                ClockVM cd = VMs[i];

                if (cd.Enabled && cd.ClockType == ClockVM.ClockTypes.Alarm)
                {
                    var ad = cd.Model as AlarmData;
                    if (ad.CurrentDateTime <= DateTime.Now)
                    {
                        ad.Enabled = false;
                        ad.ShowTimeOutForm();
                    }
                }
            }
        }
        internal void HandleClockRemoval(ClockM c)
        {
            var td = c as TimerData;

            if (td == null)
            {
                return;
            }

            ClockVM vm = MyDataFile.ClockVMCollection.VMForM(td);

            ClockMenuItem tmi = ExistingClockMenuItemInActiveMenu(vm);

            if (tmi != null)
            {
                //tmi.UpdateImage();
                //ToolStrip p = tmi.Owner;
                //Items.Remove(tmi);
                //MyInactiveMenuItem.Items.Insert(0, tmi);
            }

            UpdateSeparatorsVisibility();
        }
        private void Model_ClocksAdded(object sender, ClocksEventArgs e)
        {
            foreach (ClockM m in e.Clocks)
            {
                ClockVM vm = MyDataFile.ClockVMCollection.VMForM(m);

                if (m is TimerData tdd)
                {
                    var tmi = new ClockMenuItem();
                    tmi.DataContext = vm;
                    //if (tdd.Running)
                    //{
                    AddTimerMenuItemToMainMenu(tmi);
                    //}
                    //else
                    //{
                    //    MyInactiveMenuItem.Items.Insert(0, tmi);
                    //}
                }
            }

            UpdateSeparatorsVisibility();
        }
        // TODO: set MToVM also in synching coded reacting to VM collection change.

        private void Ms_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (SynchDisabled)
            {
                return;
            }
            SynchDisabled = true;

            if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (ClockM m in e.OldItems)
                {
                    UpdateClosestRingingMomentClockBasedOnChangedClock(m);
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                foreach (ClockVM vm in VMs)
                {
                    vm.ClockTypeChanged -= ClockVMCollection_ClockTypeChanged;
                }
                MToVM.Clear();
                SelectedClocks.Clear();
            }

            Utils.SynchronizeCollectionChange(Model.Ms, e, VMs,
                                              (ClockVM vm) =>
            {
            },
                                              (ClockM m) =>
            {
                VMForM(m).ClockTypeChanged -= ClockVMCollection_ClockTypeChanged;
            },
                                              (ClockM m, ClockVM vm) =>
            {
                return(ReferenceEquals(vm.Model, m));
            },
                                              (ClockM m) =>
            {
                int idx = Model.Ms.IndexOf(x => ReferenceEquals(x, m));     // ClockVM subclasses ClockM
                if (0 <= idx && idx <= Model.Ms.Count - 1)
                {
                    MToVM[m] = new ClockVM(m, this);
                    MToVM[m].ClockTypeChanged += ClockVMCollection_ClockTypeChanged;
                    //VMs.Insert(idx, MToVM[m]);
                    return(MToVM[m]);
                }
                return(null);

                //// indicele 1
                //int idx = Model.Ms.IndexOf(x => ReferenceEquals(x, m)); // ClockVM subclasses ClockM
                //if (!(idx >= 0 && idx <= Model.Ms.Count - 1))
                //{
                //    // indicele 2
                //    if (MToVM.ContainsKey(m))
                //    {
                //        idx = MToVM.Keys.ToList().IndexOf(m);

                //        MToVM[m] = new ClockVM(m, this);
                //        MToVM[m].ClockTypeChanged += ClockVMCollection_ClockTypeChanged;
                //        //VMs.Insert(idx, MToVM[m]);
                //        return MToVM[m];
                //    }
                //    return null;
                //}
                //return null;
            });

            if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (ClockM m in e.OldItems)
                {
                    SelectedClocks.RemoveReference(x => object.ReferenceEquals(VMForM(m), x));
                }
            }

            //switch (e.Action)
            //{
            //    case NotifyCollectionChangedAction.Add:
            //foreach (object item in e.NewItems)
            //{
            //    var mItem = (ClockM)item;
            //    int idx = Model.Ms.IndexOf(x => x == mItem);

            //    MToVM[mItem] = new ClockVM(mItem, this);

            //    MToVM[mItem].ClockTypeChanged += ClockVMCollection_ClockTypeChanged;

            //    // the operation could have been either Insert or Add
            //    if (0 <= idx && idx <= Model.Ms.Count - 1)
            //    {
            //        VMs.Insert(idx, MToVM[mItem]);
            //    }
            //    else
            //    {
            //        VMs.Add(MToVM[mItem]);

            //        if (mItem.Checked && !mItem.FilteredOut)
            //        {
            //            SelectedClocks.Add(MToVM[mItem]);
            //        }
            //    }
            //}
            //break;

            //    case NotifyCollectionChangedAction.Remove:
            //        foreach (object item in e.OldItems)
            //        {
            //            var mItem = item as ClockM;

            //            UpdateClosestRingingMomentClockBasedOnChangedClock(mItem);

            //            // find VM objects that wrap the relevant model object and remove them
            //            IEnumerable<ClockVM> query;
            //            while ((query = from vm in VMs
            //                            where ReferenceEquals(vm.Model, mItem)
            //                            select vm).Count() > 0)
            //            {
            //                ClockVM m = query.First();

            //                m.ClockTypeChanged -= ClockVMCollection_ClockTypeChanged;


            //                int index = VMs.IndexOf(m);
            //                VMs.Remove(x => ReferenceEquals(x, m));

            //                MToVM.Remove(mItem);
            //            }

            //            SelectedClocks.Remove(VMForM(mItem));
            //        }
            //        break;

            //    case NotifyCollectionChangedAction.Reset:
            //        foreach (ClockVM vm in VMs)
            //        {
            //            vm.ClockTypeChanged -= ClockVMCollection_ClockTypeChanged;
            //        }
            //        MToVM.Clear();
            //        VMs.Clear();
            //        SelectedClocks.Clear();
            //        break;

            //    case NotifyCollectionChangedAction.Move:
            //        // TODO: handle multiple items
            //        VMs.Move(e.OldStartingIndex, e.NewStartingIndex);
            //        break;

            //    case NotifyCollectionChangedAction.Replace:
            //        // TODO: handle multiple items
            //        var cm = (ClockM)e.NewItems[0];
            //        var cvm = new ClockVM(cm, this);
            //        VMs[e.OldStartingIndex] = cvm;
            //        MToVM[cm] = cvm;
            //        break;

            //    default:
            //        throw new NotImplementedException();
            //}

            SynchDisabled = false;
        }