public ReservationDurations(IEnumerable <IReservation> reservations, IEnumerable <ICost> costs, DateTime sd, DateTime ed) { var dateRange = DateRange.ExpandRange(reservations, sd, ed); var items = ReservationDateRangeItem.GetReservationDateRangeItems(reservations, costs); var range = new ReservationDateRange(items, dateRange); CreateItems(range); }
private void CreateItems(ReservationDateRange range) { _range = range; _items = new Dictionary <int, List <ReservationDurationItem> >(); _reservations = new List <ReservationDateRangeItem>(); _anomalies = new List <ReservationDateRangeItem>(); if (_range.Count == 0) { throw new NullReferenceException("range.Count is zero. This should be checked for and handled before this point."); } foreach (int resourceId in _range.Select(x => x.ResourceID).Distinct()) { _range.Clear(); /********** * each priority group must be mutually exclusive, i.e. no single reservation should * be in two groups, and all reservations must be included across all groups * * "started normal" means started on or after the scheduled start time * * "ended normal" means ended on or before the scheduled end time * * the lowest priority group is written to the array first, then the next highest * priorty group is written over that and then the next until all groups have been written ***********/ var query = _range.Where(x => x.ResourceID == resourceId).ToList(); // These are normal reservations for which we can calculate ranges. List <ReservationDateRangeItem> include = new List <ReservationDateRangeItem>(); // These are reservations that we can't calculate ranges for, probably because they are still running. List <ReservationDateRangeItem> exclude = new List <ReservationDateRangeItem>(); // Priority 0 (lowest): unstarted, cancelled include.AddRange(_range.Apply(0, query.Where(x => !x.IsStarted && !x.IsActive).OrderBy(x => x.LastModifiedOn).ToList())); // Priority 1: unstarted, uncancelled include.AddRange(_range.Apply(1, query.Where(x => !x.IsStarted && x.IsActive).OrderBy(x => x.LastModifiedOn).ToList())); // Priority 2: started normal, ended normal include.AddRange(_range.Apply(2, query.Where(x => x.IsStarted && x.ActualBeginDateTime.HasValue && x.ActualBeginDateTime.Value >= x.BeginDateTime && x.ActualEndDateTime.HasValue && x.ActualEndDateTime.Value <= x.EndDateTime).OrderBy(x => x.LastModifiedOn).ToList())); // Priority 3: started early, ended normal include.AddRange(_range.Apply(3, query.Where(x => x.IsStarted && x.ActualBeginDateTime.HasValue && x.ActualBeginDateTime.Value < x.BeginDateTime && x.ActualEndDateTime.HasValue && x.ActualEndDateTime.Value <= x.EndDateTime).OrderBy(x => x.ActualBeginDateTime).ToList())); // Priority 4: started normal, ended late include.AddRange(_range.Apply(4, query.Where(x => x.IsStarted && x.ActualBeginDateTime.HasValue && x.ActualBeginDateTime.Value >= x.BeginDateTime && x.ActualEndDateTime.HasValue && x.ActualEndDateTime.Value > x.EndDateTime).OrderByDescending(x => x.ActualBeginDateTime).ToList())); // Priority 5: started early, ended late include.AddRange(_range.Apply(5, query.Where(x => x.IsStarted && x.ActualBeginDateTime.HasValue && x.ActualBeginDateTime.Value <x.BeginDateTime && x.ActualEndDateTime.HasValue && x.ActualEndDateTime.Value> x.EndDateTime).OrderBy(x => x.LastModifiedOn).ToList())); // catch reservations that were not selected in one of the above groups (includes reservations that were started but have not ended yet) exclude = query.Where(x => x.IsStarted && (!x.ActualBeginDateTime.HasValue || !x.ActualEndDateTime.HasValue)).ToList(); _reservations.AddRange(include); _anomalies.AddRange(exclude); int count = include.Count() + exclude.Count(); int totalCount = query.Count(); if (count < totalCount) { throw new InvalidOperationException(string.Format("ReservationDuration: Reservation count validation failed. Some reservations not selected. [ResourceID = {0}, StartDate = {1:yyyy-MM-dd HH:mm:ss}, EndDate = {2:yyyy-MM-dd HH:mm:ss}, count = {3}, totalCount = {4}]", resourceId, _range.DateRange.StartDate, _range.DateRange.EndDate, count, totalCount)); } else if (count > totalCount) { throw new InvalidOperationException(string.Format("ReservationDuration: Reservation count validation falied. Some reservations selected more than once. [ResourceID = {0}, StartDate = {1:yyyy-MM-dd HH:mm:ss}, EndDate = {2:yyyy-MM-dd HH:mm:ss}, count = {3}, totalCount = {4}]", resourceId, _range.DateRange.StartDate, _range.DateRange.EndDate, count, totalCount)); } var items = new List <ReservationDurationItem>(); var ordered = include.OrderBy(x => x.ChargeBeginDateTime).ThenBy(x => x.ChargeEndDateTime).ThenBy(x => x.ReservationID).ToList(); foreach (ReservationDateRangeItem i in ordered) { var utilized = _range.GetUtilizedDuration(i.ReservationID); items.Add(new ReservationDurationItem(i, utilized)); } _items.Add(resourceId, items); } }
public ReservationDurations(ReservationDateRange range) { CreateItems(range); }