protected List<SubRegion> GetRegionsInValueSet(List<DataValue> values, bool ignoreBadData, bool useSteppedCalculations)
{
// nothing to do if no data.
if (values == null)
{
return null;
}
SubRegion currentRegion = null;
List<SubRegion> regions = new List<SubRegion>();
for (int ii = 0; ii < values.Count; ii++)
{
double currentValue = 0;
DateTime currentTime = values[ii].SourceTimestamp;
StatusCode currentStatus = values[ii].StatusCode;
// convert to doubles to facilitate numeric calculations.
if (StatusCode.IsNotBad(currentStatus))
{
try
{
currentValue = CastToDouble(values[ii]);
}
catch (Exception)
{
currentStatus = StatusCodes.BadTypeMismatch;
}
}
else
{
// use the previous value if end of region is bad.
if (currentRegion != null)
{
currentValue = currentRegion.StartValue;
}
}
// some aggregates ignore bad data so remove them from the set.
if (ignoreBadData)
{
// always keep the first region.
if (currentRegion != null)
{
if (!IsGood(values[ii]))
{
// set the status to sub normal if bad end data ignored.
if (StatusCode.IsNotBad(currentRegion.StatusCode))
{
currentRegion.StatusCode = StatusCodes.UncertainDataSubNormal;
}
// skip everything but the endpoint.
if (ii < values.Count - 1)
{
continue;
}
}
else
{
if (!useSteppedCalculations && StatusCode.IsNotGood(values[ii].StatusCode))
{
currentRegion.StatusCode = StatusCodes.UncertainDataSubNormal;
}
}
}
}
if (currentRegion != null)
{
// if using stepped calculations the end value is not used.
if (useSteppedCalculations)
{
currentRegion.EndValue = currentRegion.StartValue;
}
// using interpolated calculations means the end affects the status of the current region.
else
{
if (IsGood(values[ii]))
{
// handle case with uncertain end point.
if (StatusCode.IsNotGood(values[ii].StatusCode) && StatusCode.IsNotBad(currentRegion.StatusCode))
{
currentRegion.StatusCode = StatusCodes.UncertainDataSubNormal;
}
currentRegion.EndValue = currentValue;
}
else
{
if (StatusCode.IsNotBad(currentRegion.StatusCode))
{
currentRegion.StatusCode = StatusCodes.UncertainDataSubNormal;
}
if (ignoreBadData && StatusCode.IsNotBad(currentStatus))
{
currentRegion.EndValue = currentValue;
}
}
}
// if at end of data then duration is 1 tick.
// must be end of data if start of region is good yet end bound is bad.
if (!ignoreBadData && currentRegion != null && IsGood(currentRegion.DataPoint) && currentStatus == StatusCodes.BadNoData && ii == values.Count - 1)
{
currentRegion.Duration = 1;
}
// calculate region span.
else
{
// set uncertain status to bad if treat uncertain as bad is true.
if (StatusCode.IsUncertain(currentStatus) && !IsGood(values[ii]))
{
currentStatus = StatusCodes.BadNoData;
}
currentRegion.Duration = (currentTime - currentRegion.StartTime).TotalMilliseconds;
}
regions.Add(currentRegion);
}
// start a new region.
currentRegion = new SubRegion();
currentRegion.StartValue = currentValue;
currentRegion.EndValue = currentValue;
currentRegion.StartTime = currentTime;
currentRegion.StatusCode = currentStatus;
currentRegion.DataPoint = values[ii];
}
return regions;
}