示例#1
0
        public static TInterval[] MergeIntervals <TInterval>(params TInterval[] sourceIntervals)
            where TInterval : IRegisteredInterval
        {
            var sortedIntervals = sourceIntervals
                                  .OrderByDescending(oio => oio.StartTS.HasValue ? oio.StartTS.Value : DateTime.MinValue)
                                  .ThenByDescending(oio => oio.RegistrationDate.Value)
                                  .ToArray();

            var ret = new List <TInterval>();

            if (sortedIntervals.Length > 0)
            {
                ret.Add(sortedIntervals.First());
            }

            foreach (var interval in sortedIntervals.Skip(1))
            {
                if (VirkningType.ToStartDateTimeOrMinValue(interval.StartTS) < VirkningType.ToStartDateTimeOrMinValue(ret.First().StartTS))
                {
                    if (!interval.EndTS.HasValue || interval.EndTS.Value > VirkningType.ToStartDateTimeOrMinValue(ret.First().StartTS))
                    {
                        interval.EndTS = VirkningType.ToStartDateTimeOrMinValue(ret.First().StartTS);
                    }

                    ret.Insert(0, interval);
                }
                else
                {
                    // Cannot insert any previous intervals if latest inserted interval has no start date
                }
            }

            return(ret.ToArray());
        }
示例#2
0
        public static TInterval[] CreateFromData <TInterval>(IQueryable <ITimedType> dataObjects, DataTypeTags[] allTags)
            where TInterval : Interval, new()
        {
            dataObjects = dataObjects.Where(o => allTags.Contains(o.Tag));

            // Filter objects based on correction markers
            dataObjects = CorrectionMarker.Filter(dataObjects);

            // In case we have no correction records for history, check for possible overwrites
            dataObjects = Overwrite.Filter(dataObjects);

            // TODO: Also filter out objects that have StartDate<EndDate and an uncertainty marker on either dates (Like some HistoricalChurchInformation records)

            // sort by start date
            var sortedByStartDate = dataObjects
                                    .Select(o => new { StartTS = VirkningType.ToStartDateTimeOrMinValue(o.ToStartTS()), Object = o })
                                    .OrderBy(o => o.StartTS)
                                    .ToArray();

            var ret = new List <TInterval>();

            // Group by start date
            foreach (var dataObject in sortedByStartDate)
            {
                var  currentInterval = ret.LastOrDefault();
                bool sameInterval    =
                    currentInterval != null
                    &&
                    (
                        (dataObject.StartTS == currentInterval.StartTS.Value)
                        ||
                        (
                            currentInterval.StartDate.Value == currentInterval.StartTS.Value &&
                            dataObject.StartTS.Date == currentInterval.StartDate
                        )
                    );

                if (sameInterval)
                {
                    currentInterval.Data.Add(dataObject.Object);
                    if (currentInterval.StartDate.Value == currentInterval.StartTS.Value)
                    {
                        currentInterval.StartTS = dataObject.StartTS;
                    }
                }
                else
                {
                    currentInterval = new TInterval()
                    {
                        StartTS = dataObject.StartTS,
                        EndTS   = null,
                        Data    = new List <ITimedType>(new ITimedType[] { dataObject.Object })
                    };
                    ret.Add(currentInterval);
                }
            }

            // Filter to only intervals that either have a non null start or that have objects that can mark interval start with null value
            ret = ret.Where(intvl => intvl.Data.Where(o => o.ToStartTS().HasValue || CreateIntervalIfStartTsIsNullAttribute.GetValue(o.GetType())).FirstOrDefault() != null).ToList();

            // Fill the missing information
            foreach (var currentInterval in ret)
            {
                var missingTags = allTags.Where(tag => currentInterval.Data.Where(o => o.Tag == tag).Count() == 0);
                foreach (var missingTag in missingTags)
                {
                    var missingTagObject = dataObjects.Where(
                        o => o.Tag == missingTag &&
                        Utilities.Dates.DateRangeIncludes(o.ToStartTS(), o.ToEndTS(), currentInterval.StartTS)
                        ).FirstOrDefault();
                    if (missingTagObject != null)
                    {
                        currentInterval.Data.Add(missingTagObject);
                    }
                }
            }

            // Now set the end dates
            for (int i = 0; i < ret.Count; i++)
            {
                var currentInterval = ret[i];
                if (currentInterval.StartTS == DateTime.MinValue)
                {
                    currentInterval.StartTS = null;
                }

                // TODO: Do now allow Protection intervals to set end date for the last interval. Does that differ if the end date is in the future?
                currentInterval.EndTS = currentInterval.Data.Where(o => o.ToEndTS().HasValue).Select(o => o.ToEndTS()).Min();
                if (i < ret.Count - 1)
                {
                    var nextInterval = ret[i + 1];
                    if (currentInterval.EndTS == null || currentInterval.EndTS > nextInterval.StartTS)
                    {
                        currentInterval.EndTS = nextInterval.StartTS;
                    }
                }
            }

            // Now extend the last interval if it was closed by a type that cannot close open ends
            var lastInterval = ret.LastOrDefault();

            if (lastInterval != null && lastInterval.EndTS.HasValue)
            {
                var suggestedData    = lastInterval.Data.Where(dataObject => CannotCloseOpenEndIntervalsAttribute.GetValue(dataObject.GetType()) == false).ToList();
                var suggestedEndDate = suggestedData.Where(d => d.ToEndTS().HasValue).Select(d => d.ToEndTS()).Max();
                if (
                    suggestedData.Count < lastInterval.Data.Count &&
                    (!suggestedEndDate.HasValue || suggestedEndDate.Value > lastInterval.EndTS.Value)
                    )
                {
                    var suggestedInterval = new TInterval()
                    {
                        Data    = suggestedData,
                        StartTS = lastInterval.EndTS,
                        EndTS   = suggestedEndDate
                    };
                    ret.Add(suggestedInterval);
                }
            }

            return(ret.ToArray());
        }