public static string Run(bool incDisplay, bool incSending, DateTime date)
    {
        if (incSending)
        {
            RunBirthdaysWithoutSMSorEmail();
        }

        date = date.Date;


        bool EnableBirthdaySMS    = Convert.ToInt32(SystemVariableDB.GetByDescr("EnableBirthdaySMS").Value) == 1;
        bool EnableBirthdayEmails = Convert.ToInt32(SystemVariableDB.GetByDescr("EnableBirthdayEmails").Value) == 1;


        Site[] sites = SiteDB.GetAll();

        Patient[] patients = PatientDB.GetBirthdays(date);
        Hashtable patientContactPhoneNbrHash = GetPatientPhoneNbrCache(patients);
        Hashtable patientContactEmailHash    = GetPatientEmailCache(patients);
        Hashtable patientRegOrgHash          = GetPatientRegOrgCache(patients);   // get a hash of patient reg to org


        decimal balance = SMSCreditDataDB.GetTotal() - SMSHistoryDataDB.GetTotal();
        decimal cost    = Convert.ToDecimal(SystemVariableDB.GetByDescr("SMSPrice").Value);


        string    callerId        = System.Configuration.ConfigurationManager.AppSettings["SMSTech_callerId"];           // not here used as the callerId will be the org name
        string    countryCode     = System.Configuration.ConfigurationManager.AppSettings["SMSTech_CountryCode"];
        ArrayList messagesToSMS   = new ArrayList();
        ArrayList messagesToEmail = new ArrayList();


        string output           = "<table class=\"table table-bordered table-striped table-grid table-grid-top-bottum-padding-thick auto_width block_center\" border=\"1\" style=\"border-collapse:collapse;\">";
        int    countWithPatient = 0;

        foreach (Patient patient in patients)
        {
            // get all info to send via sms or email

            Site site = null;
            foreach (Site curSite in sites)
            {
                if ((patient.IsClinicPatient && curSite.SiteType.ID == 1) || (!patient.IsClinicPatient && curSite.SiteType.ID == 2))
                {
                    site = curSite;
                }
            }

            ArrayList orgs    = patientRegOrgHash[patient.PatientID] as ArrayList;
            string    orgText = (orgs == null || orgs.Count == 0 || orgs.Count > 1) ? site.Name : ((Organisation)orgs[0]).Name;


            string phoneNumPatient = GetPhoneNbr(patientContactPhoneNbrHash, patient.Person.EntityID, true);
            if (phoneNumPatient != null)
            {
                phoneNumPatient = phoneNumPatient.StartsWith("0") ? countryCode + phoneNumPatient.Substring(1) : phoneNumPatient;
            }

            string emailPatient = GetEmail(patientContactEmailHash, patient.Person.EntityID);

            string smsText          = GetSMSText(patient, site, patientRegOrgHash[patient.PatientID] as ArrayList);
            string emailText        = GetEmailText(patient, site, patientRegOrgHash[patient.PatientID] as ArrayList);
            string emailSubjectText = GetEmailSubjectText(patient, site, patientRegOrgHash[patient.PatientID] as ArrayList);



            // display the info

            string tdTagStart          = phoneNumPatient == null && emailPatient == null ? "<td class=\"nowrap\" style=\"color:grey;\">" : (phoneNumPatient == null ? "<td>"  : "<td><b>");
            string tdTagStartLeftAlign = phoneNumPatient == null && emailPatient == null ? "<td class=\"nowrap text_left\" style=\"color:grey;\">" : (phoneNumPatient == null ? "<td class=\"text_left\">" : "<td class=\"text_left\"><b>");
            string tdTagEnd            = phoneNumPatient == null && emailPatient == null ? "</td>" : (phoneNumPatient == null ? "</td>" : "</b></td>");

            output += "<tr>";
            output += tdTagStart + patient.PatientID + tdTagEnd;
            output += tdTagStart + patient.Person.Dob.ToString("dd-MM-yyyy") + tdTagEnd;
            output += tdTagStart + patient.Person.FullnameWithoutMiddlename + "<br />" +
                      (phoneNumPatient == null ? "-- No Mobile --" : "<u>" + phoneNumPatient + "</u>") + "<br />" +
                      (emailPatient == null ? "-- No Email --" : "<u>" + emailPatient + "</u>") + tdTagEnd;
            output += tdTagStartLeftAlign + (phoneNumPatient == null && emailPatient == null ? "" : "<u>" + emailSubjectText + "</u><br /><br />" + emailText) + tdTagEnd;
            output += "</tr>";

            countWithPatient++;



            // add to lists to sms or email (or both)

            if (EnableBirthdaySMS && phoneNumPatient != null && balance >= cost)
            {
                messagesToSMS.Add(new Tuple <int, decimal, string, string, string>(patient.PatientID, cost, phoneNumPatient, smsText, orgText));
                if (incSending)
                {
                    balance -= cost;
                }
            }
            if (EnableBirthdayEmails && emailPatient != null)
            {
                messagesToEmail.Add(new Tuple <int, string, string, string, string>(patient.PatientID, orgText, emailPatient, emailText, emailSubjectText));
            }
        }
        output += "</table>";


        // run the sending and send off reminders -- but only if there was any bookings

        if (incSending && patients.Length > 0)
        {
            /*
             * run the sendings
             */

            SendSMSes((Tuple <int, decimal, string, string, string>[])messagesToSMS.ToArray(typeof(Tuple <int, decimal, string, string, string>)));
            SendEmails((Tuple <int, string, string, string, string>[])messagesToEmail.ToArray(typeof(Tuple <int, string, string, string, string>)));


            /*
             * send balance warning
             */

            SystemVariables systemVariables            = SystemVariableDB.GetAll();
            string          warningEmail               = systemVariables["SMSCreditNotificationEmailAddress"].Value;
            decimal         warningThreshold           = Convert.ToDecimal(systemVariables["SMSCreditLowBalance_Threshold"].Value);
            bool            checkSMSCreditOutOfBalance = Convert.ToInt32(systemVariables["SMSCreditOutOfBalance_SendEmail"].Value) == 1;
            bool            checkMSCreditLowBalance    = Convert.ToInt32(systemVariables["SMSCreditLowBalance_SendEmail"].Value) == 1;


            if (warningEmail.Length > 0 && checkSMSCreditOutOfBalance && balance < cost)
            {
                SendEmail(
                    warningEmail,
                    "SMS Credit Used Up",
                    "Please note that your SMS credit at mediclinic has been used up. To continue sending, please top up.<br /><br />Best regards,<br />Mediclinic");
            }
            else if (warningEmail.Length > 0 && checkMSCreditLowBalance && balance <= warningThreshold)  // dont send warning low balance if already sending out of credit email
            {
                SendEmail(
                    warningEmail,
                    "SMS Credit Warning - Don't Forget To Top-Up Before It Runs Out",
                    "Hi! Just a friendly reminder that the SMS reminder threshold you set has been reached.<br /> To avoid missing SMS'es being sent, don't forget to top-up before the remainder runs out!<br /><br />Best regards,<br />Mediclinic");
            }
        }

        if (incDisplay)
        {
            return("Count: <b>" + countWithPatient + "</b> &nbsp;&nbsp; [with mobile: <b>" + messagesToSMS.Count + "</b>] &nbsp;&nbsp; [with email: <b>" + messagesToEmail.Count + "</b>] " + "<br /><br />" + output);
        }
        else
        {
            return(string.Empty);
        }
    }