///<summary>Called by local practice db to query HQ for EService setup info. Must remain very lite and versionless. Will be used by signup portal.
        ///If HasClinics==true then any SignupOut.EServices entries where ClinicNum==0 are invalid and should be ignored.
        ///If HasClinics==false then SignupOut.EServices should only pay attention items where ClinicNum==0.
        ///This list is kept completely unfiltered by ClinicNum for forward compatibility reasons.
        ///The ClinicNum 0 items are always used by the Signup portal to determine default signup preferences.
        ///However, these items are only used for validation and billing in the case where HasClinics==true.</summary>
        public static EServiceSetup.SignupOut GetEServiceSetupFull(SignupPortalPermission permission, bool isSwitchClinicPref = false)
        {
            //Clinics will be stored in this order at HQ to allow signup portal to display them in proper order.
            List <Clinic> clinics = Clinics.GetDeepCopy().OrderBy(x => x.ItemOrder).ToList();

            if (PrefC.GetBool(PrefName.ClinicListIsAlphabetical))
            {
                clinics = clinics.OrderBy(x => x.Abbr).ToList();
            }
#if DEBUG
            bool isMockChanged = false;
            if (WebServiceMainHQProxy.MockWebServiceMainHQ == null)
            {
                WebServiceMainHQProxy.MockWebServiceMainHQ = new WebServiceMainHQMockDemo();
                isMockChanged = true;
            }
#endif
            EServiceSetup.SignupOut signupOut = ReadXml <EServiceSetup.SignupOut>
                                                (
                WebSerializer.DeserializePrimitiveOrThrow <string>
                (
                    GetWebServiceMainHQInstance().EServiceSetup
                    (
                        CreateWebServiceHQPayload
                        (
                            WriteXml(new EServiceSetup.SignupIn()
            {
                MethodNameInt = (int)EServiceSetup.SetupMethod.GetSignupOutFull,
                HasClinics    = PrefC.HasClinicsEnabled,
                //ClinicNum is not currently used as input.
                ClinicNum                 = 0,
                ProgramVersionStr         = PrefC.GetString(PrefName.ProgramVersion),
                SignupPortalPermissionInt = (int)permission,
                Clinics = clinics
                          .Select(x => new EServiceSetup.SignupIn.ClinicLiteIn()
                {
                    ClinicNum   = x.ClinicNum,
                    ClinicTitle = x.Abbr,
                    IsHidden    = x.IsHidden,
                }).ToList(),
                IsSwitchClinicPref = isSwitchClinicPref,
            }), eServiceCode.Undefined
                        )
                    )
                )
                                                );
#if DEBUG
            if (isMockChanged)
            {
                WebServiceMainHQProxy.MockWebServiceMainHQ = null;
            }
#endif
            //We just got the latest sync info from HQ so update the local db to reflect what HQ says is true.
            #region Reconcile Phones
            List <SmsPhone> listPhonesHQ = signupOut.Phones.Select(x => new SmsPhone()
            {
                ClinicNum        = x.ClinicNum,
                CountryCode      = x.CountryCode,
                DateTimeActive   = x.DateTimeActive,
                DateTimeInactive = x.DateTimeInactive,
                InactiveCode     = x.InactiveCode,
                PhoneNumber      = x.PhoneNumber,
            }).ToList();
            SmsPhones.UpdateOrInsertFromList(listPhonesHQ);
            #endregion
            #region Reconcile practice and clinics
            List <EServiceSetup.SignupOut.SignupOutSms> smsSignups = GetSignups <EServiceSetup.SignupOut.SignupOutSms>(signupOut, eServiceCode.IntegratedTexting);
            bool isCacheInvalid = false;
            bool isSmsEnabled   = false;
            if (PrefC.HasClinicsEnabled)              //Clinics are ON so loop through all clinics and reconcile with HQ.
            {
                List <Clinic> listClinicsAll = Clinics.GetDeepCopy();
                foreach (Clinic clinicDb in listClinicsAll)
                {
                    WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms clinicSignup =
                        smsSignups.FirstOrDefault(x => x.ClinicNum == clinicDb.ClinicNum) ?? new WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms()
                    {
                        //Not found so turn it off.
                        SmsContractDate = DateTime.MinValue,
                        MonthlySmsLimit = 0,
                        IsEnabled       = false,
                    };
                    Clinic clinicNew = clinicDb.Copy();
                    clinicNew.SmsContractDate = clinicSignup.SmsContractDate;
                    clinicNew.SmsMonthlyLimit = clinicSignup.MonthlySmsLimit;
                    isCacheInvalid           |= Clinics.Update(clinicNew, clinicDb);
                    isSmsEnabled |= clinicSignup.IsEnabled;
                }
            }
            else               //Clinics are off so ClinicNum 0 is the practice clinic.
            {
                WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms practiceSignup =
                    smsSignups.FirstOrDefault(x => x.ClinicNum == 0) ?? new WebServiceMainHQProxy.EServiceSetup.SignupOut.SignupOutSms()
                {
                    //Not found so turn it off.
                    SmsContractDate = DateTime.MinValue,
                    MonthlySmsLimit = 0,
                    IsEnabled       = false,
                };
                isCacheInvalid
                    |= Prefs.UpdateDateT(PrefName.SmsContractDate, practiceSignup.SmsContractDate)
                       | Prefs.UpdateLong(PrefName.TextingDefaultClinicNum, 0)
                       | Prefs.UpdateDouble(PrefName.SmsMonthlyLimit, practiceSignup.MonthlySmsLimit);
                isSmsEnabled |= practiceSignup.IsEnabled;
            }
            #endregion
            #region Reconcile CallFire
            //Turn off CallFire if SMS has been activated.
            //This only happens the first time SMS is turned on and CallFire is still activated.
            if (isSmsEnabled && Programs.IsEnabled(ProgramName.CallFire))
            {
                Program callfire = Programs.GetCur(ProgramName.CallFire);
                if (callfire != null)
                {
                    callfire.Enabled = false;
                    Programs.Update(callfire);
                    Signalods.Insert(new Signalod()
                    {
                        IType = InvalidType.Providers
                    });
                    signupOut.Prompts.Add("Call Fire has been disabled. Cancel Integrated Texting and access program properties to retain Call Fire.");
                }
            }
            #endregion
            #region eConfirmations
            if (Prefs.UpdateBool(PrefName.ApptConfirmAutoSignedUp, IsEServiceActive(signupOut, eServiceCode.ConfirmationRequest)))
            {
                //HQ does not match the local pref. Make it match with HQ.
                isCacheInvalid = true;
                SecurityLogs.MakeLogEntry(Permissions.Setup, 0, "Automated appointment eConfirmations automatically changed by HQ.  Local pref set to "
                                          + IsEServiceActive(signupOut, eServiceCode.ConfirmationRequest).ToString() + ".");
            }
            #endregion
            if (isCacheInvalid)              //Something changed in the db. Alert other workstations and change this workstation immediately.
            {
                Signalods.Insert(new Signalod()
                {
                    IType = InvalidType.Prefs
                });
                Prefs.RefreshCache();
                Signalods.Insert(new Signalod()
                {
                    IType = InvalidType.Providers
                });
                Providers.RefreshCache();
                Clinics.RefreshCache();
            }
            return(signupOut);
        }