///<summary>Compares two EConnectorStatistics to determine if they refer to the same eConnector</summary>
        public static bool AreSameEConnector(EConnectorStatistics eConnA, EConnectorStatistics eConnB)
        {
            if (eConnA == null || eConnB == null)
            {
                return(false);
            }
            string nameA = eConnA.EConnectorComputerName.ToLower().Trim();
            string ipA   = (eConnA.PublicIP ?? "").ToLower().Trim();
            string nameB = eConnB.EConnectorComputerName.ToLower().Trim();
            string ipB   = (eConnB.PublicIP ?? "").ToLower().Trim();

            return(nameA == nameB && ipA == ipB);
        }
        ///<summary>Send a summary of eConnector statistics to OD HQ. This should only be called from the eConnector.</summary>
        public static void UpdateEConnectorStats()
        {
            EConnectorStatistics eConnStats = new EConnectorStatistics()
            {
                ListEServiceSignals = new List <EServiceSignal>(),
                ListEServicePrefs   = new List <Pref>(),
            };

            eConnStats.EConnectorComputerName   = Environment.MachineName;
            eConnStats.EConnectorDomainUserName = Environment.UserName;
            eConnStats.EConnectorIP             = ODEnvironment.GetLocalIPAddress();
            eConnStats.HasClinicsEnabled        = PrefC.HasClinicsEnabled;
            if (PrefC.HasClinicsEnabled)
            {
                eConnStats.CountActiveClinics   = OpenDentBusiness.Clinics.GetCount();
                eConnStats.CountInactiveClinics = OpenDentBusiness.Clinics.GetCount() - eConnStats.CountActiveClinics;
            }
            else
            {
                eConnStats.CountActiveClinics   = 0;
                eConnStats.CountInactiveClinics = OpenDentBusiness.Clinics.GetCount();
            }
            if (DateTime.Now.Hour == 0)            //These are heavy queries so only run them once a day around midnight.
            {
                eConnStats.CountActivePatients    = OpenDentBusiness.Procedures.GetCountPatsComplete(DateTime.Today.AddYears(-2), DateTime.Today);
                eConnStats.CountNonactivePatients = OpenDentBusiness.Patients.GetPatCountAll() - eConnStats.CountActivePatients;
                eConnStats.ListEServiceSignals    = OpenDentBusiness.EServiceSignals.GetServiceHistory(eServiceCode.ListenerService, DateTime.Today.AddDays(-30),
                                                                                                       DateTime.Today, 30);
            }
            eConnStats.DateTimeNow = DateTime.Now;
            foreach (PrefName prefName in Enum.GetValues(typeof(PrefName)))
            {
                if (prefName.In(
                        PrefName.RegistrationKey,
                        PrefName.ProgramVersion,
                        PrefName.DataBaseVersion,
                        PrefName.TextingDefaultClinicNum,
                        PrefName.WebServiceServerName,
                        PrefName.SendEmailsInDiffProcess,
                        PrefName.EmailAlertMaxConsecutiveFails,
                        PrefName.AutoCommNumClinicsParallel,
                        PrefName.AutomaticCommunicationTimeStart,
                        PrefName.AutomaticCommunicationTimeEnd) ||
                    prefName.ToString().StartsWith("WebSched") ||
                    prefName.ToString().StartsWith("ApptConfirm") ||
                    prefName.ToString().StartsWith("ApptRemind") ||
                    prefName.ToString().StartsWith("ApptEConfirm") ||
                    prefName.ToString().StartsWith("Recall") ||
                    prefName.ToString().StartsWith("PatientPortal") ||
                    prefName.ToString().StartsWith("Sms"))
                {
                    try {
                        eConnStats.ListEServicePrefs.Add(Prefs.GetPref(prefName.ToString()));
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                    }
                }
            }
            List <EConnectorStatistics> listStatsToSend = new List <EConnectorStatistics> {
                eConnStats
            };
            string dbStats = PrefC.GetString(PrefName.EConnectorStatistics);
            List <EConnectorStatistics> listDbStats = DeserializeListFromJson(dbStats) ?? new List <EConnectorStatistics>();
            bool doCreateAlert = false;

            foreach (EConnectorStatistics stats in listDbStats)
            {
                //If a different eConnector is saving stats, add that one to the list to be sent to HQ.
                if (!AreSameEConnector(eConnStats, stats) && (eConnStats.DateTimeNow - stats.DateTimeNow).TotalHours < 23)
                {
                    stats.ListEServicePrefs   = new List <Pref>();               //To save on bandwidth
                    stats.ListEServiceSignals = new List <EServiceSignal>();
                    listStatsToSend.Add(stats);
                    if ((eConnStats.DateTimeNow - stats.DateTimeNow).TotalHours < 3)
                    {
                        doCreateAlert = true;
                    }
                }
            }
            if (doCreateAlert && AlertItems.RefreshForType(AlertType.MultipleEConnectors).Count == 0)
            {
                AlertItem alert = new AlertItem {
                    Actions     = ActionType.MarkAsRead | ActionType.Delete,
                    Description = Lans.g("EConnectorStats", "eConnector services are being run on these computers:") + " "
                                  + string.Join(", ", listStatsToSend.Select(x => x.EConnectorComputerName)),
                    Severity = SeverityType.High,
                    Type     = AlertType.MultipleEConnectors,
                };
                AlertItems.Insert(alert);
            }
            string statsStr = SerializeToJson(listStatsToSend);

            OpenDentBusiness.Prefs.UpdateString(PrefName.EConnectorStatistics, statsStr);
            string payload = PayloadHelper.CreatePayload(PayloadHelper.CreatePayloadContent(statsStr, "EConnectorStatsStr"),
                                                         eServiceCode.ListenerService);

            WebServiceMainHQProxy.GetWebServiceMainHQInstance().SetEConnectorStatsAsync(payload);
        }