private int FindFirstEmptyActivePTSetIndex()
        {
            for (int idx = 0; idx < activeSetItemTrackerArrayLength; idx++)
            {
                ActiveSetItemTracker activeSetItemTracker = activeSetItemTrackerArray[idx];
                if (activeSetItemTracker != null && activeSetItemTracker.ProcessTracker == null)
                {
                    return(idx);
                }
            }

            return(-1);
        }
        private void Activate(ProcessTracker pt, int activeSetIdx)
        {
            MDRF.Common.DateTimeStampPair dtPair = MDRF.Common.DateTimeStampPair.Now;

            // if needed - deactivate the previous pt in the given index
            ActiveSetItemTracker activeSetItemTracker = activeSetItemTrackerArray[activeSetIdx];

            ProcessTracker priorPT = activeSetItemTracker.ProcessTracker;

            if (priorPT != null)
            {
                // record the last set of values (and the map) from the old ProcessTracker before replacing them with the new values.
                activeSetItemTracker.GroupInfo.Touched = true;
                activeSetMapGroup.GroupInfo.Touched    = true;
                mdrfWriter.RecordGroups(dtPair: dtPair);

                string         deactivateReason    = "pid:{0} '{1}' is being {2}".CheckedFormat(pt.pid, pt.name, pt.elevationRequestReason.IsNullOrEmpty() ? "activated" : "elevated");
                INamedValueSet extraDeactivatedNVS = new NamedValueSet()
                {
                    { "deactivateReason", deactivateReason }, { "activeSetNum", activeSetIdx + 1 }
                }.MakeReadOnly();

                priorPT.activePTSetIndex = -1;
                RecordProcessEvent("Deactivated", priorPT, extraNVS: extraDeactivatedNVS, includeExtraProcessInfo: false, includeTrackedValues: true, dtPair: dtPair);
            }

            // now move the given pt into the active set at the selected index.

            INamedValueSet extraNVS = (pt.elevationRequestReason.IsNullOrEmpty() ? new NamedValueSet()
            {
                { "activeSetNum", activeSetIdx + 1 }
            } : new NamedValueSet()
            {
                { "elevateReason", pt.elevationRequestReason }, { "activeSetNum", activeSetIdx + 1 }
            }).MakeReadOnly();

            RecordProcessEvent("Activated", pt, extraNVS: extraNVS, includeExtraProcessInfo: false, includeTrackedValues: true, dtPair: dtPair);

            pt.activePTSetIndex = activeSetIdx;
            pt.activationBaselineTrackedValues  = pt.prevTrackedValues;
            activeSetItemTracker.ProcessTracker = pt;
            activeSetItemTracker.UpdateGroupItems();
            activeSetItemTracker.GroupInfo.Touched = true;

            activeSetMapGroup.Update(activeSetIdx, pt.pid, pt.name);

            mdrfWriter.RecordGroups(dtPair: dtPair);
        }
        private void RecordProcessRemoved(ProcessTracker pt, string reason)
        {
            trackedProcessDictionary.Remove(pt.pid);
            ptSetArray = null;

            if (pt.IsInActiveSet)
            {
                activeSetMapGroup.Update(pt.activePTSetIndex, 0, "");

                ActiveSetItemTracker activeSetItemTracker = activeSetItemTrackerArray[pt.activePTSetIndex];

                activeSetItemTracker.ProcessTracker    = null;
                activeSetItemTracker.GroupInfo.Touched = true;
                pt.activePTSetIndex = -1;
            }

            INamedValueSet extraNVS = new NamedValueSet()
            {
                { "reason", reason }
            }.MakeReadOnly();

            RecordProcessEvent("Removed", pt, includeExtraProcessInfo: false, includeTrackedValues: true);
        }