using System; using System.Collections.Generic; using System.Linq; using BeWo.Data.Entities; using BS.Shared.Core; using BS.Shared.Extensions; using DevExpress.XtraScheduler; using DevExpress.XtraScheduler.Compatibility; using NHibernate.Criterion; using NHibernate.SqlCommand; namespace BeWo.Data.Utils { public class IntervalFinderHelper { public static List GenerateIntervalsForCriteria(DateTime intervalStart, DateTime intervalEnd, bool skipWeekends) { var result = new List(); if (intervalEnd <= intervalStart) { return result; } var start = intervalStart; var end = start.MergeDatesByDate(intervalEnd); while (end <= intervalEnd) { end = start.MergeDatesByDate(intervalEnd); if (skipWeekends && (start.Date.DayOfWeek == DayOfWeek.Saturday || start.Date.DayOfWeek == DayOfWeek.Sunday)) { start = start.AddDays(1); end = start.MergeDatesByDate(intervalEnd); continue; } result.AddIfNotIn(new DateTimeSpan(start, end)); start = start.AddDays(1); end = start.MergeDatesByDate(intervalEnd); } return result; } public static List CreateIntervalRecurrenceCriterias(List intervals, bool skipWeekends) { var result = new List(); foreach(var interval in intervals) { var start = interval.StartDate; var end = interval.EndDate; result.AddIfNotIn(CreateRecurrenceCriterion(start, end)); } // TODO: KGW //for (var i = 0; i < totalDays; i++) //{ // start = start.AddDays(i).MergeDatesByDate(startDate); // if (skipWeekends && (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday)) // { // continue; // } // DateTime e; // var end = start.MergeDatesByDate(endDate); // while ((e = start.AddMinutes(duration)) <= end && start <= end.AddMinutes(-1 * duration)) // { // result.AddIfNotIn(CreateRecurrenceCriterion(start, e)); // start = start.AddMinutes(intervalBuffer); // } //} return result; } private static ICriterion CreateRecurrenceCriterion(DateTime start, DateTime end) { var recurrenceBetween = $"'{start:yyyy-MM-dd HH:mm:ss}' BETWEEN STR_TO_DATE(SUBSTRING(RecurrenceInfo, 24, 19), '%m/%d/%Y %H:%i:%s') AND STR_TO_DATE(SUBSTRING(RecurrenceInfo, 50, 19), '%m/%d/%Y %H:%i:%s')"; var recurrenceAfter = $"'{start:yyyy-MM-dd HH:mm:ss}' > STR_TO_DATE(SUBSTRING(RecurrenceInfo, 24, 19), '%m/%d/%Y %H:%i:%s')"; var result = Restrictions.Or( Restrictions.And( Restrictions.Not(Restrictions.Like(nameof(SchedulerAppointment.RecurrenceInfo), "Range", MatchMode.Anywhere)), Restrictions.Like(nameof(SchedulerAppointment.RecurrenceInfo), "OccurrenceCount=\"10\"", MatchMode.Anywhere)), Restrictions.Or( Restrictions.Or( Restrictions.And(Restrictions.Lt(nameof(SchedulerAppointment.StartDate), end), Restrictions.Ge(nameof(SchedulerAppointment.EndDate), start)), Restrictions.Or(Restrictions.And( Restrictions.Like(nameof(SchedulerAppointment.RecurrenceInfo), "End", MatchMode.Anywhere), Restrictions.And(Restrictions.IsNotNull(nameof(SchedulerAppointment.RecurrenceInfo)), Expression.Sql(new SqlString(recurrenceBetween))) ), Restrictions.And( Restrictions.And( Restrictions.IsNotNull(nameof(SchedulerAppointment.RecurrenceInfo)), Restrictions.Not(Restrictions.Like(nameof(SchedulerAppointment.RecurrenceInfo), "End", MatchMode.Anywhere))), Expression.Sql(recurrenceAfter))) ), Restrictions.And(Restrictions.Eq(nameof(SchedulerAppointment.Type), 3), Expression.Sql(new SqlString(recurrenceBetween))))); return result; } public static Dictionary> CreateFreeIntervalsDictionary(IEnumerable freeIntervals) { var result = new Dictionary>(); var groupedIntervals = from dateTimeSpan in freeIntervals group dateTimeSpan by dateTimeSpan.StartDate.Date; var unsortedDictionary = new Dictionary>(); foreach (var grouping in groupedIntervals) { var orderedList = grouping.OrderBy(dateTimeSpan => dateTimeSpan.StartDate).ToList(); unsortedDictionary.AddOrUpdateValueInDictionary(grouping.Key, orderedList); } var keys = unsortedDictionary.Keys.OrderBy(key => key.Date).ToList(); foreach (var key in keys) { result.Add(key, unsortedDictionary[key]); } return result; } public static List CreateIntervals(int duration, DateTime intervalStart, DateTime intervalEnd, bool skipWeekends, int intervalBuffer) { var result = new List(); if (duration > 0 && intervalStart < intervalEnd && intervalBuffer > 10) { var timeSpan = intervalEnd - intervalStart; var totalDays = Convert.ToInt32(Math.Ceiling(timeSpan.TotalDays)); for (var i = 0; i < totalDays; i++) { var start = intervalStart.AddDays(i).MergeDatesByDate(intervalStart); if (skipWeekends && (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday)) { continue; } DateTime e; var end = start.MergeDatesByDate(intervalEnd); while ((e = start.AddMinutes(duration)) <= end && start <= end.AddMinutes(-1 * duration)) { result.Add(new DateTimeSpan(start, e)); start = start.AddMinutes(intervalBuffer); } } } return result; } public static List GenereateIntervalsForChecking(DateTime intervalStart, DateTime intervalEnd) { var start = intervalStart.Date; var end = intervalEnd.Date; var result = new List(); if (end < start) { return result; } var days = Convert.ToInt32((end - start).TotalDays); if (days == 0) { days = 1; } var rest = days % 6; var limit = (days - rest) / 6; var s = start; DateTime e; for (var i = 0; i < limit; i++) { e = s.AddDays(5); result.Add(new DateTimeSpan(s, e)); s = e.AddDays(1); } if (rest > 0) { e = s.AddDays(rest); if (rest == 1) { e = e.AddDays(-1); } result.Add(new DateTimeSpan(s, e)); } return result; } public static IEnumerable CalculateRecurrences(IEnumerable appointments, DateTime start, DateTime end, IReadOnlyCollection changedOccurrences, IReadOnlyCollection deletedOccurrences) { var result = new List(); var interval = new TimeInterval(start, end); foreach (var appointment in appointments.Where(app => app.RecurrenceInfo != null && app.Type == 1 && app.StartDate.HasValue && app.EndDate.HasValue)) { var recurrenceInfo = new RecurrenceInfo(); recurrenceInfo.FromXml(appointment.RecurrenceInfo); var occurrenceCalculator = OccurrenceCalculator.CreateInstance(recurrenceInfo); var pattern = StaticAppointmentFactory.CreateAppointment(AppointmentType.Pattern); pattern.RecurrenceInfo.FromXml(appointment.RecurrenceInfo); pattern.Start = pattern.RecurrenceInfo.Start; pattern.End = pattern.RecurrenceInfo.End; var patternId = pattern.RecurrenceInfo.Id.ToString(); var occurrences = occurrenceCalculator.CalcOccurrences(interval, pattern); if (occurrences.Count > 0) { foreach (var app in occurrences.GetAppointments(interval)) { if(appointment.EndDate == null || appointment.StartDate == null) { continue; } var index = app.RecurrenceIndex; var duration = (appointment.EndDate.Value - appointment.StartDate.Value).TotalMinutes; var s = app.Start; var e = app.Start.AddMinutes(duration); var isOutOfInterval = s.AreInBetweenDates(e, start, end) == false; var isChangedOccurrence = changedOccurrences.Any(a => a.PatternId.Equals(patternId) && a.Index == index); var isDeletedOccurrence = deletedOccurrences.Any(a => a.PatternId.Equals(patternId) && a.Index == index); if (isOutOfInterval || isChangedOccurrence || isDeletedOccurrence) { continue; } var recurringAppointment = new SchedulerAppointment { AllDay = appointment.AllDay, CustomerList = appointment.CustomerList, Notice = appointment.Notice, EmployeeList = appointment.EmployeeList, EndDate = app.Start.AddMinutes(duration), FormerBookingSequenceOid = appointment.FormerBookingSequenceOid, IsPrivate = appointment.IsPrivate, Location = appointment.Location, Originator = appointment.Originator, RecurrenceInfo = app.RecurrenceInfo.ToXml(), ReminderInfo = appointment.ReminderInfo, ResourceList = appointment.ResourceList, StartDate = app.Start, Subject = appointment.Subject ?? string.Empty, Type = appointment.Type }; result.AddIfNotIn(recurringAppointment); } } } return result; } public static IEnumerable GetRecurrencesForIntervalFinder(List appointments, DateTime startDate, DateTime endDate, IReadOnlyCollection changedOccurrences, IReadOnlyCollection deletedOccurrences, bool skipWeekends) { var result = new List(); var dayCount = Convert.ToInt32(Math.Ceiling((endDate - startDate).TotalDays)); if (dayCount <= 0) { return result; } for (var i = 0; i < dayCount; i++) { var start = startDate.AddDays(i); if (skipWeekends && (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday)) { continue; } var end = start.MergeDatesByDate(endDate); var calculatedRecurrences = CalculateRecurrences(appointments, start, end, changedOccurrences, deletedOccurrences); result.AddRange(calculatedRecurrences); } return result; } } }