Skip to content

Commit

Permalink
Merge branch 'main' into nullability-ext-ref
Browse files Browse the repository at this point in the history
  • Loading branch information
hf-kklein authored Aug 21, 2024
2 parents 461af10 + 9131ad0 commit 5305f96
Show file tree
Hide file tree
Showing 57 changed files with 986 additions and 261 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ public static bool Has(this BO.Benachrichtigung b, string key, string value)
/// <returns></returns>
public static bool Has(this BO.Benachrichtigung b, GenericStringStringInfo gssi)
{
if (b.Infos == null || b.Infos.Count == 0) return false;
if (b.Infos == null || b.Infos.Count == 0)
{
return false;
}

// ToDo für Hamid: Bitte prüfen, warum Contains false zurückliefert.
return b.Infos.Any(m => m.KeyColumn == gssi.KeyColumn && m.Value == gssi.Value);
}
Expand All @@ -47,7 +51,11 @@ public static bool Has(this BO.Benachrichtigung b, GenericStringStringInfo gssi)
/// <returns>true if key is in <see cref="BO4E.BO.Benachrichtigung.Infos" /></returns>
public static bool Has(this BO.Benachrichtigung b, string key)
{
if (b.Infos == null || b.Infos.Count == 0) return false;
if (b.Infos == null || b.Infos.Count == 0)
{
return false;
}

return b.Infos.Any(gssi => gssi.KeyColumn == key);
}

Expand All @@ -68,11 +76,18 @@ public static bool Has(this BO.Benachrichtigung b, string key)
public static bool Has<T>(this BO.Benachrichtigung b, string keyName, Predicate<T> predicate,
bool passByDefault = true, TypeConverter typeConverter = null) where T : IComparable
{
if (!b.Has(keyName)) return passByDefault;
if (!b.Has(keyName))
{
return passByDefault;
}

foreach (var info in b.Infos.Where(gssi => gssi.KeyColumn == keyName))
try
{
if (typeConverter == null) typeConverter = TypeDescriptor.GetConverter(typeof(T));
if (typeConverter == null)
{
typeConverter = TypeDescriptor.GetConverter(typeof(T));
}

{
var value = (T)typeConverter.ConvertFromString(info.Value);
Expand All @@ -97,11 +112,18 @@ public static void MoveInfosToUserProperties(this BO.Benachrichtigung b, bool ov
{
if (b.Infos != null && b.Infos.Count > 0)
{
if (b.UserProperties == null) b.UserProperties = new Dictionary<string, object>();
if (b.UserProperties == null)
{
b.UserProperties = new Dictionary<string, object>();
}

foreach (var info in b.Infos)
{
if (b.UserProperties.ContainsKey(info.KeyColumn) && overwriteExistingKeys)
{
b.UserProperties.Remove(info.KeyColumn);
}

b.UserProperties.Add(info.KeyColumn,
info.Value); // might throw exception if key exists and !overwriteExistingKeys. That's ok.
}
Expand Down
113 changes: 100 additions & 13 deletions BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,23 @@ public static decimal GetTotalConsumption(this BO.Energiemenge em,
/// <returns>Tuple of consumption value and automatically determined unit of measurement</returns>
public static Tuple<decimal, Mengeneinheit> GetConsumption(this BO.Energiemenge em, ITimeRange reference)
{
if (!IsPure(em)) throw new ArgumentException("The Energiemenge is not pure.");
if (em.Energieverbrauch.Count == 0) return Tuple.Create(0.0M, Mengeneinheit.ANZAHL);
if (!IsPure(em))
{
throw new ArgumentException("The Energiemenge is not pure.");
}

if (em.Energieverbrauch.Count == 0)
{
return Tuple.Create(0.0M, Mengeneinheit.ANZAHL);
}

ISet<Mengeneinheit> einheiten = new HashSet<Mengeneinheit>(em.Energieverbrauch.Select(x => x.Einheit));
if (einheiten.Count > 1)
// z.B. kWh und Wh oder Monat und Jahr... Die liefern IsPure==true.
// z.B. kWh und Wh oder Monat und Jahr... Die liefern IsPure==true.
{
throw new NotImplementedException("Converting different units of same type is not supported yet.");
}

var v = em.Energieverbrauch.First();
var consumption = em.GetConsumption(reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit);
return Tuple.Create(consumption, v.Einheit);
Expand All @@ -143,8 +154,11 @@ public static decimal GetConsumption(this BO.Energiemenge em, ITimeRange referen
Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit me)
{
if (!me.IsExtensive())
{
throw new ArgumentException(
$"The Mengeneinheit {me} isn't extensive. Calculating a consumption doesn't make sense.");
}

return em.Energieverbrauch
.Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obiskennzahl && v.Einheit == me)
.Sum(v => GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, false) * v.Wert);
Expand All @@ -166,9 +180,13 @@ public static BO.Energiemenge Normalise(this BO.Energiemenge em, decimal target
totalConsumption = em.GetTotalConsumption();
result = em.DeepClone();
if (totalConsumption.Item1 != 0.0M)
{
scalingFactor = target / totalConsumption.Item1;
}
else
{
scalingFactor = 0.0M;
}

Parallel.ForEach(result.Energieverbrauch.Where(v => v.Einheit == totalConsumption.Item2),
v => { v.Wert = scalingFactor * v.Wert; });
Expand All @@ -188,14 +206,22 @@ public static BO.Energiemenge Normalise(this BO.Energiemenge em, decimal target
public static decimal? GetLoad(this BO.Energiemenge em, Mengeneinheit me, DateTime dt)
{
if (!me.IsIntensive())
{
throw new ArgumentException(
$"The Mengeneinheit {me} isn't intensive. Calculating the value for a specific point in time doesn't make sense.");
}

decimal? result = null;
foreach (var v in em.Energieverbrauch.Where(v => v.Startdatum <= dt && dt < v.Enddatum))
if (result.HasValue)
{
result += v.Wert;
}
else
{
result = v.Wert;
}

return result;
}

Expand All @@ -209,9 +235,16 @@ public static BO.Energiemenge Normalise(this BO.Energiemenge em, decimal target
/// <returns>Tuple of average value and unit of measurement</returns>
public static Tuple<decimal?, Mengeneinheit> GetAverage(this BO.Energiemenge em)
{
if (!IsPure(em)) throw new ArgumentException("Energiemenge is not pure.");
if (!IsPure(em))
{
throw new ArgumentException("Energiemenge is not pure.");
}

if (em.Energieverbrauch.Count == 0)
{
return Tuple.Create<decimal?, Mengeneinheit>(null, Mengeneinheit.KW);
}

if (em.Energieverbrauch.Count == 0) return Tuple.Create<decimal?, Mengeneinheit>(null, Mengeneinheit.KW);
var v = em.Energieverbrauch.First();
return Tuple.Create(em.GetAverage(v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit), v.Einheit);
}
Expand Down Expand Up @@ -251,13 +284,21 @@ public static BO.Energiemenge Normalise(this BO.Energiemenge em, decimal target
{
var overlapFactor = GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true);
if (result.HasValue)
{
result += overlapFactor * v.Wert;
}
else
{
result = v.Wert;
}

overallDenominator += overlapFactor;
}

if (result.HasValue) return result / overallDenominator;
if (result.HasValue)
{
return result / overallDenominator;
}

return null;
}
Expand Down Expand Up @@ -293,16 +334,25 @@ public static List<TimeRange> GetMissingTimeRanges(this BO.Energiemenge em, ITim


if (filteredVerbrauch.Count < 2)
{
throw new ArgumentException("Not enough entries in energieverbrauch to determine periodicity.");
}

if (!IsEvenlySpaced(em, reference, wev, obis, me, true))
{
throw new ArgumentException(
"The provided Energiemenge is not evenly spaced although gaps are allowed.");
}

var periodicity = GetTimeSpans(em, wev, obis, me).Min();
if (
Math.Abs((reference.Start - em.GetMinDate()).TotalMilliseconds % periodicity.TotalMilliseconds) !=
0)
{
throw new ArgumentException(
$"The absolute difference between reference.start ({reference.Start}) and the minimal date time in the Energiemenge ({em.GetMinDate()}) has to be an integer multiple of the periodicity {periodicity.TotalMilliseconds} but was {(reference.Start - em.GetMinDate()).TotalMilliseconds}.");
}

// since it's assured, that the energieverbrauch entries are evenly spaced it doesn't matter which entry we use to determine the duration.
var duration = filteredVerbrauch.Values.Min(v => v.Enddatum) -
filteredVerbrauch.Values.Min(v => v.Startdatum);
Expand All @@ -327,7 +377,9 @@ public static List<TimeRange> GetMissingTimeRanges(this BO.Energiemenge em, ITim
if (!filteredVerbrauch.ContainsKey(
new Tuple<DateTimeOffset?, DateTimeOffset?>(dt,
dt + duration))) // Where<Verbrauch>(v => v.startdatum == dt && v.enddatum == dt + duration).Any())
{
result.Add(new TimeRange(dt, (dt + duration).Value));
}
//}
}

Expand All @@ -345,8 +397,11 @@ public static List<TimeRange> GetMissingTimeRanges(this BO.Energiemenge em, ITim
public static List<TimeRange> GetMissingTimeRanges(this BO.Energiemenge em, TimeRange reference)
{
if (!em.IsPure())
{
throw new ArgumentException(
"The Energiemenge you provided is not pure. Consider using the overloaded method.");
}

var v = em.Energieverbrauch.FirstOrDefault();
return GetMissingTimeRanges(em, reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit);
}
Expand All @@ -372,17 +427,23 @@ public static bool IsEvenlySpaced(this BO.Energiemenge em, ITimeRange reference,
startEndDatumPeriods = GetTimeSpans(em, wev, obis, me);


if (startEndDatumPeriods.Count < 2) return true;
if (startEndDatumPeriods.Count < 2)
{
return true;
}

if (allowGaps)
{
// each time difference must be a multiple of the smallest difference.

var minDiff = startEndDatumPeriods.Min().TotalSeconds;
foreach (var ts in startEndDatumPeriods)
if (Math.Abs(ts.TotalSeconds % minDiff) != 0)
// use profiler as logger:
// use profiler as logger:

{
return false;
}


return true;
Expand All @@ -408,7 +469,9 @@ public static bool IsEvenlySpaced(this BO.Energiemenge em, bool allowGaps = fals
var combinations = GetWevObisMeCombinations(em);
foreach (var combo in combinations)
if (!em.IsEvenlySpaced(em.GetTimeRange(), combo.Item1, combo.Item2, combo.Item3, allowGaps))
{
return false;
}


return true;
Expand Down Expand Up @@ -490,8 +553,15 @@ public static decimal GetCoverage(this BO.Energiemenge em, ITimeRange reference)
{

if (!IsPure(em))
{
throw new ArgumentException("The Energiemenge is not pure. Cannot determine parameters.");
if (em.Energieverbrauch.Count == 0) return 0.0M;
}

if (em.Energieverbrauch.Count == 0)
{
return 0.0M;
}

var v = em.Energieverbrauch.First();
return em.GetCoverage(reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit);

Expand Down Expand Up @@ -571,8 +641,10 @@ private static decimal GetOverlapFactor(TimeRange period, ITimeRange reference,
try
{
if (toReference)
{
return (decimal)intersectedPeriods.TotalDuration.TotalSeconds /
(decimal)reference.Duration.TotalSeconds;
}

return (decimal)intersectedPeriods.TotalDuration.TotalSeconds / (decimal)period.Duration.TotalSeconds;
}
Expand Down Expand Up @@ -653,8 +725,14 @@ public static bool IsPureUserProperties(this BO.Energiemenge em)
if (values.TryGetValue(key, out var onlyValue))
{
if (rawValue == null && onlyValue != null)
{
return false;
if (rawValue != null && !rawValue.Equals(onlyValue)) return false;
}

if (rawValue != null && !rawValue.Equals(onlyValue))
{
return false;
}
}
else
{
Expand All @@ -674,7 +752,10 @@ public static bool IsPureUserProperties(this BO.Energiemenge em)
public static bool IsPureMengeneinheit(this BO.Energiemenge em)
{

if (em.Energieverbrauch.Select(v => v.Einheit).Distinct().Count() <= 1) return true;
if (em.Energieverbrauch.Select(v => v.Einheit).Distinct().Count() <= 1)
{
return true;
}

var me1 = em.Energieverbrauch.Select(v => v.Einheit).First();
return em.Energieverbrauch.Select(v => v.Einheit).All(me2 => me1.IsConvertibleTo(me2));
Expand Down Expand Up @@ -712,7 +793,10 @@ public static bool IsExtensive(this BO.Energiemenge em)
/// <returns>a list of pure energiemengen (<see cref="IsPure"/>)</returns>
public static List<BO.Energiemenge> SplitInPureGroups(this BO.Energiemenge em)
{
if (em.Energieverbrauch == null) return new List<BO.Energiemenge> { em };
if (em.Energieverbrauch == null)
{
return new List<BO.Energiemenge> { em };
}

var result = new List<BO.Energiemenge>();
foreach (var group in em.Energieverbrauch.GroupBy(PurityGrouper))
Expand All @@ -732,7 +816,10 @@ public static bool IsExtensive(this BO.Energiemenge em)
/// <param name="em"></param>
public static void Detangle(this BO.Energiemenge em)
{
if (em.Energieverbrauch != null) em.Energieverbrauch = VerbrauchExtension.Detangle(em.Energieverbrauch);
if (em.Energieverbrauch != null)
{
em.Energieverbrauch = VerbrauchExtension.Detangle(em.Energieverbrauch);
}
}

private class BasicVerbrauchDateTimeComparer : IComparer<CompletenessReport.BasicVerbrauch>
Expand Down
Loading

0 comments on commit 5305f96

Please sign in to comment.