/* private static IEnumerable<T> ByWeekNumber<T>(this IEnumerable<T> instances, IEnumerable<int> byWeekNumberList, Frequency recurrenceRuleType) where T : IDate
         * {
         *  switch (recurrenceRuleType)
         *  {
         *      case Frequency.Yearly:
         *          return (from instance in instances
         *                  from monthNumber in byMonthList.OrderBy(monthNumber => monthNumber)
         *                  select (T)instance.PlusMonths(monthNumber - instance.Month)).Distinct();
         *  }
         *
         *  return null;
         * } */

        private static IEnumerable <T> ByYearDay <T>(this IEnumerable <T> instances, RecurrenceRule recurrenceRule) where T : IDate
        {
            if (recurrenceRule.ByYearDay == null)
            {
                return(instances);
            }

            switch (recurrenceRule.Frequency)
            {
            case Frequency.Yearly:
                return(from instance in instances
                       from dayInYear in GetDaysOfYear(recurrenceRule.ByYearDay, instance.Year)
                       select(T) instance.PlusDays(instance.DayOfYear - dayInYear));

            case Frequency.Hourly:
            case Frequency.Minutely:
            case Frequency.Secondly:
                return
                    (instances.Where(
                         instance =>
                         GetDaysOfYear(recurrenceRule.ByYearDay, instance.Year).Contains(instance.DayOfYear)));
            }

            throw new Exception();
        }
        private static IEnumerable <T> ByMonth <T>(this IEnumerable <T> instances, RecurrenceRule recurrenceRule) where T : IDate
        {
            if (recurrenceRule.ByDay == null)
            {
                return(instances);
            }

            switch (recurrenceRule.Frequency)
            {
            case Frequency.Yearly:
                return(from instance in instances
                       from monthNumber in recurrenceRule.ByMonth.Distinct().OrderBy(monthNumber => monthNumber)
                       select(T) instance.PlusMonths(monthNumber - instance.Month));

            case Frequency.Monthly:
            case Frequency.Weekly:
            case Frequency.Daily:
            case Frequency.Hourly:
            case Frequency.Minutely:
            case Frequency.Secondly:
                return(instances.OrderedFilter(recurrenceRule.ByMonth.OrderBy(monthNumber => monthNumber),
                                               instance => instance.Month));
            }

            return(null);
        }
        private static IEnumerable <T> ByDay <T>(this IEnumerable <T> instances, RecurrenceRule recurrenceRule) where T : IDate
        {
            if (recurrenceRule.ByDay == null)
            {
                return(instances);
            }

            var limitByDay =
                instances.Where(
                    instance => recurrenceRule.ByDay.Select(weekday => weekday.Item2).Contains(instance.DayOfWeek));

            Func <bool, IEnumerable <T> > expandByDay =
                (offsetIsMonth) =>
                instances.Select(
                    instance =>
                    recurrenceRule.ByDay.Select(
                        weekdayNumber =>
                        GetDays(weekdayNumber, instance.Year, offsetIsMonth ? (int?)instance.Month : null))
                    .SelectMany(dayOfYear => dayOfYear)
                    .Select(dayOfYear => instance.PlusDays(dayOfYear - instance.DayOfYear)))
                .SelectMany(instance => instance)
                .Cast <T>();

            switch (recurrenceRule.Frequency)
            {
            case Frequency.Yearly:
                return(recurrenceRule.ByYearDay != null || recurrenceRule.ByMonthDay != null
                        ? limitByDay
                        : expandByDay(false));

            case Frequency.Monthly:
                return(recurrenceRule.ByMonthDay != null ? limitByDay : expandByDay(true));

            case Frequency.Weekly:
                return(from instance in instances
                       from weekday in
                       recurrenceRule.ByDay.Select(weekdayNumber => weekdayNumber.Item2)
                       .Distinct()
                       .OrderBy(
                           weekday =>
                           weekday <
                           recurrenceRule.WorkWeekStart.GetValueOrDefault(IsoDayOfWeek.Monday))
                       .ThenBy(weekday => weekday)
                       select WeekDayDifference(instance, weekday, recurrenceRule.WorkWeekStart));

            case Frequency.Hourly:
            case Frequency.Minutely:
            case Frequency.Secondly:
                return(limitByDay);
            }

            return(null);
        }
        private static IEnumerable <T> GetOccurences <T>(RecurrenceRule recurrenceRule, T dateStart, DateTimeZone timeZone) where T : IDate
        {
            var instances =
                Intervals(recurrenceRule.Frequency, recurrenceRule.Interval, dateStart)
                .Select(
                    interval =>
                    GetSetOfRecurrenceInstances(recurrenceRule, interval)
                    .BySetPosition(recurrenceRule))
                .SelectMany(set => set)
                .Count(recurrenceRule)
                .Until(recurrenceRule, timeZone);

            return(instances);
        }
        private static IEnumerable <T> Until <T>(this IEnumerable <T> instances, RecurrenceRule rule, DateTimeZone timeZone) where T : IDate
        {
            var recurrenceRuleZonedDateTime = rule as RecurrenceRule <ZonedDateTime?>;
            var zonedDateTime = recurrenceRuleZonedDateTime != null
                ? recurrenceRuleZonedDateTime.Until
                : (rule is RecurrenceRule <ZonedDateTime>
                   ?(ZonedDateTime?)((RecurrenceRule <ZonedDateTime>)rule).Until
                   : null);

            if (zonedDateTime.HasValue)
            {
                return
                    (instances.TakeWhile(
                         instance =>
                         ((IDateTime)instance).ToLocalDateTime()
                         .InZoneLeniently(timeZone)
                         .CompareTo(zonedDateTime.Value) <= 0));
            }

            var recurrenceRuleDateTime = rule as RecurrenceRule <LocalDateTime?>;
            var localDateTime          = recurrenceRuleDateTime != null
                ? recurrenceRuleDateTime.Until
                : (rule is RecurrenceRule <LocalDateTime>
                   ?(LocalDateTime?)((RecurrenceRule <LocalDateTime>)rule).Until
                   : null);

            if (localDateTime.HasValue)
            {
                return(instances.TakeWhile(instance => ((IDateTime)instance).ToLocalDateTime().CompareTo(localDateTime.Value) <= 0));
            }

            var recurrenceRuleDate = rule as RecurrenceRule <LocalDate?>;
            var localDate          = recurrenceRuleDate != null
                ? recurrenceRuleDate.Until
                : (rule is RecurrenceRule <LocalDate>?(LocalDate?)((RecurrenceRule <LocalDate>)rule).Until : null);

            if (localDate.HasValue)
            {
                return(instances.TakeWhile(instance => ((IDate)instance).ToLocalDate().CompareTo(localDate.Value) <= 0));
            }

            return(instances);
        }
        private static IEnumerable <T> GetSetOfRecurrenceInstances <T>(RecurrenceRule recurrenceRule, T instance) where T : IDate
        {
            var set = Enumerable.Repeat(instance, 1)
                      .ByMonth(recurrenceRule)
                      .ByYearDay(recurrenceRule)
                      .ByMonthDay(recurrenceRule)
                      .ByDay(recurrenceRule);

            if (instance is IDateTime)
            {
                set =
                    set.Cast <IDateTime>()
                    .ByHour(recurrenceRule)
                    .ByMinute(recurrenceRule)
                    .BySecond(recurrenceRule)
                    .Cast <T>();
            }

            return(set);
        }
 public static IEnumerable <LocalDate> GetOccurences(RecurrenceRule recurrenceRule, LocalDate dateStart)
 {
     return(GetOccurences(recurrenceRule, new Date(dateStart), null).Select(o => o.ToLocalDate()));
 }
 public static IEnumerable <ZonedDateTime> GetOccurences(RecurrenceRule <LocalDateTime?> recurrenceRule, LocalDateTime dateStart, DateTimeZone dateStartTimeZone)
 {
     return
         (GetOccurences(recurrenceRule, new DateTime(dateStart), dateStartTimeZone)
          .Select(o => o.ToLocalDateTime().InZoneLeniently(dateStartTimeZone)));
 }
 private static IEnumerable <T> Count <T>(this IEnumerable <T> instances, RecurrenceRule recurrenceRule)
     where T : IDate
 {
     return(recurrenceRule.Count.HasValue ? instances.Take(recurrenceRule.Count.Value) : instances);
 }
        private static IEnumerable <T> BySetPosition <T>(this IEnumerable <T> instances, RecurrenceRule recurrenceRule)
        {
            if (recurrenceRule.BySetPosition == null)
            {
                return(instances);
            }

            return
                (instances.Where(
                     (instance, index) =>
                     recurrenceRule.BySetPosition.Select(setPositionDay => GetIndex(setPositionDay, instances.Count()))
                     .Contains(index)));
        }
        private static IEnumerable <IDateTime> BySecond(this IEnumerable <IDateTime> instances, RecurrenceRule recurrenceRule)
        {
            switch (recurrenceRule.Frequency)
            {
            case Frequency.Yearly:
            case Frequency.Monthly:
            case Frequency.Weekly:
            case Frequency.Daily:
            case Frequency.Hourly:
            case Frequency.Minutely:
                return(from instance in instances
                       from second in recurrenceRule.BySecond.Distinct().OrderBy(second => second)
                       select instance.PlusSeconds(second - instance.Second));

            case Frequency.Secondly:
                return(instances.Where(instance => recurrenceRule.BySecond.Contains(instance.Second)));
            }

            return(null);
        }
        private static IEnumerable <IDateTime> ByMinute(this IEnumerable <IDateTime> instances, RecurrenceRule recurrenceRule)
        {
            switch (recurrenceRule.Frequency)
            {
            case Frequency.Yearly:
            case Frequency.Monthly:
            case Frequency.Weekly:
            case Frequency.Daily:
            case Frequency.Hourly:
                return((from instance in instances
                        from minute in recurrenceRule.ByMinute.OrderBy(minute => minute)
                        select instance.PlusMinutes(minute - instance.Minute)).Distinct());

            case Frequency.Minutely:
            case Frequency.Secondly:
                return(instances.Where(instance => recurrenceRule.ByMinute.Contains(instance.Hour)));
            }

            return(null);
        }
        private static IEnumerable <T> ByMonthDay <T>(this  IEnumerable <T> instances, RecurrenceRule recurrenceRule) where T : IDate
        {
            switch (recurrenceRule.Frequency)
            {
            case Frequency.Yearly:
            case Frequency.Monthly:
                return
                    (instances.SelectMany(
                         instance =>
                         recurrenceRule.ByMonthDay.Select(monthDay => GetDayOfMonth(monthDay, instance.Year, instance.Month))
                         .Where(dayOfMonth => dayOfMonth.HasValue)
                         .Select(dayOfMonth => dayOfMonth.Value)
                         .OrderBy(dayOfMonth => dayOfMonth)
                         .Distinct(),
                         (instance, dayOfMonth) => (T)instance.PlusDays(instance.Day - dayOfMonth)));

            case Frequency.Daily:
            case Frequency.Hourly:
            case Frequency.Minutely:
            case Frequency.Secondly:
                return
                    (instances.Where(
                         instance =>
                         recurrenceRule.ByMonthDay.Select(monthDay => GetDayOfMonth(monthDay, instance.Year, instance.Month))
                         .Where(dayOfMonth => dayOfMonth.HasValue)
                         .Select(dayOfMonth => dayOfMonth.Value)
                         .Contains(instance.Day)));
            }
            return(null);
        }