// was before v 3.5: private async void LoadSampleDataGroupFromPatientDataList(SampleDataGroup g, TP_PatientReports p)
 private async Task LoadSampleDataGroupFromPatientDataList(SampleDataGroup g, TP_PatientReports p)
 {
     g.Items.Clear();
     //string encodedTemp;
     foreach (TP_PatientReport pdi in p)
     {
         pdi.ImageEncoded = await pdi.FormatImageEncoded();
         g.Items.Add(new SampleDataItem(
             pdi.FormatUniqueID(),
             pdi.FormatTitle(),
             pdi.FormatSubtitle(),
             pdi.ImageEncoded, // freshened above
             pdi.FormatImageBorderColor(),
             pdi.FormatDescription(),
             pdi.FormatContent(),
             g));
     }
 }
        private void UpdateChartPage7()
        {
            string eventName = "";
            // No longer needed, now that we have App.PatientDataGroups.GetOutboxForStatistics():
            // // sorting added June 2015, so call to outboxCountPerDaySpecificEventSet in UpdateChartPage7Impl will work right
            // List<TP_PatientReport> orig = App.PatientDataGroups.GetOutbox().GetAsList();
            // List<TP_PatientReport> sort = new List<TP_PatientReport>();
            // sort = orig.OrderBy(o => o.WhenLocalTime).ToList();
            // //sort = orig.OrderByDescending(o => o.WhenLocalTime).ToList();
            // TP_PatientReports pdl = new TP_PatientReports();
            // pdl.ReplaceWithList(sort);
            TP_PatientReports pdl = App.PatientDataGroups.GetOutboxForStatistics();
            TP_PatientReports results = new TP_PatientReports();
            TP_EventsDataList edl = App.CurrentDisasterList;
            // Across events.  Widen range by at least 2 days to prevent stupid clipping of line segments and/or data points.
            minDT = FindMinimumDate().AddDays(-2.0);
            maxDT = FindMaximumDate().AddDays(2.0);
            WidenRange(); // May adjust minDT, maxDT
            List<DateValueItem>[] arrivalLines = new List<DateValueItem>[10]; // Handle up to 10 events first draft
            LineSeries[] ls = new LineSeries[10];
            int i = 0;
            foreach (var edi in edl)
            {
                eventName = edi.EventName;
                foreach (var pdi in pdl)
                {
                    if (pdi.EventName == eventName)
                        results.Add(pdi);
                }
                if (results.Count() > 0)
                {
                    arrivalLines[i] = new List<DateValueItem>();
                    ls[i] = new LineSeries();
                    UpdateChartPage7Impl(eventName, results, ls[i], arrivalLines[i]);
/* FIRST DRAFT, THEN MOVED
                    if (i == 0)
                    {
                        ls[i].IndependentAxis = new DateTimeAxis() { Minimum = minDT, Maximum = maxDT, FontSize = 10, Orientation = AxisOrientation.X, Location = AxisLocation.Bottom }; // explicitly state bottom so won't end up with top & bottom labels
                        ls[i].DependentRangeAxis = new LinearAxis() { Minimum = 0, Interval = 1.0, Orientation = AxisOrientation.Y, ShowGridLines = true, FontSize = 11 }; // BorderThickness = new Thickness(2.0), BorderBrush = new SolidColorBrush(Colors.White) };
                    }
                    else
                    {
                        ls[i].IndependentAxis = new DateTimeAxis() { Minimum = minDT, Maximum = maxDT, FontSize = 0.1, Orientation = AxisOrientation.X, Location = AxisLocation.Bottom }; // explicitly state bottom so won't end up with top & bottom labels
                        // When redraws, grid lines are not perfectly atop each other, so suppress
                        ls[i].DependentRangeAxis = new LinearAxis() { Minimum = 0, Interval = 1.0, Orientation = AxisOrientation.Y, ShowGridLines = false, FontSize = 0.1 }; // BorderThickness = new Thickness(2.0), BorderBrush = new SolidColorBrush(Colors.White) };
                    }
                    //ls[i].DataPointStyle = GetDataPointStyleWithNoPointsRandomLineColors();
                    LineChartArrivalsAllStations_Page7.Series.Add(ls[i]);
 */
                    results.Clear();
                    i++;
                }
            }
            // Can't rely on auto-scaling to work right with multilines if we're setting axis (in order to set interval)
            // So calculate max count here across events, for benefit of setting axes:
            int maxCount = 0;
            for(int j=0; j < i; j++)
            {
                foreach(var dvi in arrivalLines[j])
                {
                    if(dvi.Value > maxCount)
                        maxCount = dvi.Value;
                }
            }
            // Prettify:
            double yinterval = 1.0;
            if (maxCount <= 10)
            {
                maxCount = 10;
            }
            else if (maxCount <= 25)
            {
                maxCount = 25;
                yinterval = 5.0;
            }
            else if (maxCount <= 50)
            {
                maxCount = 50;
                yinterval = 5.0;
            }
            else if (maxCount <= 100)
            {
                maxCount = 100;
                yinterval = 10.0;
            }
            else
            {
                maxCount = (maxCount % 100) * 100;
                yinterval = 25.0;
            }

            // Set axes & finish
            for (int j = 0; j < i; j++)
            {
                if (j == 0)
                {
                    ls[j].IndependentAxis = new DateTimeAxis() { Minimum = minDT, Maximum = maxDT, FontSize = 10, Orientation = AxisOrientation.X, Location = AxisLocation.Bottom }; // explicitly state bottom so won't end up with top & bottom labels
                    ls[j].DependentRangeAxis = new LinearAxis() { Minimum = 0, Maximum = maxCount, Interval = yinterval, Orientation = AxisOrientation.Y, ShowGridLines = true, Location = AxisLocation.Left, FontSize = 11 }; // BorderThickness = new Thickness(2.0), BorderBrush = new SolidColorBrush(Colors.White) };
                }
                else
                {
                    ls[j].IndependentAxis = new DateTimeAxis() { Minimum = minDT, Maximum = maxDT, FontSize = 0.1, Orientation = AxisOrientation.X, Location = AxisLocation.Bottom }; // explicitly state bottom so won't end up with top & bottom labels
                    // When redraws, grid lines are not perfectly atop each other, so suppress
                    ls[j].DependentRangeAxis = new LinearAxis() { Minimum = 0, Maximum = maxCount, Interval = yinterval, Orientation = AxisOrientation.Y, ShowGridLines = true, Location=AxisLocation.Left, FontSize = 0.1 }; // BorderThickness = new Thickness(2.0), BorderBrush = new SolidColorBrush(Colors.White) };
                }
                //ls[i].DataPointStyle = GetDataPointStyleWithNoPointsRandomLineColors();
                LineChartArrivalsAllStations_Page7.Series.Add(ls[j]);
            }

        }
        private void UpdateChartPage7Impl(string eventName, TP_PatientReports arrivalsOneEvent, LineSeries series, List<DateValueItem> arrivalLine)
        {
            outboxCountPerDaySpecificEventSet(arrivalsOneEvent, arrivalLine);
            series.ItemsSource = arrivalLine;

            series.Name = "Chart 7 " + eventName;
            series.Title = eventName;
            // should these be "Name" or "Value" instead of "Path"?
            series.IndependentValueBinding = new Binding();
            series.DependentValueBinding = new Binding();
            series.IndependentValueBinding.Path = new PropertyPath("DateTimeBucket");
            series.DependentValueBinding.Path = new PropertyPath("Value");
/* MAYBENOT
            series.IndependentValuePath = "DateTimeBucket";
            series.DependentValuePath = "Value";
 */
            series.IsSelectionEnabled = true;
        }
        /// <summary>
        /// Given an input list of patients, ordered from oldest first to newest last, for either a single event or a set of events that we don't care to distinguish (e.g., all events),
        /// returns a list with the date of each one-day bucket (with time zeroed) and the count within the bucket
        /// </summary>
        /// <param name="arrivalsByDateSpecificEvent"></param>
        public void outboxCountPerDaySpecificEventSet(TP_PatientReports arrivalsIn, List<DateValueItem> arrivalsOut)
        {
            if (arrivalsIn.Count<TP_PatientReport>() == 0)
                return;
            DateTimeOffset startOfBucket;
            DateTimeOffset currentItem;
            bool firstloop = true;
            int inBucket = 0;
            foreach (var i in arrivalsIn)
            {
                // For Release 6, use of i.WhenLocalTime in this loop replaced by i.WhenLocalTimeMsg1, i.e., arrival time
                if (String.IsNullOrEmpty(i.WhenLocalTimeMsg1))
                    continue; // assume weird empty record

                if (firstloop)
                {
                    firstloop = false;

                    DateTimeOffset firstInBucket = DateTimeOffset.Parse(i.WhenLocalTimeMsg1);
                    // Zero out anything under 1 day
                    startOfBucket = new DateTimeOffset(firstInBucket.Year, firstInBucket.Month, firstInBucket.Day, 0, 0, 0, firstInBucket.Offset);
                    inBucket = 1;
                    continue;
                }
                currentItem = DateTime.Parse(i.WhenLocalTimeMsg1);
                if (currentItem.Year == startOfBucket.Year && currentItem.DayOfYear == startOfBucket.DayOfYear)
                {
                    inBucket++;
                    continue;
                }
                // record count accumulated from last through loop:
                arrivalsOut.Add(new DateValueItem { DateTimeBucket = startOfBucket.DateTime, Value = inBucket });

#if OK_BUT_TOO_MANY_ZERO_POINTS
                startOfBucket = startOfBucket.AddDays(1.0);
                // Generate buckets with zeros, 1 per day:
                while (currentItem.Year > startOfBucket.Year || currentItem.DayOfYear > startOfBucket.DayOfYear)
                {
                    arrivalsOut.Add(new DateValueItem { DateTimeBucket = startOfBucket.DateTime, Value = 0 });
                    startOfBucket = startOfBucket.AddDays(1.0);
                }
#endif
                startOfBucket = startOfBucket.AddDays(1.0);
                // Generate two buckets with zeros, at either end of range (or a single bucket if there's only 1 zero day between non-zero days):
                if (currentItem.Year > startOfBucket.Year || currentItem.DayOfYear > startOfBucket.DayOfYear)
                {
                    arrivalsOut.Add(new DateValueItem { DateTimeBucket = startOfBucket.DateTime, Value = 0 }); // 1st one
                    startOfBucket = startOfBucket.AddDays(1.0);
                    if (currentItem.Year > startOfBucket.Year || currentItem.DayOfYear > startOfBucket.DayOfYear)
                    {
                        while (currentItem.Year > startOfBucket.Year || currentItem.DayOfYear > startOfBucket.DayOfYear)
                            startOfBucket = startOfBucket.AddDays(1.0); // skip redundant zero points in center of their range
                        arrivalsOut.Add(new DateValueItem { DateTimeBucket = startOfBucket.DateTime.AddDays(-1.0), Value = 0 }); // 2nd one.  Note -1 day
                    }
                }

                // New bucket starting
                inBucket = 1;
            }
            // Last bucket:
            arrivalsOut.Add(new DateValueItem { DateTimeBucket = startOfBucket.DateTime, Value = inBucket });
            // Special case...
            if (arrivalsOut.Count == 1)
            {
                // Need to generate an extra zero point so that there's at least 1 line segment visible.
                // We'll do it here at end, rather than beginning... smarter algorithm would have caller give us hint to generate at beginning, at end, or both.
                startOfBucket = startOfBucket.AddDays(1.0);
                arrivalsOut.Add(new DateValueItem { DateTimeBucket = startOfBucket.DateTime, Value = 0 });
            }
        }