Example #1
0
        private bool ParseCallbackSettingsXML()
        {
            Trace.TraceInformation("Enter.");

            try
            {
                if (xmlDoc == null)
                {
                    Trace.TraceWarning("xmlDoc is null.");
                    return(false);
                }

                System.Xml.XmlNodeReader reader = new System.Xml.XmlNodeReader(xmlDoc);

                List <CallbackContactServiceQueue> _TempQueues = new List <CallbackContactServiceQueue>();

                CallbackContactServiceQueue _cbCSQ = null;
                CallbackContactServiceQueueSettingsProfile _profile = null;

                CallbackBackupCSQ       _bckCSQ = null;
                CallbackAlgorithmFilter _filter = null;

                bool bAcceptCallbacksTimeframeElementEnded = true;
                bool bCallbackProcessingTimeframeEnded     = true;

                bool bCallbackReentryAlgorithmElementBegan = false;
                bool bCallbackOfferedAlgorithmElementBegan = false;

                while (reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case System.Xml.XmlNodeType.Element:

                        if (reader.Name.Equals("csq"))
                        {
                            _cbCSQ = new CallbackContactServiceQueue();

                            _cbCSQ.Name = reader.GetAttribute("name");

                            bCallbackReentryAlgorithmElementBegan = false;
                            bCallbackOfferedAlgorithmElementBegan = false;
                        }

                        if (reader.Name.Equals("CallbackEnabled"))
                        {
                            try
                            {
                                _cbCSQ.CallbackEnabled = bool.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _cbCSQ.CallbackEnabled = false;
                            }
                        }

                        if (reader.Name.Equals("CallerRecording"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.CallerRecording = bool.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.CallerRecording = false;
                            }
                        }

                        if (reader.Name.Equals("RetentionPeriod"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.RetentionPeriod = int.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.RetentionPeriod = 7;
                            }
                        }

                        if (reader.Name.Equals("AppServerURLPrefix"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            _profile.AppServerURLPrefix = reader.ReadString();
                        }

                        if (reader.Name.Equals("EmailAlerts"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.EmailAlerts = bool.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.EmailAlerts = false;
                            }
                        }

                        if (reader.Name.Equals("AdminEmail"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            _profile.AdminEmail = reader.ReadString();
                        }

                        if (reader.Name.Equals("CallerIDVerify"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.CallerIDVerify = bool.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.CallerIDVerify = false;
                            }
                        }

                        if (reader.Name.Equals("AbandonCallback"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.AbandonCallback = bool.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.AbandonCallback = false;
                            }
                        }

                        if (reader.Name.Equals("AbandonCBMinQTime"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.AbandonCBMinQTime = int.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.AbandonCBMinQTime = 0;
                            }
                        }

                        if (reader.Name.Equals("AbandonCBMinInterCallTime"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.AbandonCBMinInterCallTime = int.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.AbandonCBMinInterCallTime = 0;
                            }
                        }

                        if (reader.Name.Equals("CBQueue"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            _bckCSQ = new CallbackBackupCSQ();

                            _bckCSQ.Name = reader.GetAttribute("csq");

                            try
                            {
                                _bckCSQ.OverflowTime = int.Parse(reader.GetAttribute("overflowtime"));
                            }
                            catch
                            {
                                _bckCSQ.OverflowTime = 0;
                            }

                            _profile.BackupCSQs.Add(_bckCSQ);

                            _bckCSQ = null;
                        }

                        if (reader.Name.Equals("AcceptCallbacksTimeframe"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            bAcceptCallbacksTimeframeElementEnded = false;
                        }

                        if (reader.Name.Equals("Begin"))
                        {
                            if (!bAcceptCallbacksTimeframeElementEnded)
                            {
                                _profile.AcceptCallbacksTimeframeBegin = reader.ReadString();
                            }

                            if (!bCallbackProcessingTimeframeEnded)
                            {
                                _profile.CallbackProcessingTimeframeBegin = reader.ReadString();
                            }
                        }

                        if (reader.Name.Equals("End"))
                        {
                            if (!bAcceptCallbacksTimeframeElementEnded)
                            {
                                _profile.AcceptCallbacksTimeframeEnd = reader.ReadString();
                            }

                            if (!bCallbackProcessingTimeframeEnded)
                            {
                                _profile.CallbackProcessingTimeframeEnd = reader.ReadString();
                            }
                        }

                        if (reader.Name.Equals("CallbackOfferedAlgorithm"))
                        {
                            bCallbackOfferedAlgorithmElementBegan = true;
                        }

                        if (reader.Name.Equals("CallbackReentryAlgorithm"))
                        {
                            bCallbackReentryAlgorithmElementBegan = true;
                        }

                        if (reader.Name.Equals("TotalInQueue") ||
                            reader.Name.Equals("CSQAgentsReady") ||
                            reader.Name.Equals("CSQCallsWaiting") ||
                            reader.Name.Equals("AgentsLoggedIn") ||
                            reader.Name.Equals("CallsWaiting") ||
                            reader.Name.Equals("LongestQueueTime") ||
                            reader.Name.Equals("CallbackRequests"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            _filter = new CallbackAlgorithmFilter();

                            _filter.Name = reader.Name;

                            try
                            {
                                _filter.Enabled = bool.Parse(reader.GetAttribute("Enabled"));
                            }
                            catch
                            {
                                _filter.Enabled = false;
                            }

                            _filter.Operation = reader.GetAttribute("Operation");

                            try
                            {
                                _filter.Value = int.Parse(reader.GetAttribute("Value"));
                            }
                            catch
                            {
                                _filter.Value = 0;
                            }

                            if (bCallbackOfferedAlgorithmElementBegan)
                            {
                                _profile.OfferedAlgorithmFilters.Add(_filter);
                            }

                            if (bCallbackReentryAlgorithmElementBegan)
                            {
                                _profile.ReentryAlgorithmFilters.Add(_filter);
                            }

                            _filter = null;
                        }

                        if (reader.Name.Equals("CallbackProcessingTimeframe"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            bCallbackProcessingTimeframeEnded = false;
                        }

                        if (reader.Name.Equals("EndOfDayPurgeCallbackRequests"))
                        {
                            if (_profile == null)
                            {
                                _profile = new CallbackContactServiceQueueSettingsProfile();
                            }

                            try
                            {
                                _profile.EndOfDayPurgeCallbackRequests = bool.Parse(reader.ReadString());
                            }
                            catch
                            {
                                _profile.EndOfDayPurgeCallbackRequests = false;
                            }
                        }

                        break;

                    case System.Xml.XmlNodeType.EndElement:

                        if (reader.Name.Equals("csq"))
                        {
                            if (_cbCSQ != null)
                            {
                                _cbCSQ.Profile = _profile;
                                _TempQueues.Add(_cbCSQ);
                            }
                            else
                            {
                                Trace.TraceWarning("CSQ was not added to list because _cbCSQ is null.");
                            }

                            _profile = null;
                            _cbCSQ   = null;
                        }

                        if (reader.Name.Equals("CallbackReentryAlgorithm"))
                        {
                            bCallbackReentryAlgorithmElementBegan = false;
                        }

                        if (reader.Name.Equals("AcceptCallbacksTimeframe"))
                        {
                            bAcceptCallbacksTimeframeElementEnded = true;
                        }

                        if (reader.Name.Equals("CallbackOfferedAlgorithm"))
                        {
                            bCallbackOfferedAlgorithmElementBegan = false;
                        }

                        if (reader.Name.Equals("CallbackProcessingTimeframe"))
                        {
                            bCallbackProcessingTimeframeEnded = true;
                        }

                        break;
                    } //switch (reader.NodeType)
                }     //while (reader.Read())

                reader.Close();
                reader = null;

                xmlDoc = null;

                _Queues = _TempQueues;

                _TempQueues = null;
                _profile    = null;
                _cbCSQ      = null;

                return(true);
            }
            catch (Exception ex)
            {
                Trace.TraceError("Exception:" + ex.Message + Environment.NewLine + "StackTrace:" + ex.StackTrace);
                xmlDoc = null;
                return(false);
            }
        }
        public bool Analyse(ContactServiceQueueInformation Information, CallbackContactServiceQueueSettingsProfile Profile, CallbackRecordManager RecordManager)
        {
            Trace.TraceInformation("Enter.");

            try
            {
                if (Information == null)
                {
                    _Description = "Information is null.";
                    Trace.TraceWarning("Information is null.");
                    return(false);
                }

                if (Profile == null)
                {
                    _Description = "Profile is null.";
                    Trace.TraceWarning("Profile is null.");
                    return(false);
                }

                if (RecordManager == null)
                {
                    _Description = "RecordManager is null.";
                    Trace.TraceWarning("RecordManager is null.");
                    return(false);
                }

                bool bResult = true;

                foreach (CallbackAlgorithmFilter filter in Profile.OfferedAlgorithmFilters)
                {
                    if (filter.Enabled)
                    {
                        try
                        {
                            Constants.FilterOperations Operation = Constants.FilterOperations.BIGGERTHANOREQUALTO;

                            Operation = (Constants.FilterOperations)Enum.Parse(typeof(Constants.FilterOperations), filter.Operation.ToUpper());

                            switch (filter.Name)
                            {
                            case "AgentsLoggedIn":

                                switch (Operation)
                                {
                                case Constants.FilterOperations.BIGGERTHANOREQUALTO:

                                    if (Information.AgentsLoggedIn >= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has less than " + filter.Value + " agents logged in.";
                                        bResult      = bResult && false;
                                    }

                                    break;

                                case Constants.FilterOperations.SMALLERTHANOREQUALTO:

                                    if (Information.AgentsLoggedIn <= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has more than " + filter.Value + " agents logged in.";
                                        bResult      = bResult && false;
                                    }

                                    break;
                                }

                                break;

                            case "CallsWaiting":

                                switch (Operation)
                                {
                                case Constants.FilterOperations.BIGGERTHANOREQUALTO:

                                    if (Information.ContactsWaiting >= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has less than " + filter.Value + " calls waiting.";
                                        bResult      = bResult && false;
                                    }

                                    break;

                                case Constants.FilterOperations.SMALLERTHANOREQUALTO:

                                    if (Information.ContactsWaiting <= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has more than " + filter.Value + " calls waiting.";
                                        bResult      = bResult && false;
                                    }

                                    break;
                                }

                                break;

                            case "LongestQueueTime":

                                switch (Operation)
                                {
                                case Constants.FilterOperations.BIGGERTHANOREQUALTO:

                                    if (Information.LongestWaitingContact >= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has longest queue time less than " + filter.Value;
                                        bResult      = bResult && false;
                                    }

                                    break;

                                case Constants.FilterOperations.SMALLERTHANOREQUALTO:

                                    if (Information.LongestWaitingContact <= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has longest queue time more than " + filter.Value;
                                        bResult      = bResult && false;
                                    }

                                    break;
                                }

                                break;

                            case "CallbackRequests":

                                switch (Operation)
                                {
                                case Constants.FilterOperations.BIGGERTHANOREQUALTO:

                                    if (RecordManager.NumberOfRecordsForQueue(Information.Name) >= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has fewer than " + filter.Value + " callback requests.";
                                        bResult      = bResult && false;
                                    }

                                    break;

                                case Constants.FilterOperations.SMALLERTHANOREQUALTO:

                                    if (RecordManager.NumberOfRecordsForQueue(Information.Name) <= filter.Value)
                                    {
                                        bResult = bResult && true;
                                    }
                                    else
                                    {
                                        _Description = "CSQ " + Information.Name + " has more than " + filter.Value + " callback requests:" + RecordManager.NumberOfRecordsForQueue(Information.Name);
                                        bResult      = bResult && false;
                                    }

                                    break;
                                }

                                break;

                            default:

                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            _Description = "Exception performing algorithm comparisons.";
                            Trace.TraceWarning("Exception: " + ex.Message + Environment.NewLine + "Stacktrace: " + ex.StackTrace);
                            bResult = false;
                        }
                    }
                }

                return(bResult);
            }
            catch (Exception ex)
            {
                _Description = "Exception running callback offer algorithm.";
                Trace.TraceWarning("Exception: " + ex.Message + Environment.NewLine + "Stacktrace: " + ex.StackTrace);
                return(false);
            }
        }
 public CallbackContactServiceQueue()
 {
     _CallbackEnabled = false;
     _Name            = String.Empty;
     _Profile         = null;
 }
        void _tmrTick_Tick(object State)
        {
            Trace.TraceInformation("Enter.");

            lock (objLock)
            {
                _tmrTick.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

                DateTime dtBegin = DateTime.Now;

                if (_settingsManager == null)
                {
                    Trace.TraceWarning("_settingsManager is null.");
                    _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
                    return;
                }

                if (_settingsManager.ApplicationSettings == null)
                {
                    Trace.TraceWarning("_settingsManager.ApplicationSettings is null.");
                    _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
                    return;
                }

                if (_settingsManager.CallbackSettings == null)
                {
                    Trace.TraceWarning("_settingsManager.CallbackSettings is null.");
                    _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
                    return;
                }

                if (!_settingsManager.UCCXMasterNodeDetected)
                {
                    Trace.TraceWarning("_settingsManager.UCCXMasterNodeDetected is false; no UCCX Master Node has been detected.");
                    _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
                    return;
                }

                if (_recordManager == null)
                {
                    Trace.TraceWarning("_recordManager is null.");
                    _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
                    return;
                }

                if (_recordManager.GetRecordCount() == 0)
                {
                    _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
                    return;
                }

                try
                {
                    //Task #1: Detect day boundary crossing, check end of day purge and flag records

                    DateTime _CurrentTick = DateTime.Now;

                    bool _DayBoundaryCrossed = false;

                    if (!(_CurrentTick.Year == _LastTick.Year && _CurrentTick.Month == _LastTick.Month && _CurrentTick.Day == _LastTick.Day))
                    {
                        Trace.TraceInformation("Day bounderay was crossed.");
                        _DayBoundaryCrossed = true;
                    }

                    _LastTick = _CurrentTick;

                    foreach (CallbackRecord record in _recordManager.Records)
                    {
                        String sCSQ = record.TargetCSQ;

                        CallbackContactServiceQueue _queue = null;

                        foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)
                        {
                            if (sCSQ == queue.Name)
                            {
                                _queue = queue;
                                break;
                            }
                        }//foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)

                        if (_queue != null)
                        {
                            CallbackContactServiceQueueSettingsProfile _Profile = null;

                            if (_queue.Profile == null)
                            {
                                foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)
                                {
                                    if (queue.Name == "Default")
                                    {
                                        _Profile = queue.Profile;
                                        break;
                                    }
                                }//foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)
                            }
                            else
                            {
                                _Profile = _queue.Profile;
                            }

                            if (_Profile != null)
                            {
                                if (_DayBoundaryCrossed)
                                {
                                    record.CallbackProcessingTimeframeEndCrossed = false;

                                    Trace.TraceInformation("CallbackProcessingTimeframeEndCrossed set to false for record " + record.ID);
                                }
                                else
                                {
                                    //Trace.TraceInformation("CallbackProcessingTimeframeEndCrossed was not set for record " + record.ID);
                                }

                                DateTime dtCallbackProcessingTimeframeEnd = DateTime.ParseExact(_Profile.CallbackProcessingTimeframeEnd, "HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);

                                if (!record.CallbackProcessingTimeframeEndCrossed)
                                {
                                    //Trace.TraceInformation("CallbackProcessingTimeframeEndCrossed is false for record " + record.ID);

                                    if (DateTime.Now.Subtract(dtCallbackProcessingTimeframeEnd).TotalMilliseconds >= 0)
                                    {
                                        Trace.TraceInformation("Now is after dtCallbackProcessingTimeframeEnd for record " + record.ID);

                                        record.CallbackProcessingTimeframeEndCrossed = true;
                                        record.ReportOn = true;

                                        //Check record age; mark purge if older than maximum number of days
                                        if (DateTime.Now.Subtract(record.RequestDate).TotalDays > _settingsManager.ApplicationSettings.MaximumNumberOfDays)
                                        {
                                            record.Purge         = true;
                                            record.PurgeDueToAge = true;
                                            Trace.TraceInformation("Record " + record.ID + " is " + record.Status + " and was marked for end of day purging due to record age.");
                                        }

                                        if (record.Status == Constants.RecordStatus.INVALID ||
                                            record.Status == Constants.RecordStatus.INACTIVE ||
                                            record.Status == Constants.RecordStatus.EXCEEDEDNUMBEROFATTEMPTS ||
                                            record.Status == Constants.RecordStatus.COMPLETED)
                                        {
                                            record.Purge = true;
                                            Trace.TraceInformation("Record " + record.ID + " is " + record.Status + " and was marked for end of day purging due to status");
                                        }

                                        if (record.Status == Constants.RecordStatus.NEW ||
                                            record.Status == Constants.RecordStatus.RETRY ||
                                            record.Status == Constants.RecordStatus.FORCERETRY)
                                        {
                                            if (_Profile.EndOfDayPurgeCallbackRequests)
                                            {
                                                record.Purge = true;
                                                Trace.TraceInformation("Record " + record.ID + " is " + record.Status + " and was marked for end of day purging due to status");
                                            }
                                            else
                                            {
                                                record.Status = Constants.RecordStatus.PURGED;

                                                Trace.TraceInformation("Record " + record.ID + " was marked " + record.Status);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        //Trace.TraceInformation("Now is not after dtCallbackProcessingTimeframeEnd for record " + record.ID);
                                    }
                                }
                                else
                                {
                                    Trace.TraceInformation("CallbackProcessingTimeframeEndCrossed is true for record " + record.ID);
                                }
                            } //if (_Profile != null)
                        }     //if (_queue != null)
                    }         //foreach (CallbackRecord record in _recordManager.Records)

                    //Task #2: Remove records where purge is true from _recordManager.Records

                    if (_recordManager.Purge())
                    {
                        Trace.TraceInformation("_recordManager.Purge() returned true.");
                    }
                    else
                    {
                        Trace.TraceWarning("_recordManager.Purge() returned false.");
                    }

                    //This code is temporary, until a inactive cache is built
                    if (_recordManager.RemoveRecordsInFinalState())
                    {
                        Trace.TraceInformation("_recordManager.RemoveRecordsInFinalState() returned true.");
                    }
                    else
                    {
                        Trace.TraceWarning("_recordManager.RemoveRecordsInFinalState() returned false.");
                    }
                    //This code is temporary, until a inactive cache is built

                    if (_recordManager.StatusReport())
                    {
                        Trace.TraceInformation("_recordManager.StatusReport() returned true.");
                    }
                    else
                    {
                        Trace.TraceWarning("_recordManager.StatusReport() returned false.");
                    }

                    if (_recordManager.NumberOfActionableRecords() == 0)
                    {
                        Trace.TraceWarning("_recordManager.NumberOfActionableRecords() is 0; ");
                        _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
                        return;
                    }

                    if (DateTime.Now.Subtract(_RealtimeDataClient.LastRealtimeDataCollectedAt).TotalMilliseconds > Constants.CONTACT_REALTIMEDATE_REFRESH)
                    {
                        Trace.TraceWarning("Last RealtimeData refresh was at : " + _RealtimeDataClient.LastRealtimeDataCollectedAt);
                    }

                    //Task #3:

                    String sErrorDescription = String.Empty;

                    foreach (CallbackRecord record in _recordManager.Records)
                    {
                        double dInactiveTime = 0;

                        switch (record.Status)
                        {
                        case Constants.RecordStatus.NEW:

                            break;

                        case Constants.RecordStatus.PURGED:

                            break;

                        case Constants.RecordStatus.RETRY:

                            break;

                        case Constants.RecordStatus.INVALID:

                            continue;

                        case Constants.RecordStatus.INACTIVE:

                            continue;

                        case Constants.RecordStatus.COMPLETED:

                            continue;

                        case Constants.RecordStatus.EXCEEDEDNUMBEROFATTEMPTS:

                            continue;

                        case Constants.RecordStatus.PROCESSING:

                            dInactiveTime = DateTime.Now.Subtract(record.StatusLastUpdated).TotalSeconds;

                            if (dInactiveTime >= Constants.STATUSUPDATEINACTIVITY)
                            {
                                sErrorDescription = String.Empty;

                                if (_recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.RETRY, out sErrorDescription))
                                {
                                    Trace.TraceInformation("Record " + record.ID + " went from PROCESSING to " + record.Status + " because it was inactive for " + dInactiveTime.ToString());
                                }
                                else
                                {
                                    Trace.TraceWarning("Record " + record.ID + " did not go to RETRY. Current status:" + record.Status);
                                }
                            }

                            continue;

                        case Constants.RecordStatus.REQUESTED:

                            dInactiveTime = DateTime.Now.Subtract(record.StatusLastUpdated).TotalSeconds;

                            if (dInactiveTime >= Constants.STATUSUPDATEINACTIVITY)
                            {
                                sErrorDescription = String.Empty;

                                if (_recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.RETRY, out sErrorDescription))
                                {
                                    Trace.TraceInformation("Record " + record.ID + " went from REQUESTED to RETRY because it was inactive for " + dInactiveTime.ToString());
                                }
                                else
                                {
                                    Trace.TraceWarning("Record " + record.ID + " did not go to RETRY. Current status:" + record.Status);
                                }
                            }

                            continue;

                        case Constants.RecordStatus.QUEUED:

                            dInactiveTime = DateTime.Now.Subtract(record.StatusLastUpdated).TotalSeconds;

                            if (dInactiveTime >= Constants.STATUSUPDATEINACTIVITY)
                            {
                                sErrorDescription = String.Empty;

                                if (_recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.RETRY, out sErrorDescription))
                                {
                                    Trace.TraceInformation("Record " + record.ID + " went from " + record.Status + " to RETRY because it was inactive for " + dInactiveTime.ToString());
                                }
                                else
                                {
                                    Trace.TraceWarning("Record " + record.ID + " did not go to RETRY. Current status:" + record.Status);
                                }
                            }

                            continue;

                        case Constants.RecordStatus.DIALINGTARGET:

                            sErrorDescription = String.Empty;

                            if (_recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.COMPLETED, out sErrorDescription))
                            {
                                Trace.TraceInformation("Record " + record.ID + " went from DIALINGTARGET to " + record.Status);
                            }
                            else
                            {
                                Trace.TraceWarning("Record " + record.ID + " did not go to COMPLETED. Current status:" + record.Status);
                            }

                            continue;

                        case Constants.RecordStatus.AGENTACKNOWLEDGED:

                            dInactiveTime = DateTime.Now.Subtract(record.StatusLastUpdated).TotalSeconds;

                            if (dInactiveTime >= Constants.STATUSUPDATEINACTIVITY)
                            {
                                sErrorDescription = String.Empty;

                                if (_recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.RETRY, out sErrorDescription))
                                {
                                    Trace.TraceInformation("Record " + record.ID + " went from AGENTACKNOWLEDGED to " + record.Status + " because it was inactive for " + dInactiveTime.ToString());
                                }
                                else
                                {
                                    Trace.TraceWarning("Record " + record.ID + " did not go to RETRY. Current status:" + record.Status);
                                }
                            }

                            continue;

                        case Constants.RecordStatus.AGENTABANDONED:

                            sErrorDescription = String.Empty;

                            if (_recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.RETRY, out sErrorDescription))
                            {
                                Trace.TraceInformation("Record " + record.ID + " went from AGENTABANDONED to " + record.Status + " because it was inactive for " + dInactiveTime.ToString());
                            }
                            else
                            {
                                Trace.TraceWarning("Record " + record.ID + " did not go to RETRY. Current status:" + record.Status);
                            }

                            continue;

                        case Constants.RecordStatus.IVR_FAILURE:

                            sErrorDescription = String.Empty;

                            if (_recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.RETRY, out sErrorDescription))
                            {
                                Trace.TraceInformation("Record " + record.ID + " went from IVR_FAILURE to " + record.Status);
                            }
                            else
                            {
                                Trace.TraceWarning("Record " + record.ID + " did not go to RETRY. Current status:" + record.Status);
                            }

                            break;
                        }//switch (record.Status)

                        if (record.Status == Constants.RecordStatus.NEW ||
                            record.Status == Constants.RecordStatus.RETRY ||
                            record.Status == Constants.RecordStatus.PURGED)
                        {
                            //Assert NumberOFAttempts
                            if (record.Status == Constants.RecordStatus.RETRY)
                            {
                                if (record.NumberOfAttempts >= _settingsManager.ApplicationSettings.MaximumNumberOfAttempts)
                                {
                                    Trace.TraceInformation("Record " + record.ID + " has reached the maximum number of attempts:" + record.NumberOfAttempts);

                                    sErrorDescription = String.Empty;

                                    _recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.EXCEEDEDNUMBEROFATTEMPTS, out sErrorDescription);

                                    continue;
                                }

                                if (DateTime.Now.Subtract(record.StatusLastUpdated).TotalMinutes <= _settingsManager.ApplicationSettings.MinimumIntervalBetweenRetries)
                                {
                                    Trace.TraceInformation("Record  " + record.ID + " is in status:" + record.Status + " and has not yet waited " + _settingsManager.ApplicationSettings.MinimumIntervalBetweenRetries + " mins to be attempted again.");

                                    continue;
                                }
                            }

                            String sCSQ = record.TargetCSQ;

                            CallbackContactServiceQueue _queue = null;

                            foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)
                            {
                                if (sCSQ == queue.Name)
                                {
                                    _queue = queue;
                                    break;
                                }
                            }//foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)

                            if (_queue != null)
                            {
                                Trace.TraceInformation("Record " + record.ID + " Settings for CSQ " + sCSQ + " were found.");

                                CallbackContactServiceQueueSettingsProfile _Profile = null;

                                if (_queue.Profile == null)
                                {
                                    Trace.TraceInformation("Record " + record.ID + " Profile for CSQ " + sCSQ + " is null; look for default profile.");

                                    foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)
                                    {
                                        if (queue.Name == "Default")
                                        {
                                            _Profile = queue.Profile;
                                            break;
                                        }
                                    }//foreach (CallbackContactServiceQueue queue in _settingsManager.CallbackSettings.Queues)

                                    if (_Profile == null)
                                    {
                                        Trace.TraceWarning("Record " + record.ID + " Profile for CSQ " + sCSQ + " was not found. Flag record as invalid.");
                                        sErrorDescription = String.Empty;
                                        _recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.INVALID, out sErrorDescription);

                                        continue;
                                    }
                                    else
                                    {
                                        Trace.TraceInformation("Record " + record.ID + " Default Profile for CSQ " + sCSQ + " was found.");
                                    }
                                }
                                else
                                {
                                    Trace.TraceInformation("Record " + record.ID + " Profile for CSQ " + sCSQ + " is not null.");
                                    _Profile = _queue.Profile;
                                }

                                //Check profile settings:
                                if (_queue.CallbackEnabled)
                                {
                                    if (_Profile == null)
                                    {
                                        Trace.TraceWarning("Record " + record.ID + " _Profile is null.");
                                    }

                                    if (_Profile.CallbackProcessingTimeframeBegin == null)
                                    {
                                        Trace.TraceWarning("Record " + record.ID + " _Profile.CallbackProcessingTimeframeBegin is null.");
                                    }

                                    DateTime dtCallbackProcessingTimeframeBegin = DateTime.ParseExact(_Profile.CallbackProcessingTimeframeBegin, "HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
                                    DateTime dtCallbackProcessingTimeframeEnd   = DateTime.ParseExact(_Profile.CallbackProcessingTimeframeEnd, "HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);

                                    Trace.TraceInformation("Record " + record.ID + " dtCallbackProcessingTimeframeBegin = " + dtCallbackProcessingTimeframeBegin.ToString() + " Now = " + DateTime.Now.ToString());

                                    if (DateTime.Now.Subtract(dtCallbackProcessingTimeframeBegin).TotalMilliseconds >= 0)
                                    {
                                        Trace.TraceInformation("Record " + record.ID + " CallbackProcessingTimeframe has opened.");

                                        if (dtCallbackProcessingTimeframeEnd.Subtract(DateTime.Now).TotalMilliseconds >= 0)
                                        {
                                            Trace.TraceInformation("Record " + record.ID + " CallbackProcessingTimeframe has not yet closed.");

                                            double dNumberOfIVRPorts       = double.Parse(_settingsManager.ApplicationSettings.UCCXNumberOfIVRPorts);
                                            double dMaxIVRPortUsagePercent = double.Parse(_settingsManager.ApplicationSettings.UCCXMaxIVRPortUsagePercent);

                                            double bMaxIVRPortsAvailable = Math.Floor(dNumberOfIVRPorts * (dMaxIVRPortUsagePercent / 100.0));

                                            int iNumberOfContactsInIVR = _RealtimeDataClient.NumberOfContactsInIVR;

                                            if (bMaxIVRPortsAvailable > iNumberOfContactsInIVR)
                                            {
                                                Trace.TraceInformation("Record id " + record.ID + " Number of contacts in IVR: " + iNumberOfContactsInIVR.ToString() + " IVR Ports available to Callback Server: " + bMaxIVRPortsAvailable.ToString());

                                                if (_settingsManager.ApplicationSettings.BasicInsertionThrottling_Enabled)
                                                {
                                                    Trace.TraceInformation("Record id " + record.ID + " BasicInsertionThrottling: Enabled");

                                                    int iCallbacksInIVR = _recordManager.RecordsCurrentlyInIVR;

                                                    if (iCallbacksInIVR < _settingsManager.ApplicationSettings.BasicInsertionThrottling_MaximumRecordsAtATime)
                                                    {
                                                        Trace.TraceInformation("Record id " + record.ID + " Number of Callbacks in IVR: " + iCallbacksInIVR.ToString() + " BasicInsertionThrottling_MaximumRecordsAtATime: " + _settingsManager.ApplicationSettings.BasicInsertionThrottling_MaximumRecordsAtATime);
                                                    }
                                                    else //if(iCallbacksInIVR < _settingsManager.ApplicationSettings.BasicInsertionThrottling_MaximumRecordsAtATime)
                                                    {
                                                        Trace.TraceWarning("Record " + record.ID + " cannot be reentered: " + " Number of Callbacks in IVR: " + iCallbacksInIVR.ToString() + " BasicInsertionThrottling_MaximumRecordsAtATime: " + _settingsManager.ApplicationSettings.BasicInsertionThrottling_MaximumRecordsAtATime);

                                                        continue;
                                                    }//if(iCallbacksInIVR < _settingsManager.ApplicationSettings.BasicInsertionThrottling_MaximumRecordsAtATime)
                                                }
                                                else
                                                {
                                                    Trace.TraceInformation("Record id " + record.ID + " BasicInsertionThrottling: Disabled");
                                                }

                                                if (_RealtimeDataClient.GetContactsQueuedFor(record.TargetCSQ))
                                                {
                                                    Trace.TraceInformation("Record " + record.ID + " contactRealtimeData.GetContactsQueuedFor() returned true.");

                                                    if (_RealtimeDataClient.OrderContactsQueuedFor())
                                                    {
                                                        Trace.TraceInformation("Record " + record.ID + " contactRealtimeData.OrderContactsQueuedFor() returned true.");

                                                        int iResult = _RealtimeDataClient.GetNumberOfContactAheadOf(record.ContactID, record.ID, record.QueueStartTime);

                                                        if (iResult == -1)
                                                        {
                                                            Trace.TraceWarning("_RealtimeDataClient.GetNumberOfContactAheadOf() of recordID " + record.ID + " returned -1. Not sure what to do if false!!!!");

                                                            continue;
                                                        }
                                                        else if (iResult == -2)
                                                        {
                                                            Trace.TraceInformation("_RealtimeDataClient.GetNumberOfContactAheadOf() of recordID " + record.ID + " Not to be reentered yet; scheduled.");

                                                            continue;
                                                        }
                                                        else if (iResult == 0)
                                                        {
                                                            Trace.TraceInformation("_RealtimeDataClient.GetNumberOfContactAheadOf() of recordID " + record.ID + " :" + iResult);

                                                            Trace.TraceInformation("Record id " + record.ID + " with contactID " + record.ContactID + " can be reentered");

                                                            System.Threading.Thread thr = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(_SendReentryRequest));
                                                            thr.Start(record.ID);
                                                            thr = null;

                                                            break;
                                                        }
                                                    }
                                                    else//if (_RealtimeDataClient.OrderContactsQueuedFor())
                                                    {
                                                        Trace.TraceWarning("Record " + record.ID + " contactRealtimeData.OrderContactsQueuedFor() returned false.");
                                                    } //if (_RealtimeDataClient.OrderContactsQueuedFor())
                                                }
                                                else  //if (_RealtimeDataClient.GetContactsQueuedFor(record.TargetCSQ))
                                                {
                                                    Trace.TraceWarning("Record " + record.ID + " contactRealtimeData.GetContactsQueuedFor() returned false.");
                                                } //if (_RealtimeDataClient.GetContactsQueuedFor(record.TargetCSQ))
                                            }
                                            else  //if (bMaxIVRPortsAvailable > iNumberOfContactsInIVR)
                                            {
                                                Trace.TraceWarning("Record " + record.ID + " cannot be reentered: " + " Number of contacts in IVR: " + iNumberOfContactsInIVR.ToString() + " IVR Ports available to Callback Server: " + bMaxIVRPortsAvailable.ToString());

                                                continue;
                                            }//if (bMaxIVRPortsAvailable > iNumberOfContactsInIVR)

                                            //Try reentry based on default algorithm
                                        }
                                        else//if (dtCallbackProcessingTimeframeEnd.Subtract(DateTime.Now).TotalMilliseconds >= 0)
                                        {
                                            Trace.TraceInformation("Record " + record.ID + " CallbackProcessingTimeframe has closed.");
                                        } //if (dtCallbackProcessingTimeframeEnd.Subtract(DateTime.Now).TotalMilliseconds >= 0)
                                    }
                                    else  //if (DateTime.Now.Subtract(dtCallbackProcessingTimeframeBegin).TotalMilliseconds >= 0)
                                    {
                                        Trace.TraceInformation("Record " + record.ID + " CallbackProcessingTimeframe has not yet opened.");
                                    } //if (DateTime.Now.Subtract(dtCallbackProcessingTimeframeBegin).TotalMilliseconds >= 0)
                                }
                                else  //if (_queue.CallbackEnabled)
                                {
                                    Trace.TraceWarning("Record " + record.ID + " Callback in not enabled for CSQ " + sCSQ + "; Flag record as invalid.");
                                    sErrorDescription = String.Empty;
                                    _recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.INVALID, out sErrorDescription);
                                    continue;
                                } //if (_queue.CallbackEnabled)
                            }
                            else  //if (_queue != null)
                            {
                                Trace.TraceWarning("Record " + record.ID + " Settings for CSQ " + sCSQ + " were not found. Flag record as invalid.");
                                sErrorDescription = String.Empty;
                                _recordManager.Update(record.ID, String.Empty, String.Empty, Constants.RecordStatus.INVALID, out sErrorDescription);
                                continue;
                            } //if (_queue != null)
                        }
                        else  //if (record.Status != Constants.RecordStatus.INVALID)
                        {
                            Trace.TraceWarning("Record " + record.ID + " is not NEW or RETRY.");
                        } //if (record.Status != Constants.RecordStatus.INVALID)
                    }     //foreach (CallbackRecord record in _recordManager.Records)
                }
                catch (Exception ex)
                {
                    Trace.TraceWarning("Exception: " + ex.Message + Environment.NewLine + "Stacktrace: " + ex.StackTrace);
                }

                Trace.TraceInformation("Cycle through " + _recordManager.Records.Count + " records took " + DateTime.Now.Subtract(dtBegin).TotalMilliseconds + " ms.");

                _tmrTick.Change(TICKINTERVAL, TICKINTERVAL);
            }//lock (objLock)

            Trace.TraceInformation("Exit.");
        }