Exemple #1
0
        public void CalendarGetGapTest()
        {
            // simmulation of some reservations
            var periods = new TimePeriodCollection
            {
                new DayRangeCollection(2011, 3, 7, 2),
                new DayRangeCollection(2011, 3, 16, 2)
            };

            // the overall search range
            var limits = new CalendarTimeRange(new DateTime(2011, 3, 4), new DateTime(2011, 3, 21));
            var days   = new DayRangeCollection(limits.Start, limits.Duration.Days + 1);

            // limits의 내부이고, 주말인 DayRange를 추가합니다.
            var excludeDays = days.GetDays().Where(day => limits.HasInside(day) && day.DayOfWeek.IsWeekEnd());

            periods.AddAll(excludeDays.Cast <ITimePeriod>());

            var gapCalculator = new TimeGapCalculator <TimeRange>(new TimeCalendar());
            var gaps          = gapCalculator.GetGaps(periods, limits);

            gaps.Count.Should().Be(4);
            gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 4), DurationUtil.Days(1))).Should().Be.True();
            gaps[1].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 9), DurationUtil.Days(3))).Should().Be.True();
            gaps[2].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 14), DurationUtil.Days(2))).Should().Be.True();
            gaps[3].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 18), DurationUtil.Days(1))).Should().Be.True();
        }
Exemple #2
0
        public void SortByEndTest()
        {
            DateTime             now         = ClockProxy.Clock.Now;
            SchoolDay            schoolDay   = new SchoolDay(now);
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            timePeriods.AddAll(schoolDay);

            timePeriods.SortByEnd(ListSortDirection.Descending);

            Assert.Equal(timePeriods[0], schoolDay.Lesson4);
            Assert.Equal(timePeriods[1], schoolDay.Break3);
            Assert.Equal(timePeriods[2], schoolDay.Lesson3);
            Assert.Equal(timePeriods[3], schoolDay.Break2);
            Assert.Equal(timePeriods[4], schoolDay.Lesson2);
            Assert.Equal(timePeriods[5], schoolDay.Break1);
            Assert.Equal(timePeriods[6], schoolDay.Lesson1);

            timePeriods.SortByEnd();

            Assert.Equal(timePeriods[0], schoolDay.Lesson1);
            Assert.Equal(timePeriods[1], schoolDay.Break1);
            Assert.Equal(timePeriods[2], schoolDay.Lesson2);
            Assert.Equal(timePeriods[3], schoolDay.Break2);
            Assert.Equal(timePeriods[4], schoolDay.Lesson3);
            Assert.Equal(timePeriods[5], schoolDay.Break3);
            Assert.Equal(timePeriods[6], schoolDay.Lesson4);
        }         // SortByEndTest
        }         // CalculateNextStateChange

        // ----------------------------------------------------------------------
        private ITimePeriodCollection GetWeekExcludePeriods(DateTime moment)
        {
            ITimePeriodCollection weekExcludePeriods = new TimePeriodCollection();

            weekExcludePeriods.AddAll(holidays);

            Week calendarWeek = new Week(moment);

            foreach (Day calendarDay in calendarWeek.GetDays())
            {
                ScheduleDay <T> day = week[calendarDay.DayOfWeek];
                weekExcludePeriods.AddAll(day.GetExcludePeriods(calendarDay.Start));
            }

            return(new TimePeriodCombiner <T>().CombinePeriods(weekExcludePeriods));
        }         // GetWeekExcludePeriods
Exemple #4
0
        public void GetGapTest()
        {
            DateTime                      now            = ClockProxy.Clock.Now;
            SchoolDay                     schoolDay      = new SchoolDay(now);
            TimePeriodCollection          excludePeriods = new TimePeriodCollection();
            TimeGapCalculator <TimeRange> gapCalculator  = new TimeGapCalculator <TimeRange>();

            excludePeriods.AddAll(schoolDay);

            Assert.Equal(0, gapCalculator.GetGaps(excludePeriods).Count);
            Assert.Equal(0, gapCalculator.GetGaps(excludePeriods, schoolDay).Count);

            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            excludePeriods.Add(schoolDay.Lesson2);
            excludePeriods.Add(schoolDay.Lesson3);
            excludePeriods.Add(schoolDay.Lesson4);

            ITimePeriodCollection gaps2 = gapCalculator.GetGaps(excludePeriods);

            Assert.Equal(3, gaps2.Count);
            Assert.True(gaps2[0].IsSamePeriod(schoolDay.Break1));
            Assert.True(gaps2[1].IsSamePeriod(schoolDay.Break2));
            Assert.True(gaps2[2].IsSamePeriod(schoolDay.Break3));

            TimeRange             testRange3 = new TimeRange(schoolDay.Lesson1.Start, schoolDay.Lesson4.End);
            ITimePeriodCollection gaps3      = gapCalculator.GetGaps(excludePeriods, testRange3);

            Assert.Equal(3, gaps3.Count);
            Assert.True(gaps3[0].IsSamePeriod(schoolDay.Break1));
            Assert.True(gaps3[1].IsSamePeriod(schoolDay.Break2));
            Assert.True(gaps3[2].IsSamePeriod(schoolDay.Break3));

            TimeRange             testRange4 = new TimeRange(schoolDay.Start.AddHours(-1), schoolDay.End.AddHours(1));
            ITimePeriodCollection gaps4      = gapCalculator.GetGaps(excludePeriods, testRange4);

            Assert.Equal(5, gaps4.Count);
            Assert.True(gaps4[0].IsSamePeriod(new TimeRange(testRange4.Start, schoolDay.Start)));
            Assert.True(gaps4[1].IsSamePeriod(schoolDay.Break1));
            Assert.True(gaps4[2].IsSamePeriod(schoolDay.Break2));
            Assert.True(gaps4[3].IsSamePeriod(schoolDay.Break3));
            Assert.True(gaps4[4].IsSamePeriod(new TimeRange(testRange4.End, testRange3.End)));

            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            ITimePeriodCollection gaps8 = gapCalculator.GetGaps(excludePeriods, schoolDay.Lesson1);

            Assert.Equal(0, gaps8.Count);

            TimeRange             testRange9 = new TimeRange(schoolDay.Lesson1.Start.Subtract(new TimeSpan(1)), schoolDay.Lesson1.End.Add(new TimeSpan(1)));
            ITimePeriodCollection gaps9      = gapCalculator.GetGaps(excludePeriods, testRange9);

            Assert.Equal(2, gaps9.Count);
            Assert.Equal <TimeSpan>(gaps9[0].Duration, new TimeSpan(1));
            Assert.Equal <TimeSpan>(gaps9[1].Duration, new TimeSpan(1));
        }         // GetGapsTest
        public void CountTest() {
            var timePeriods = new TimePeriodCollection();
            timePeriods.Count.Should().Be(0);

            timePeriods.AddAll(_timeRangeTestData.AllPeriods);
            timePeriods.Count.Should().Be(_timeRangeTestData.AllPeriods.Count);

            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);
        }
Exemple #6
0
        public void CountTest()
        {
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            Assert.Equal(0, timePeriods.Count);

            timePeriods.AddAll(timeRangeTestData.AllPeriods);
            Assert.Equal <int>(timePeriods.Count, timeRangeTestData.AllPeriods.Count);

            timePeriods.Clear();
            Assert.Equal(0, timePeriods.Count);
        }         // CountTest
Exemple #7
0
        public void CountTest()
        {
            var timePeriods = new TimePeriodCollection();

            timePeriods.Count.Should().Be(0);

            timePeriods.AddAll(_timeRangeTestData.AllPeriods);
            timePeriods.Count.Should().Be(_timeRangeTestData.AllPeriods.Count);

            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);
        }
        public void ItemIndexTest() {
            var timePeriods = new TimePeriodCollection();
            var schoolDay = new SchoolDay();
            timePeriods.AddAll(schoolDay);

            Assert.AreEqual(timePeriods[0], schoolDay.Lesson1);
            Assert.AreEqual(timePeriods[1], schoolDay.Break1);
            Assert.AreEqual(timePeriods[2], schoolDay.Lesson2);
            Assert.AreEqual(timePeriods[3], schoolDay.Break2);
            Assert.AreEqual(timePeriods[4], schoolDay.Lesson3);
            Assert.AreEqual(timePeriods[5], schoolDay.Break3);
            Assert.AreEqual(timePeriods[6], schoolDay.Lesson4);
        }
Exemple #9
0
        public void ClearTest()
        {
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            Assert.Equal(0, timePeriods.Count);
            timePeriods.Clear();
            Assert.Equal(0, timePeriods.Count);

            timePeriods.AddAll(new SchoolDay());
            Assert.Equal(7, timePeriods.Count);
            timePeriods.Clear();
            Assert.Equal(0, timePeriods.Count);
        }         // ClearTest
Exemple #10
0
        public void ClearTest()
        {
            var timePeriods = new TimePeriodCollection();

            timePeriods.Count.Should().Be(0);
            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);

            timePeriods.AddAll(new SchoolDay());
            timePeriods.Count.Should().Be(7);
            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);
        }
Exemple #11
0
        public void AddAllTest()
        {
            DateTime             now         = ClockProxy.Clock.Now;
            SchoolDay            schoolDay   = new SchoolDay(now);
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            Assert.Equal(0, timePeriods.Count);

            timePeriods.AddAll(schoolDay);
            Assert.Equal(timePeriods.Count, schoolDay.Count);

            timePeriods.Clear();
            Assert.Equal(0, timePeriods.Count);
        }         // AddAllTest
Exemple #12
0
        public void AddAllTest()
        {
            var now         = ClockProxy.Clock.Now;
            var schoolDay   = new SchoolDay(now);
            var timePeriods = new TimePeriodCollection();

            timePeriods.Count.Should().Be(0);

            timePeriods.AddAll(schoolDay);
            timePeriods.Count.Should().Be(schoolDay.Count);

            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);
        }
Exemple #13
0
        public void ItemIndexTest()
        {
            TimePeriodCollection timePeriods = new TimePeriodCollection();
            SchoolDay            schoolDay   = new SchoolDay();

            timePeriods.AddAll(schoolDay);

            Assert.Equal(timePeriods[0], schoolDay.Lesson1);
            Assert.Equal(timePeriods[1], schoolDay.Break1);
            Assert.Equal(timePeriods[2], schoolDay.Lesson2);
            Assert.Equal(timePeriods[3], schoolDay.Break2);
            Assert.Equal(timePeriods[4], schoolDay.Lesson3);
            Assert.Equal(timePeriods[5], schoolDay.Break3);
            Assert.Equal(timePeriods[6], schoolDay.Lesson4);
        }         // ItemIndexTest
Exemple #14
0
        public void SortByEndTest()
        {
            DateTime             now         = ClockProxy.Clock.Now;
            SchoolDay            schoolDay   = new SchoolDay(now);
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            timePeriods.AddAll(schoolDay);

            timePeriods.SortByEnd();

            timePeriods[0].Should().Be(schoolDay.Lesson4);
            timePeriods[1].Should().Be(schoolDay.Break3);
            timePeriods[2].Should().Be(schoolDay.Lesson3);
            timePeriods[3].Should().Be(schoolDay.Break2);
            timePeriods[4].Should().Be(schoolDay.Lesson2);
            timePeriods[5].Should().Be(schoolDay.Break1);
            timePeriods[6].Should().Be(schoolDay.Lesson1);
        }
        public void IndexOfTest()
        {
            DateTime             now         = ClockProxy.Clock.Now;
            SchoolDay            schoolDay   = new SchoolDay(now);
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            Assert.AreEqual(timePeriods.IndexOf(new TimeRange()), -1);
            Assert.AreEqual(timePeriods.IndexOf(new TimeBlock()), -1);

            timePeriods.AddAll(schoolDay);

            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Lesson1), 0);
            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Break1), 1);
            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Lesson2), 2);
            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Break2), 3);
            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Lesson3), 4);
            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Break3), 5);
            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Lesson4), 6);

            timePeriods.Remove(schoolDay.Lesson1);
            Assert.AreEqual(timePeriods.IndexOf(schoolDay.Lesson1), -1);
        }         // IndexOfTest
Exemple #16
0
        // notUseTime holds disabled (grayed out) time slots. italki uses it to ensure that a session must be booked at least in 24 hours in advance.
        //private ITimePeriodCollection ProcessNotUseTime(string html, DateTime firstDay)
        //{
        //    var arrText = FindText(html, "var notUseTime=", ";");
        //    // I am not sure how many days may come in notUseTime, i.e. whether it is one- or two-dimentional. We force it to be 2D.
        //    if (!arrText.StartsWith("[[") && !arrText.EndsWith("]]"))
        //    {
        //        arrText = "[" + arrText + "]";
        //    }
        //    return ProcessDayArray(arrText, firstDay);
        //}

        private ITimePeriodCollection ProcessDayArray(string arrText, DateTime firstDay)
        {
            var periods = new TimePeriodCollection();
            var days    = JArray.Parse(arrText);

            foreach (var day in days)
            {
                // The first item is the day number. The following items are half-hour times.
                var dayNumber = (int)day.First();
                var slots     = day
                                .Skip(1)
                                .Select(i =>
                {
                    var slot  = (int)i;
                    var start = firstDay.AddDays(dayNumber).AddMinutes(slot * ItalkiTimeSlotDuration.TotalMinutes);
                    var end   = start + ItalkiTimeSlotDuration;
                    return(new TimeRange(start, end));
                });
                periods.AddAll(slots);
            }
            return(CombinePeriods(periods));
        }
Exemple #17
0
        public void IndexOfTest()
        {
            DateTime             now         = ClockProxy.Clock.Now;
            SchoolDay            schoolDay   = new SchoolDay(now);
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            Assert.Equal <int>(timePeriods.IndexOf(new TimeRange()), -1);
            Assert.Equal <int>(timePeriods.IndexOf(new TimeBlock()), -1);

            timePeriods.AddAll(schoolDay);

            Assert.Equal(0, timePeriods.IndexOf(schoolDay.Lesson1));
            Assert.Equal(1, timePeriods.IndexOf(schoolDay.Break1));
            Assert.Equal(2, timePeriods.IndexOf(schoolDay.Lesson2));
            Assert.Equal(3, timePeriods.IndexOf(schoolDay.Break2));
            Assert.Equal(4, timePeriods.IndexOf(schoolDay.Lesson3));
            Assert.Equal(5, timePeriods.IndexOf(schoolDay.Break3));
            Assert.Equal(6, timePeriods.IndexOf(schoolDay.Lesson4));

            timePeriods.Remove(schoolDay.Lesson1);
            Assert.Equal <int>(timePeriods.IndexOf(schoolDay.Lesson1), -1);
        }         // IndexOfTest
Exemple #18
0
        /// <summary>
        /// Get vacant time slots from Italki, shredded as sessions
        /// </summary>
        /// <returns></returns>
        public static async Task <IEnumerable <SessionDto> > GetOfferedSchedules(DateTime startDate, DateTime endDate, bool forceRealTime)
        {
            // Load all the HTML pages simultaneously.
            var tasks = ItalkiTeachers.Select(i => GetTeacherPeriods(i.UserId, forceRealTime));
            var teacherPeriodsArray = await Task.WhenAll(tasks);

            // italki does not allow booking in less than 24 hour.
            var threshold = GetBookingTimeThreshold();

            var allPeriods = teacherPeriodsArray
                             // Flatten all lists
                             .SelectMany(i => i)
                             // Filter
                             .Where(i =>
                                    (i.Start < endDate) &&
                                    (i.End > startDate) &&
                                    // There may be 30-minute "left over" slots available. We filter them out. Our sessions are 60 minutes.
                                    (i.Duration >= SessionDuration) &&
                                    (i.End >= threshold + SessionDuration)
                                    )
            ;

            // Merge all periods for display.
            ITimePeriodCollection periodCollection = new TimePeriodCollection();
            var periodCombiner = new TimePeriodCombiner <TeacherTimeRange>();

            periodCollection.AddAll(allPeriods);
            periodCollection = periodCombiner.CombinePeriods(periodCollection);

            var offeredSessions = periodCollection
                                  .Select(i => new SessionDto
            {
                Start = i.Start >= threshold ? i.Start : threshold,
                End   = i.End,
            });

            return(offeredSessions);
        }
Exemple #19
0
        public void IndexOfTest()
        {
            var now         = ClockProxy.Clock.Now;
            var schoolDay   = new SchoolDay(now);
            var timePeriods = new TimePeriodCollection();

            timePeriods.IndexOf(new TimeRange()).Should().Be(-1);
            timePeriods.IndexOf(new TimeBlock()).Should().Be(-1);

            timePeriods.AddAll(schoolDay);

            timePeriods.IndexOf(schoolDay.Lesson1).Should().Be(0);
            timePeriods.IndexOf(schoolDay.Break1).Should().Be(1);
            timePeriods.IndexOf(schoolDay.Lesson2).Should().Be(2);
            timePeriods.IndexOf(schoolDay.Break2).Should().Be(3);
            timePeriods.IndexOf(schoolDay.Lesson3).Should().Be(4);
            timePeriods.IndexOf(schoolDay.Break3).Should().Be(5);
            timePeriods.IndexOf(schoolDay.Lesson4).Should().Be(6);

            timePeriods.Remove(schoolDay.Lesson1);
            timePeriods.IndexOf(schoolDay.Lesson1).Should().Be(-1);
            timePeriods.IndexOf(schoolDay.Break1).Should().Be(0);
        }
        public void IndexOfTest() {
            var now = ClockProxy.Clock.Now;
            var schoolDay = new SchoolDay(now);
            var timePeriods = new TimePeriodCollection();

            timePeriods.IndexOf(new TimeRange()).Should().Be(-1);
            timePeriods.IndexOf(new TimeBlock()).Should().Be(-1);

            timePeriods.AddAll(schoolDay);

            timePeriods.IndexOf(schoolDay.Lesson1).Should().Be(0);
            timePeriods.IndexOf(schoolDay.Break1).Should().Be(1);
            timePeriods.IndexOf(schoolDay.Lesson2).Should().Be(2);
            timePeriods.IndexOf(schoolDay.Break2).Should().Be(3);
            timePeriods.IndexOf(schoolDay.Lesson3).Should().Be(4);
            timePeriods.IndexOf(schoolDay.Break3).Should().Be(5);
            timePeriods.IndexOf(schoolDay.Lesson4).Should().Be(6);

            timePeriods.Remove(schoolDay.Lesson1);
            timePeriods.IndexOf(schoolDay.Lesson1).Should().Be(-1);
            timePeriods.IndexOf(schoolDay.Break1).Should().Be(0);
        }
Exemple #21
0
        public void GetGapTest()
        {
            var now       = ClockProxy.Clock.Now;
            var schoolDay = new SchoolDay(now);

            var gapCalculator = new TimeGapCalculator <TimeRange>();

            var excludePeriods = new TimePeriodCollection();

            excludePeriods.AddAll(schoolDay);

            gapCalculator.GetGaps(excludePeriods).Count.Should().Be(0);
            gapCalculator.GetGaps(excludePeriods, schoolDay).Count.Should().Be(0);

            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            excludePeriods.Add(schoolDay.Lesson2);
            excludePeriods.Add(schoolDay.Lesson3);
            excludePeriods.Add(schoolDay.Lesson4);

            var gaps2 = gapCalculator.GetGaps(excludePeriods);

            gaps2.Count.Should().Be(3);
            gaps2[0].IsSamePeriod(schoolDay.Break1).Should().Be.True();
            gaps2[1].IsSamePeriod(schoolDay.Break2).Should().Be.True();
            gaps2[2].IsSamePeriod(schoolDay.Break3).Should().Be.True();

            var testRange3 = new TimeRange(schoolDay.Lesson1.Start, schoolDay.Lesson4.End);
            var gaps3      = gapCalculator.GetGaps(excludePeriods, testRange3);

            gaps3.Count.Should().Be(3);
            gaps3[0].IsSamePeriod(schoolDay.Break1).Should().Be.True();
            gaps3[1].IsSamePeriod(schoolDay.Break2).Should().Be.True();
            gaps3[2].IsSamePeriod(schoolDay.Break3).Should().Be.True();

            var testRange4 = new TimeRange(schoolDay.Start.AddHours(-1), schoolDay.End.AddHours(1));
            var gaps4      = gapCalculator.GetGaps(excludePeriods, testRange4);

            gaps4.Count.Should().Be(5);
            gaps4[0].IsSamePeriod(new TimeRange(testRange4.Start, schoolDay.Start)).Should().Be.True();
            gaps4[1].IsSamePeriod(schoolDay.Break1).Should().Be.True();
            gaps4[2].IsSamePeriod(schoolDay.Break2).Should().Be.True();
            gaps4[3].IsSamePeriod(schoolDay.Break3).Should().Be.True();
            gaps4[4].IsSamePeriod(new TimeRange(testRange4.End, schoolDay.End)).Should().Be.True();


            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            var gaps8 = gapCalculator.GetGaps(excludePeriods, schoolDay.Lesson1);

            gaps8.Count.Should().Be(0);


            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            var testRange9 = new TimeRange(schoolDay.Lesson1.Start.Subtract(new TimeSpan(1)), schoolDay.Lesson1.End.Add(new TimeSpan(1)));
            var gaps9      = gapCalculator.GetGaps(excludePeriods, testRange9);

            gaps9.Count.Should().Be(2);
            gaps9[0].Duration.Should().Be(TimeSpan.FromTicks(1));
            gaps9[1].Duration.Should().Be(TimeSpan.FromTicks(1));
        }
Exemple #22
0
        /// <summary>
        /// De-tangles a list of overlapping Verbrauch entries where entries can be subsets of other entries.
        /// </summary>
        /// <example>
        /// [---v1---)
        /// [-----v2------)
        /// [---------v3---------)
        /// is transformed into
        /// [--v1---)
        /// ........[-v2--)
        /// ..............[--v3--)
        /// </example>
        /// <param name="input"></param>
        /// <returns></returns>
        public static List <Verbrauch> Detangle(IEnumerable <Verbrauch> input)
        {
            //var filteredInput = KeepShortestSlices(input);
            HashSet <Verbrauch> resultSet = new HashSet <Verbrauch>();
            var groups = input.OrderBy(v => (v.Startdatum, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit)).GroupBy(v => new Tuple <Wertermittlungsverfahren, string, Mengeneinheit>
                                                                                                                           (
                                                                                                                               v.Wertermittlungsverfahren,
                                                                                                                               v.Obiskennzahl,
                                                                                                                               v.Einheit
                                                                                                                           ));

            foreach (var vGroup in groups)
            {
                HashSet <Verbrauch> subResult = new HashSet <Verbrauch>();

                // find pairs (x,y) where x.end == y.start:
                // |----x----|--------y--------|
                //var adjacentVerbrauchs = from x in vGroup join y in vGroup on x.enddatum equals y.startdatum select new { x, y };
                var adjacentVerbrauchs = from x in vGroup join y in vGroup on x.Enddatum equals y.Startdatum select new { x, y };
                foreach (var av in adjacentVerbrauchs)
                {
                    subResult.Add(av.x);
                    subResult.Add(av.y);
                }

                // |----x----|--------y--------|
                // |-------------z-------------|
                // ==> delete z from result where z.start == x.start and z.end == y.end
                //var fullyRedundantVerbrauchs = from av in adjacentVerbrauchs join z in vGroup on new { av.x.startdatum, av.y.enddatum } equals new { z.startdatum, z.enddatum } select new { av, z };
                var fullyRedundantVerbrauchs = from av in adjacentVerbrauchs join z in vGroup on new { av.x.Startdatum, av.y.Enddatum } equals new { z.Startdatum, z.Enddatum } select new { av, z };
                foreach (var frv in fullyRedundantVerbrauchs)
                {
                    if (frv.av.x.Wert + frv.av.y.Wert != frv.z.Wert)
                    {
                        throw new ArgumentException($"Inconsistent data detected: {JsonConvert.SerializeObject(frv.av.x)} + {JsonConvert.SerializeObject(frv.av.y)} ≠ {JsonConvert.SerializeObject(frv.z)}");
                    }
                    subResult.Remove(frv.z);
                }

                // |----------x----------|---y---|
                // |---------------z-------------|
                // or
                // |---y---|----------x----------|
                // |---------------z-------------|
                // or
                // |---x1--|-----y------|---x2---|
                // |--------------z--------------|
                // y and z are given. find x such that x.value == y.value+z.value
                //subResult.UnionWith(vGroup);
                subResult.UnionWith(vGroup);
                foreach (Verbrauch z in new HashSet <Verbrauch>(subResult))
                {
                    var ys = subResult.Where(y => z.Contains(y) && !z.Equals(y));
                    if (ys.Count() > 0)
                    {
                        TimePeriodSubtractor <TimeRange> tps    = new TimePeriodSubtractor <TimeRange>();
                        TimePeriodCollection             source = new TimePeriodCollection {
                            z.GetTimeRange()
                        };
                        TimePeriodCollection subtract = new TimePeriodCollection();
                        subtract.AddAll(ys.Select(y => y.GetTimeRange()));
                        ITimePeriodCollection subtractionResult = tps.SubtractPeriods(source, subtract);
                        var xs = new HashSet <Verbrauch>();
                        foreach (var tr in subtractionResult)
                        {
                            Verbrauch v = new Verbrauch()
                            {
                                Einheit = z.Einheit,
                                Wertermittlungsverfahren = z.Wertermittlungsverfahren,
                                Obiskennzahl             = z.Obiskennzahl,
                                Startdatum = tr.Start,
                                Enddatum   = tr.End
                            };
                            xs.Add(v);
                        }
                        var totalXWert     = z.Wert - ys.Select(y => y.Wert).Sum();
                        var totalXDuration = xs.Select(x => x.GetDuration().TotalSeconds).Sum();
                        foreach (var x in xs)
                        {
                            x.Wert = (totalXWert * (decimal)x.GetDuration().TotalSeconds) / ((decimal)totalXDuration);
                        }
                        subResult.Remove(z);
                        subResult.UnionWith(xs);
                    }
                }
                resultSet.UnionWith(subResult);
            }
            List <Verbrauch> result = new List <Verbrauch>(resultSet);

            result.Sort(new VerbrauchDateTimeComparer());
            return(result);
        }
Exemple #23
0
        /// <summary>
        /// <paramref name="start"/>시각으로부터 <paramref name="offset"/> 만큼 떨어진 시각을 구합니다.
        /// </summary>
        /// <param name="start">기준 시각</param>
        /// <param name="offset">기간</param>
        /// <param name="seekDirection">검색 방향 (이전|이후)</param>
        /// <param name="seekBoundaryMode">검색 값 포함 여부</param>
        /// <param name="remaining">짜투리 기간</param>
        /// <returns>기준 시각으로터 오프셋만큼 떨어진 시각</returns>
        protected DateTime? CalculateEnd(DateTime start, TimeSpan offset, SeekDirection seekDirection, SeekBoundaryMode seekBoundaryMode,
                                         out TimeSpan? remaining) {
            if(IsDebugEnabled)
                log.Debug("기준시각으로부터 오프셋만큼 떨어진 시각을 구합니다... " +
                          @"start=[{0}], offset=[{1}], seekDirection=[{2}], seekBoundaryMode=[{3}]",
                          start, offset, seekDirection, seekBoundaryMode);

            Guard.Assert(offset >= TimeSpan.Zero, "offset 값은 항상 0 이상이어야 합니다. offset=[{0}]", offset);

            remaining = offset;

            // search periods
            ITimePeriodCollection searchPeriods = new TimePeriodCollection(IncludePeriods);
            if(searchPeriods.Count == 0)
                searchPeriods.Add(TimeRange.Anytime);

            // available periods
            ITimePeriodCollection availablePeriods = new TimePeriodCollection();
            if(ExcludePeriods.Count == 0) {
                availablePeriods.AddAll(searchPeriods);
            }
            else {
                // 예외 기간을 제외합니다.
                //
                var gapCalculator = new TimeGapCalculator<TimeRange>();

                var query
                    = searchPeriods
#if !SILVERLIGHT
                        .AsParallel()
                        .AsOrdered()
#endif
                        .SelectMany(searchPeriod =>
                                    ExcludePeriods.HasOverlapPeriods(searchPeriod)
                                        ? gapCalculator.GetGaps(ExcludePeriods, searchPeriod) // 예외 기간과 검색 기간에서 겹치지 않는 기간을 계산하여, 추려냅니다.
                                        : new TimePeriodCollection { searchPeriod } // 예외 기간과 겹쳐진 부분이 없다면, 기간 전체를 추가합니다.
                        );

                availablePeriods.AddAll(query);
            }

            // 유효한 Period가 없다면 중단합니다.
            if(availablePeriods.Count == 0)
                return null;

            // 기간중에 중복되는 부분의 없도록 유효한 기간을 결합합니다.
            if(availablePeriods.Count > 1) {
                var periodCombiner = new TimePeriodCombiner<TimeRange>();
                availablePeriods = periodCombiner.CombinePeriods(availablePeriods);
            }

            // 첫 시작 기간을 찾습니다.
            //
            DateTime seekMoment;
            var startPeriod = (seekDirection == SeekDirection.Forward)
                                  ? FindNextPeriod(start, availablePeriods, out seekMoment)
                                  : FindPreviousPeriod(start, availablePeriods, out seekMoment);

            // 첫 시작 기간이 없다면 중단합니다.
            if(startPeriod == null)
                return null;

            // 오프셋 값이 0 이라면, 바로 다음 값이므로 seekMoment를 반환합니다.
            if(offset == TimeSpan.Zero)
                return seekMoment;

            if(seekDirection == SeekDirection.Forward) {
                for(var i = availablePeriods.IndexOf(startPeriod); i < availablePeriods.Count; i++) {
                    var gap = availablePeriods[i];
                    var gapRemaining = gap.End - seekMoment;

                    if(IsDebugEnabled)
                        log.Debug("Seek Forward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining,
                                  remaining, seekMoment);

                    var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill)
                                             ? gapRemaining >= remaining
                                             : gapRemaining > remaining;

                    if(isTargetPeriod) {
                        var end = seekMoment + remaining.Value;
                        remaining = null;
                        return end;
                    }

                    remaining = remaining - gapRemaining;

                    if(i == availablePeriods.Count - 1)
                        return null;

                    seekMoment = availablePeriods[i + 1].Start; // next period
                }
            }
            else {
                for(var i = availablePeriods.IndexOf(startPeriod); i >= 0; i--) {
                    var gap = availablePeriods[i];
                    var gapRemaining = seekMoment - gap.Start;

                    if(IsDebugEnabled)
                        log.Debug("Seek Backward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining,
                                  remaining, seekMoment);

                    var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill)
                                             ? gapRemaining >= remaining
                                             : gapRemaining > remaining;

                    if(isTargetPeriod) {
                        var end = seekMoment - remaining.Value;
                        remaining = null;
                        return end;
                    }
                    remaining = remaining - gapRemaining;

                    if(i == 0)
                        return null;

                    seekMoment = availablePeriods[i - 1].End; // previous period
                }
            }
            return null;
        }
        public void SortByEndTest() {
            DateTime now = ClockProxy.Clock.Now;
            SchoolDay schoolDay = new SchoolDay(now);
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            timePeriods.AddAll(schoolDay);

            timePeriods.SortByEnd();

            timePeriods[0].Should().Be(schoolDay.Lesson4);
            timePeriods[1].Should().Be(schoolDay.Break3);
            timePeriods[2].Should().Be(schoolDay.Lesson3);
            timePeriods[3].Should().Be(schoolDay.Break2);
            timePeriods[4].Should().Be(schoolDay.Lesson2);
            timePeriods[5].Should().Be(schoolDay.Break1);
            timePeriods[6].Should().Be(schoolDay.Lesson1);
        }
        public void AddAllTest() {
            var now = ClockProxy.Clock.Now;
            var schoolDay = new SchoolDay(now);
            var timePeriods = new TimePeriodCollection();

            timePeriods.Count.Should().Be(0);

            timePeriods.AddAll(schoolDay);
            timePeriods.Count.Should().Be(schoolDay.Count);

            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);
        }
        public void GetGapTest() {
            var now = ClockProxy.Clock.Now;
            var schoolDay = new SchoolDay(now);

            var gapCalculator = new TimeGapCalculator<TimeRange>();

            var excludePeriods = new TimePeriodCollection();
            excludePeriods.AddAll(schoolDay);

            gapCalculator.GetGaps(excludePeriods).Count.Should().Be(0);
            gapCalculator.GetGaps(excludePeriods, schoolDay).Count.Should().Be(0);

            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            excludePeriods.Add(schoolDay.Lesson2);
            excludePeriods.Add(schoolDay.Lesson3);
            excludePeriods.Add(schoolDay.Lesson4);

            var gaps2 = gapCalculator.GetGaps(excludePeriods);
            gaps2.Count.Should().Be(3);
            gaps2[0].IsSamePeriod(schoolDay.Break1).Should().Be.True();
            gaps2[1].IsSamePeriod(schoolDay.Break2).Should().Be.True();
            gaps2[2].IsSamePeriod(schoolDay.Break3).Should().Be.True();

            var testRange3 = new TimeRange(schoolDay.Lesson1.Start, schoolDay.Lesson4.End);
            var gaps3 = gapCalculator.GetGaps(excludePeriods, testRange3);
            gaps3.Count.Should().Be(3);
            gaps3[0].IsSamePeriod(schoolDay.Break1).Should().Be.True();
            gaps3[1].IsSamePeriod(schoolDay.Break2).Should().Be.True();
            gaps3[2].IsSamePeriod(schoolDay.Break3).Should().Be.True();

            var testRange4 = new TimeRange(schoolDay.Start.AddHours(-1), schoolDay.End.AddHours(1));
            var gaps4 = gapCalculator.GetGaps(excludePeriods, testRange4);

            gaps4.Count.Should().Be(5);
            gaps4[0].IsSamePeriod(new TimeRange(testRange4.Start, schoolDay.Start)).Should().Be.True();
            gaps4[1].IsSamePeriod(schoolDay.Break1).Should().Be.True();
            gaps4[2].IsSamePeriod(schoolDay.Break2).Should().Be.True();
            gaps4[3].IsSamePeriod(schoolDay.Break3).Should().Be.True();
            gaps4[4].IsSamePeriod(new TimeRange(testRange4.End, schoolDay.End)).Should().Be.True();


            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            var gaps8 = gapCalculator.GetGaps(excludePeriods, schoolDay.Lesson1);

            gaps8.Count.Should().Be(0);


            excludePeriods.Clear();
            excludePeriods.Add(schoolDay.Lesson1);
            var testRange9 = new TimeRange(schoolDay.Lesson1.Start.Subtract(new TimeSpan(1)), schoolDay.Lesson1.End.Add(new TimeSpan(1)));
            var gaps9 = gapCalculator.GetGaps(excludePeriods, testRange9);

            gaps9.Count.Should().Be(2);
            gaps9[0].Duration.Should().Be(TimeSpan.FromTicks(1));
            gaps9[1].Duration.Should().Be(TimeSpan.FromTicks(1));
        }
Exemple #27
0
        public void GetFreeBusyRequestTimePeriodIntersectorTest()
        {
            //取得會議室資訊
            var calendarAttributes =
                "fullName,email";
            var searchMeetingRooms = new SearchCalendarResourcesRequest(calendarAttributes);

            ZmailRequest.ApiRequest = searchMeetingRooms;
            var zResquestRoom = ZmailDispatcher.SendRequest(ZmailRequest);
            var respRoom      = zResquestRoom.ApiResponse as SearchCalendarResourcesResponse;
            var crList        = respRoom?.CalendarResourceList;

            if (crList != null)
            {
                var crEmails = crList.Select(cr => cr.AttributesList.Where(ar => ar.Key.Equals("email")).Select(ar => ar.Value).FirstOrDefault());
                var sdate    = DateTime.Now;
                var edate    = sdate.AddDays(7);
                //多人請用逗號隔開
                var crEmailStrings = string.Join(",", crEmails.ToArray());
                var searchNames    = "[email protected],[email protected]," + crEmailStrings;
                ZmailRequest.ApiRequest = new GetFreeBusyRequest(sdate, edate, searchNames);
                var zResquest = ZmailDispatcher.SendRequest(ZmailRequest);
                var resp      = zResquest.ApiResponse as GetFreeBusyResponse;
                var wkHours   = resp?.Workinghours;
                if (wkHours != null)
                {
                    var periods = new Dictionary <string, TimePeriodCollection>();
                    var users   = wkHours.Users.Where(u => !crEmails.Contains(u.id));

                    //找出所有人的共同時間
                    var periodIntersector = new TimePeriodIntersector <TimeRange>();
                    var resultPeriods     = new TimePeriodCollection();
                    var idx = 0;
                    foreach (var user in users)
                    {
                        Console.WriteLine(user.id);
                        Console.WriteLine("Free");
                        var userPeriods = new TimePeriodCollection();

                        foreach (var f in user.Fs)
                        {
                            Console.WriteLine($" {f.s} - {f.e}");
                            userPeriods.Add(new TimeRange(f.s, f.e));
                        }
                        periods.Add(user.id, userPeriods);
                        if (idx == 0)
                        {
                            resultPeriods.AddAll(user.Fs.Select(f => new TimeRange(f.s, f.e)));
                        }
                        else
                        {
                            resultPeriods.AddAll(user.Fs.Select(f => new TimeRange(f.s, f.e)));
                            if (resultPeriods.Any())
                            {
                                var intersectedPeriods = periodIntersector.IntersectPeriods(resultPeriods, false);
                                resultPeriods.Clear();
                                resultPeriods.AddAll(intersectedPeriods.Select(p => new TimeRange(p.Start, p.End)));
                            }
                        }
                    }

                    Console.WriteLine("...共同的時間...");
                    foreach (var intersectedPeriod in resultPeriods)
                    {
                        Console.WriteLine("所有人共同的的時間 Period: " + intersectedPeriod);
                    }

                    //對應到會議室
                    var crs = wkHours.Users.Where(u => crEmails.Contains(u.id));

                    foreach (var cr in crList)
                    {
                        var email = cr.AttributesList.Where(ar => ar.Key.Equals("email"))
                                    .Select(ar => ar.Value)
                                    .FirstOrDefault();
                        var fullName = cr.AttributesList.Where(ar => ar.Key.Equals("fullName"))
                                       .Select(ar => ar.Value)
                                       .FirstOrDefault();

                        Console.WriteLine($"{fullName}:{email}");
                        var crHour = wkHours.Users.FirstOrDefault(u => u.id.Equals(email));
                        if (crHour != null)
                        {
                            var crPeriods = new TimePeriodCollection();
                            crPeriods.AddAll(resultPeriods.Select(p => new TimeRange(p.Start, p.End)));
                            crPeriods.AddAll(crHour.Fs.Select(f => new TimeRange(f.s, f.e)));
                            var intersectedPeriods = periodIntersector.IntersectPeriods(crPeriods, false);
                            Console.WriteLine($"{fullName}:{email}...共同的時間...");
                            foreach (var intersectedPeriod in intersectedPeriods)
                            {
                                Console.WriteLine("    Period: " + intersectedPeriod);
                            }
                        }
                    }
                }
            }
        }
Exemple #28
0
        public void SortByTest()
        {
            DateTime             now         = ClockProxy.Clock.Now;
            SchoolDay            schoolDay   = new SchoolDay(now);
            TimePeriodCollection timePeriods = new TimePeriodCollection();

            // start
            timePeriods.Add(schoolDay.Lesson4);
            timePeriods.Add(schoolDay.Break3);
            timePeriods.Add(schoolDay.Lesson3);
            timePeriods.Add(schoolDay.Break2);
            timePeriods.Add(schoolDay.Lesson2);
            timePeriods.Add(schoolDay.Break1);
            timePeriods.Add(schoolDay.Lesson1);

            timePeriods.SortBy(TimePeriodStartComparer.Comparer);

            Assert.Equal(timePeriods[0], schoolDay.Lesson1);
            Assert.Equal(timePeriods[1], schoolDay.Break1);
            Assert.Equal(timePeriods[2], schoolDay.Lesson2);
            Assert.Equal(timePeriods[3], schoolDay.Break2);
            Assert.Equal(timePeriods[4], schoolDay.Lesson3);
            Assert.Equal(timePeriods[5], schoolDay.Break3);
            Assert.Equal(timePeriods[6], schoolDay.Lesson4);

            timePeriods.SortReverseBy(TimePeriodStartComparer.Comparer);

            Assert.Equal(timePeriods[0], schoolDay.Lesson4);
            Assert.Equal(timePeriods[1], schoolDay.Break3);
            Assert.Equal(timePeriods[2], schoolDay.Lesson3);
            Assert.Equal(timePeriods[3], schoolDay.Break2);
            Assert.Equal(timePeriods[4], schoolDay.Lesson2);
            Assert.Equal(timePeriods[5], schoolDay.Break1);
            Assert.Equal(timePeriods[6], schoolDay.Lesson1);

            // end
            timePeriods.Clear();
            timePeriods.AddAll(schoolDay);

            timePeriods.SortReverseBy(TimePeriodEndComparer.Comparer);

            Assert.Equal(timePeriods[0], schoolDay.Lesson4);
            Assert.Equal(timePeriods[1], schoolDay.Break3);
            Assert.Equal(timePeriods[2], schoolDay.Lesson3);
            Assert.Equal(timePeriods[3], schoolDay.Break2);
            Assert.Equal(timePeriods[4], schoolDay.Lesson2);
            Assert.Equal(timePeriods[5], schoolDay.Break1);
            Assert.Equal(timePeriods[6], schoolDay.Lesson1);

            timePeriods.SortBy(TimePeriodEndComparer.Comparer);

            Assert.Equal(timePeriods[0], schoolDay.Lesson1);
            Assert.Equal(timePeriods[1], schoolDay.Break1);
            Assert.Equal(timePeriods[2], schoolDay.Lesson2);
            Assert.Equal(timePeriods[3], schoolDay.Break2);
            Assert.Equal(timePeriods[4], schoolDay.Lesson3);
            Assert.Equal(timePeriods[5], schoolDay.Break3);
            Assert.Equal(timePeriods[6], schoolDay.Lesson4);

            // duration
            timePeriods.Clear();
            TimeSpan oneHour    = new TimeSpan(1, 0, 0);
            TimeSpan twoHours   = new TimeSpan(2, 0, 0);
            TimeSpan threeHours = new TimeSpan(3, 0, 0);
            TimeSpan fourHours  = new TimeSpan(4, 0, 0);

            timePeriods.Add(new TimeRange(now, oneHour));
            timePeriods.Add(new TimeRange(now, twoHours));
            timePeriods.Add(new TimeRange(now, threeHours));
            timePeriods.Add(new TimeRange(now, fourHours));

            timePeriods.SortReverseBy(TimePeriodDurationComparer.Comparer);

            Assert.Equal(fourHours, timePeriods[0].Duration);
            Assert.Equal(threeHours, timePeriods[1].Duration);
            Assert.Equal(twoHours, timePeriods[2].Duration);
            Assert.Equal(oneHour, timePeriods[3].Duration);

            timePeriods.SortBy(TimePeriodDurationComparer.Comparer);

            Assert.Equal(oneHour, timePeriods[0].Duration);
            Assert.Equal(twoHours, timePeriods[1].Duration);
            Assert.Equal(threeHours, timePeriods[2].Duration);
            Assert.Equal(fourHours, timePeriods[3].Duration);
        }         // SortByTest
Exemple #29
0
        /// <summary>
        /// <paramref name="start"/>시각으로부터 <paramref name="offset"/> 만큼 떨어진 시각을 구합니다.
        /// </summary>
        /// <param name="start">기준 시각</param>
        /// <param name="offset">기간</param>
        /// <param name="seekDirection">검색 방향 (이전|이후)</param>
        /// <param name="seekBoundaryMode">검색 값 포함 여부</param>
        /// <param name="remaining">짜투리 기간</param>
        /// <returns>기준 시각으로터 오프셋만큼 떨어진 시각</returns>
        protected DateTime?CalculateEnd(DateTime start, TimeSpan offset, SeekDirection seekDirection, SeekBoundaryMode seekBoundaryMode,
                                        out TimeSpan?remaining)
        {
            if (IsDebugEnabled)
            {
                log.Debug("기준시각으로부터 오프셋만큼 떨어진 시각을 구합니다... " +
                          @"start=[{0}], offset=[{1}], seekDirection=[{2}], seekBoundaryMode=[{3}]",
                          start, offset, seekDirection, seekBoundaryMode);
            }

            Guard.Assert(offset >= TimeSpan.Zero, "offset 값은 항상 0 이상이어야 합니다. offset=[{0}]", offset);

            remaining = offset;

            // search periods
            ITimePeriodCollection searchPeriods = new TimePeriodCollection(IncludePeriods);

            if (searchPeriods.Count == 0)
            {
                searchPeriods.Add(TimeRange.Anytime);
            }

            // available periods
            ITimePeriodCollection availablePeriods = new TimePeriodCollection();

            if (ExcludePeriods.Count == 0)
            {
                availablePeriods.AddAll(searchPeriods);
            }
            else
            {
                // 예외 기간을 제외합니다.
                //
                var gapCalculator = new TimeGapCalculator <TimeRange>();

                var query
                    = searchPeriods
#if !SILVERLIGHT
                      .AsParallel()
                      .AsOrdered()
#endif
                      .SelectMany(searchPeriod =>
                                  ExcludePeriods.HasOverlapPeriods(searchPeriod)
                                        ? gapCalculator.GetGaps(ExcludePeriods, searchPeriod) // 예외 기간과 검색 기간에서 겹치지 않는 기간을 계산하여, 추려냅니다.
                                        : new TimePeriodCollection {
                    searchPeriod
                }                                                                   // 예외 기간과 겹쳐진 부분이 없다면, 기간 전체를 추가합니다.
                                  );

                availablePeriods.AddAll(query);
            }

            // 유효한 Period가 없다면 중단합니다.
            if (availablePeriods.Count == 0)
            {
                return(null);
            }

            // 기간중에 중복되는 부분의 없도록 유효한 기간을 결합합니다.
            if (availablePeriods.Count > 1)
            {
                var periodCombiner = new TimePeriodCombiner <TimeRange>();
                availablePeriods = periodCombiner.CombinePeriods(availablePeriods);
            }

            // 첫 시작 기간을 찾습니다.
            //
            DateTime seekMoment;
            var      startPeriod = (seekDirection == SeekDirection.Forward)
                                  ? FindNextPeriod(start, availablePeriods, out seekMoment)
                                  : FindPreviousPeriod(start, availablePeriods, out seekMoment);

            // 첫 시작 기간이 없다면 중단합니다.
            if (startPeriod == null)
            {
                return(null);
            }

            // 오프셋 값이 0 이라면, 바로 다음 값이므로 seekMoment를 반환합니다.
            if (offset == TimeSpan.Zero)
            {
                return(seekMoment);
            }

            if (seekDirection == SeekDirection.Forward)
            {
                for (var i = availablePeriods.IndexOf(startPeriod); i < availablePeriods.Count; i++)
                {
                    var gap          = availablePeriods[i];
                    var gapRemaining = gap.End - seekMoment;

                    if (IsDebugEnabled)
                    {
                        log.Debug("Seek Forward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining,
                                  remaining, seekMoment);
                    }

                    var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill)
                                             ? gapRemaining >= remaining
                                             : gapRemaining > remaining;

                    if (isTargetPeriod)
                    {
                        var end = seekMoment + remaining.Value;
                        remaining = null;
                        return(end);
                    }

                    remaining = remaining - gapRemaining;

                    if (i == availablePeriods.Count - 1)
                    {
                        return(null);
                    }

                    seekMoment = availablePeriods[i + 1].Start; // next period
                }
            }
            else
            {
                for (var i = availablePeriods.IndexOf(startPeriod); i >= 0; i--)
                {
                    var gap          = availablePeriods[i];
                    var gapRemaining = seekMoment - gap.Start;

                    if (IsDebugEnabled)
                    {
                        log.Debug("Seek Backward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining,
                                  remaining, seekMoment);
                    }

                    var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill)
                                             ? gapRemaining >= remaining
                                             : gapRemaining > remaining;

                    if (isTargetPeriod)
                    {
                        var end = seekMoment - remaining.Value;
                        remaining = null;
                        return(end);
                    }
                    remaining = remaining - gapRemaining;

                    if (i == 0)
                    {
                        return(null);
                    }

                    seekMoment = availablePeriods[i - 1].End; // previous period
                }
            }
            return(null);
        }
        public void CalendarGetGapTest() {
            // simmulation of some reservations
            var periods = new TimePeriodCollection
                          {
                              new DayRangeCollection(2011, 3, 7, 2),
                              new DayRangeCollection(2011, 3, 16, 2)
                          };

            // the overall search range
            var limits = new CalendarTimeRange(new DateTime(2011, 3, 4), new DateTime(2011, 3, 21));
            var days = new DayRangeCollection(limits.Start, limits.Duration.Days + 1);

            // limits의 내부이고, 주말인 DayRange를 추가합니다.
            var excludeDays = days.GetDays().Where(day => limits.HasInside(day) && day.DayOfWeek.IsWeekEnd());
            periods.AddAll(excludeDays.Cast<ITimePeriod>());

            var gapCalculator = new TimeGapCalculator<TimeRange>(new TimeCalendar());
            var gaps = gapCalculator.GetGaps(periods, limits);

            gaps.Count.Should().Be(4);
            gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 4), DurationUtil.Days(1))).Should().Be.True();
            gaps[1].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 9), DurationUtil.Days(3))).Should().Be.True();
            gaps[2].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 14), DurationUtil.Days(2))).Should().Be.True();
            gaps[3].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 18), DurationUtil.Days(1))).Should().Be.True();
        }
        public void ClearTest() {
            var timePeriods = new TimePeriodCollection();
            timePeriods.Count.Should().Be(0);
            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);

            timePeriods.AddAll(new SchoolDay());
            timePeriods.Count.Should().Be(7);
            timePeriods.Clear();
            timePeriods.Count.Should().Be(0);
        }