Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Linq;
- using System.Reflection;
- namespace RemsReachWebServices.Helpers
- {
- #region Custom Attributes
- [AttributeUsage(AttributeTargets.Property)]
- public class DoNotCopyIntoTimeWindow : Attribute { } // leave default
- [AttributeUsage(AttributeTargets.Property)]
- public class IsProcessedIntoTimeWindow : Attribute { } // calculate time window for this property
- [AttributeUsage(AttributeTargets.Property)]
- public class IsTimeWindowDate : Attribute { } // attribute to mark property as the datetime
- [AttributeUsage(AttributeTargets.Property)]
- public class IsTimeWindowIdentifier : Attribute { } // this is the time window property
- #endregion
- public class TimeWindow
- {
- #region Structs
- public struct TimeWindowDictionary
- {
- public PropertyInfo PropertyInfo { get; set; }
- public Dictionary<NullObject<dynamic>, int> Dictionary { get; set; }
- }
- public struct NullObject<T>
- {
- [DefaultValue(true)]
- private readonly bool isnull; // default property initializers are not supported for structs
- private NullObject(T item, bool isnull) : this()
- {
- this.isnull = isnull;
- Item = item;
- }
- public NullObject(T item) : this(item, item == null)
- {
- }
- public static NullObject<T> Null()
- {
- return new NullObject<T>();
- }
- public T Item { get; private set; }
- public bool IsNull()
- {
- return isnull;
- }
- public static implicit operator T(NullObject<T> nullObject)
- {
- return nullObject.Item;
- }
- public static implicit operator NullObject<T>(T item)
- {
- return new NullObject<T>(item);
- }
- public override string ToString()
- {
- return (Item != null) ? Item.ToString() : "NULL";
- }
- public override bool Equals(object obj)
- {
- if (obj == null)
- return IsNull();
- if (!(obj is NullObject<T>))
- return false;
- var no = (NullObject<T>)obj;
- if (IsNull())
- return no.IsNull();
- if (no.IsNull())
- return false;
- return Item.Equals(no.Item);
- }
- public override int GetHashCode()
- {
- if (IsNull())
- return 0;
- var result = Item.GetHashCode();
- if (result >= 0)
- result++;
- return result;
- }
- }
- public struct Properties
- {
- public List<PropertyInfo> PropertiesToProcess { get; set; }
- public List<PropertyInfo> CopyProperties { get; set; }
- public PropertyInfo TimeWindowIdentifier { get; set; }
- public PropertyInfo DatePropertyInfo { get; set; }
- public int Size { get; set; }
- }
- #endregion
- #region Class Members
- private static readonly ConcurrentDictionary<Type, Properties> PropertiesDictionary = new ConcurrentDictionary<Type, Properties>();
- #endregion
- #region Methods
- public static IEnumerable<T> CalculateTimeWindows<T>(DateTime dateFrom, DateTime dateTo, List<T> stateModels) where T : new()
- {
- if (stateModels.Count() == 0)
- return new List<T>();
- dateFrom = GetPropertiesAndDictionaries(
- dateFrom,
- stateModels,
- out PropertyInfo datePropertyInfo,
- out List<PropertyInfo> copyProperties,
- out PropertyInfo timeWindowIdentifier,
- out int size,
- out TimeWindowDictionary[] dictionaries);
- byte[] windowDurations = { 5, 15, 60 };
- return windowDurations.SelectMany(wd =>
- CalculateTimeWindow(
- dateFrom,
- dateTo,
- stateModels,
- wd,
- datePropertyInfo,
- copyProperties,
- timeWindowIdentifier,
- size,
- dictionaries));
- }
- public static IEnumerable<T> CalculateTimeWindow<T>(DateTime dateFrom, DateTime dateTo, List<T> stateModels, byte timeWindowMinutes, PropertyInfo datePropertyInfo, List<PropertyInfo> copyProperties, PropertyInfo timeWindowIdentifier, int size, TimeWindowDictionary[] dictionaries) where T : new()
- {
- if (stateModels.Count() > 0)
- {
- DateTime currentWindowFrom, currentWindowTo, nextWindowFrom;
- nextWindowFrom = dateFrom;
- int itemPointer = 0;
- T prevItem = default;
- T prevTimeWindow = default;
- int j = 1;
- do // one time window
- {
- for (int i = 0; i < size; i++)
- dictionaries[i].Dictionary = new Dictionary<NullObject<dynamic>, int>();
- currentWindowFrom = nextWindowFrom;
- nextWindowFrom = currentWindowFrom.AddMinutes(timeWindowMinutes);
- currentWindowTo = nextWindowFrom.AddSeconds(-1);
- var calculateTime = currentWindowFrom;
- for (; itemPointer < stateModels.Count(); itemPointer++)
- {
- var item = stateModels.ElementAt(itemPointer);
- var date = (DateTime)datePropertyInfo.GetValue(item);
- if (date >= currentWindowTo)
- break;
- var endDate = (date > currentWindowTo) ? nextWindowFrom : date; // state might extend more than the end of the time window
- CalculateStateSeconds(prevItem, dictionaries, calculateTime, endDate);
- prevItem = item;
- calculateTime = (date < currentWindowFrom) ? currentWindowFrom : date; // to fix the 'yesterday' date
- }
- if (calculateTime < currentWindowTo)
- CalculateStateSeconds(prevItem, dictionaries, calculateTime, nextWindowFrom);
- if (dictionaries[0].Dictionary.Count > 0)
- {
- bool sameAsPrevious = (prevTimeWindow != null);
- var output = new T();
- foreach (var dictionary in dictionaries)
- {
- var maxValue = dictionary.Dictionary.First();
- for (j = 1; j < dictionary.Dictionary.Count; j++)
- {
- var valuePair = dictionary.Dictionary.ElementAt(j);
- if (valuePair.Value > maxValue.Value)
- maxValue = valuePair;
- }
- var valToSet = maxValue.Key.Item;
- if (sameAsPrevious)
- {
- var prevVal = GetValue(prevTimeWindow, dictionary.PropertyInfo);
- if (!(valToSet == null && prevVal == null))
- sameAsPrevious = (valToSet == prevVal);
- }
- SetValue(output, dictionary.PropertyInfo, valToSet);
- }
- if (!sameAsPrevious)
- {
- foreach (var copyProperty in copyProperties)
- SetValue(output, copyProperty, copyProperty.GetValue(prevItem));
- timeWindowIdentifier.SetValue(output, timeWindowMinutes);
- datePropertyInfo.SetValue(output, currentWindowFrom);
- prevTimeWindow = output;
- yield return output;
- }
- }
- }
- while (nextWindowFrom <= dateTo);
- }
- }
- private static DateTime GetPropertiesAndDictionaries<T>(DateTime dateFrom, List<T> stateModels, out PropertyInfo datePropertyInfo, out List<PropertyInfo> copyProperties, out PropertyInfo timeWindowIdentifier, out int size, out TimeWindowDictionary[] dictionaries) where T : new()
- {
- Type tType = typeof(T);
- if (!PropertiesDictionary.TryGetValue(tType, out Properties properties))
- {
- var propInfos = tType.GetProperties();
- datePropertyInfo = propInfos.Single(p => p.GetCustomAttributes(typeof(IsTimeWindowDate), true).Any());
- var propertiesToProcess = propInfos.Where(p => p.GetCustomAttributes(typeof(IsProcessedIntoTimeWindow), true).Any()).ToList();
- copyProperties = propInfos.Where(p => !p.GetCustomAttributes(typeof(IsTimeWindowIdentifier), true).Any() && !p.GetCustomAttributes(typeof(DoNotCopyIntoTimeWindow), true).Any() && !p.GetCustomAttributes(typeof(IsTimeWindowDate), true).Any() && !p.GetCustomAttributes(typeof(IsProcessedIntoTimeWindow), true).Any() && p.CanWrite && !p.GetMethod.IsVirtual).ToList();
- timeWindowIdentifier = propInfos.Single(p => p.GetCustomAttributes(typeof(IsTimeWindowIdentifier), true).Any());
- size = propertiesToProcess.Count();
- properties = new Properties()
- {
- CopyProperties = copyProperties,
- DatePropertyInfo = datePropertyInfo,
- PropertiesToProcess = propertiesToProcess,
- TimeWindowIdentifier = timeWindowIdentifier,
- Size = size
- };
- PropertiesDictionary.TryAdd(tType, properties);
- }
- else
- {
- datePropertyInfo = properties.DatePropertyInfo;
- copyProperties = properties.CopyProperties;
- timeWindowIdentifier = properties.TimeWindowIdentifier;
- size = properties.Size;
- }
- dictionaries = properties.PropertiesToProcess
- .Select(p => new TimeWindowDictionary { PropertyInfo = p })
- .ToArray();
- var firstDate = (DateTime)datePropertyInfo.GetValue(stateModels.First());
- if (firstDate < dateFrom)
- dateFrom = new DateTime(firstDate.Year, firstDate.Month, firstDate.Day, firstDate.Hour, 0, 0, DateTimeKind.Utc);
- return dateFrom;
- }
- private static dynamic GetValue(object inputObject, PropertyInfo propertyInfo)
- {
- return propertyInfo.GetValue(inputObject);
- }
- //private static void SetValue(object inputObject, string propertyName, object propertyVal)
- private static void SetValue(object inputObject, PropertyInfo propertyInfo, object propertyVal)
- {
- if (propertyVal != null)
- {
- //find the property type
- Type propertyType = propertyInfo.PropertyType;
- //Convert.ChangeType does not handle conversion to nullable types
- //if the property type is nullable, we need to get the underlying type of the property
- var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType;
- //Returns an System.Object with the specified System.Type and whose value is
- //equivalent to the specified object.
- propertyVal = Convert.ChangeType(propertyVal, targetType);
- }
- //Set the value of the property
- propertyInfo.SetValue(inputObject, propertyVal, null);
- }
- private static bool IsNullableType(Type type)
- {
- return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
- }
- private static void CalculateStateSeconds<T>(T prevItem, IEnumerable<TimeWindowDictionary> dictionaries, DateTime calculateTime, DateTime endDate)
- {
- if (prevItem != null)
- {
- var seconds = Convert.ToInt32(endDate.Subtract(calculateTime).TotalSeconds);
- foreach (var dictionary in dictionaries)
- {
- var key = dictionary.PropertyInfo.GetValue(prevItem);
- dictionary.Dictionary.TryGetValue(key, out int existingSeconds);
- dictionary.Dictionary[key] = existingSeconds + seconds;
- }
- }
- }
- #endregion
- }
- }
- myList1.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList1).ToList());
- myList2.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList2).ToList());
- myList3.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList3).ToList());
- myList4.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList4).ToList());
- myList5.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList5).ToList());
- myList6.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList6).ToList());
- myList7.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList7).ToList());
- myList8.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList8).ToList());
- myList9.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList9).ToList());
- myList10.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList10).ToList());
- myList11.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList11).ToList());
- myList12.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList12).ToList());
- myList13.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList13).ToList());
- myList14.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList14).ToList());
- myList15.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList15).ToList());
- myList16.AddRange(TimeWindow.CalculateTimeWindows(dateFrom, dateTo, myList16).ToList());
- if (stateModels.Count() == 0)
- return new List<T>();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement