The date interval efficiency.
Inheritance: DateInterval
        public void AccountForEfficiencies_FixedEnd_MultipleDateIntervalEfficiencies_ReturnsCorrectAnswer()
        {
            //         +------------+
            //       |0|  |0|  |0|

            // Result:
            //   +------------------+
            //       |0|  |0|  |0|

            // Arrange
            var now = DateTime.Now;
            var dateInterval = new DateInterval(now.AddDays(2), now.AddDays(7));

            var dateIntervalEfficiencies = new List<DateIntervalEfficiency>();
            var efficiency1 = new DateIntervalEfficiency(now.AddDays(1), now.AddDays(2), 0);
            var efficiency2 = new DateIntervalEfficiency(now.AddDays(3), now.AddDays(4), 0);
            var efficiency3 = new DateIntervalEfficiency(now.AddDays(5), now.AddDays(6), 0);

            dateIntervalEfficiencies.Add(efficiency1);
            dateIntervalEfficiencies.Add(efficiency2);
            dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(dateIntervalEfficiencies, FixedEndPoint.Max);

            var correctDateInterval = new DateInterval(dateInterval.Max.Value.Add(-dateInterval.Duration).Add(-efficiency1.Duration).Add(-efficiency2.Duration).Add(-efficiency3.Duration), dateInterval.Max.Value);

            // Assert
            Assert.AreEqual(correctDateInterval, newDateInterval);
        }
        public void AccountForEfficiencies_Overlap1()
        {
            // 300% has higher priority than 200%,
            // 50% and 200% have same priority so 50% takes precedence.

            // +--------------------------+            Duration: 60 mins
            // |-----------200%-----------|			   Duration: 50 mins
            // |--50%--|           |-500%-|			   Duration (1): 30 min, (2): 10min

            // Frist we must work out the calendar efficiencies:

            // |--50%--|                               Duration: 30 mins
            //         |---200%---|                    Duration: 20 mins
            //                    |-500%-|             Duration: 10 mins

            // 30 mins at 50%	   => 15   mins at 100%
            // 20 mins at 200%     => 40   mins at 100%
            // 10 mins at 500%     => 50   mins at 100%

            // Result:
            // 60 - 15 - 40 = 5 mins
            // 5 mins at 100% is equivalend to 5/5 = 1 min at 500%
            // Total duration is: 30 + 20 + 1 = 51 mins

            // Arrange
            DateTime end = this.start.AddMinutes(60);
            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(30)), 50);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(30), this.start.AddMinutes(50)), 200);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(50), this.start.AddMinutes(60)), 500, 1);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(51));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_FixedEnd_NoOverlap_ThreeIntervals4()
        {
            // NOTE: This test if with Max end point fixed
            //
            // +----------------------+         Duration: 70 mins
            // |----------|                     Duration: 30 mins at 30%
            //            |-----|               Duration: 15 mins at 200%
            //                  |-|             Duration: 5 mins at 50%

            // The first section is not affected by a calendar period (i.e. 70 - 30 - 15 - 5 = 20)
            // So only 70 - 20 = 50 mins are affected by calendar periods.
            // Details:
            // 30 mins at 30%   => 9 min at 100%
            // 15 mins at 200%  => 30 min at 100%
            // 5 mins at 50%    => 2.5 min at 100%
            // 50 - 9 - 30 - 2.5 = 8.5 mins

            // So the 50 mins affected by the calendar period will last 30 + 15 + 5 + 8.5 = 58.5 mins
            // Total duration 20 + 58.5 = 78.5 mins

            // Arrange
            DateTime end = this.start.AddMinutes(70);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(30)), 30);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(30), this.start.AddMinutes(45)), 200);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(45), this.start.AddMinutes(50)), 50);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies, FixedEndPoint.Max);

            // Assert
            var result = new DateInterval(end.AddMinutes(-78.5), end);
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_NoOverlap_OneInterval()
        {
            // +--------------------------------+      Duration: 60 mins
            // |--------|                              Duration: 30 mins at 20%
            //
            // Result
            // |----------------|                      Duration: 84 mins

            // Arrange
            DateTime end = this.start.AddMinutes(60);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(30)), 20); // 30 mins at 20%
            this.dateIntervalEfficiencies.Add(efficiency1);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(84));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_NoOverlap_TwoIntervals2()
        {
            // +------------------+     Duration: 60 mins
            //           |--------|     Duration: 20 mins at 40%
            //     |-----|              Duration: 10 mins at 150%
            //
            // Result
            // 20 mins at 40%  => 8 mins at 100%
            // 10 mins at 150% => 15 mins at 100%
            // 60 - 8 - 15 = 37
            //
            // Total = 20 + 10 + 37 = 67 mins

            // Arrange
            DateTime end = this.start.AddMinutes(60);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(40), this.start.AddMinutes(60)), 40);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(30), this.start.AddMinutes(40)), 150);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(67));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_NoOverlap_TwoIntervals()
        {
            // +------------------+      Duration: 60 mins
            // |--------|                Duration: 30 mins at 20%
            //          |---------|      Duration: 30 mins at 150%
            //
            // Result
            // 30 mins at 20%  => 6 mins at 100%
            // 30 mins at 150% => 45 mins at 100%
            // 60 - 6 - 45 = 9 mins
            //
            // Total = 30 + 30 + 9 = 69 mins

            // Arrange
            DateTime end = this.start.AddMinutes(60);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(30)), 20); // 30 mins at 20%
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(30), this.start.AddMinutes(60)), 150); // 30 mins at 20%
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(69));  // Duration: 69 mins
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_NoOverlap_ThreeIntervals3()
        {
            //         +----------------------+     Duration: 60 mins
            // |-------|                            Duration: 30 mins at 30% (outside)
            //         |-------|                    Duration: 25 mins at 200%
            //                 |---|                Duration: 15 mins at 50%

            // Details:
            // 30 mins at 30%   => 0 (outside)
            // 25 mins at 200%  => 50 min at 100%
            // 15 mins at 50%   => 7.5 min at 100%
            // 60 - 50 - 7.5 = 2.5 min
            //
            // Result: 25 + 15 + 2.5 = 42.5 mins.

            // Arrange
            DateTime end = this.start.AddMinutes(60);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(-30), this.start), 30);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(25)), 200);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(25), this.start.AddMinutes(40)), 50);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(42.5));  // Duration: 42.5 mins
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_NoOverlap_ThreeIntervals2()
        {
            // +----------------------+                      Duration: 80 mins
            // |-------|                                     Duration: 20 mins at 10%
            //         |-------------|                       Duration: 50 mins at 60%
            //                       |------------|          Duration: 40 mins at 150%

            // Details:

            // 20 mins at 10%  => 2 min at 100%
            // 50 mins at 60%  => 30 min at 100%
            // 40 mins at 150% => 60 min at 100%
            //
            // 80 - 2 - 30 = 48min
            // 48 mins at 100% => 32 mins at 150%
            //
            // Final result: 20 + 50 + 32 = 102 mins

            // Arrange
            DateTime end = this.start.AddMinutes(80);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(20)), 10);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(20), this.start.AddMinutes(70)), 60);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(70), this.start.AddMinutes(110)), 150);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(102));  // Duration: 102 mins
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_FixedEnd_OneEfficiencyCalendarStartAndEndWithDateInterval_ReturnsCorrectAnswer()
        {
            // +-----------+
            // |----200----|

            // Result:
            //       +-----+
            // |----200----|

            // Arrange
            var now = DateTime.Now;
            var dateInterval = new DateInterval(now, now.AddDays(1));

            var dateIntervalEfficiencies = new List<DateIntervalEfficiency>();
            var efficiency1 = new DateIntervalEfficiency(dateInterval.Min.Value, dateInterval.Max.Value, 200);
            dateIntervalEfficiencies.Add(efficiency1);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(dateIntervalEfficiencies, FixedEndPoint.Max);

            var correctDateInterval = new DateInterval(dateInterval.Max.Value.AddTicks(-dateInterval.Duration.Ticks / 2), dateInterval.Max.Value);

            // Assert
            Assert.AreEqual(correctDateInterval, newDateInterval);
        }
        public void AccountForEfficiencies_Overlap3()
        {
            // +--------------------------+                Duration: 55 mins
            //    |------80%-------|			  	       Duration: 30 mins, starts at 15
            //                  |-200%-|	               Duration: 20 mins starts at 40

            //Work out the calendar efficiences
            // |--|                                         Duration: 15 mins at 100%
            //    |----80%-----|                            Duration: 30 mins
            //                 |--200%-|                    Duration: 15 mins

            // 15 mins at 100%     => 15 mins at 100%
            // 30 mins at 80%	   => 24 mins at 100%
            // 15 mins at 200%     => 30 mins at 100%

            // Result:

            // 55 - 15 - 24 = 16 mins
            // 16 min at 100% is equivalend to 8 mins at 200%
            // Total duration is: 15 + 30 + 8 = 53 min

            // Arrange
            DateTime end = this.start.AddMinutes(55);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(15), this.start.AddMinutes(45)), 80, 1);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(40), this.start.AddMinutes(60)), 200);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(53));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_OneZeroEfficiencyCalendarStartsInAndEndsAfterDateInterval_ReturnsCorrectResult()
        {
            // +-----------+
            //          |--0--|

            // Result:
            // +-----------------+
            //          |--0--|

            // Arrange
            var now = DateTime.Now;
            var dateInterval = new DateInterval(now, now.AddDays(4));

            var dateIntervalEfficiencies = new List<DateIntervalEfficiency>();
            var efficiency1 = new DateIntervalEfficiency(now.AddDays(3), now.AddDays(5), 0);
            dateIntervalEfficiencies.Add(efficiency1);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(dateIntervalEfficiencies);

            var correctDateInterval = new DateInterval(dateInterval.Min.Value, dateInterval.Duration.Add( efficiency1.Duration ));

            // Assert
            Assert.AreEqual(correctDateInterval, newDateInterval);
        }
        public void AccountForEfficiencies_FixedEnd_OneZeroEfficiencyCalendarStartBeforeAndEndsWithinDateInterval_ReturnsCorrectResult()
        {
            //       +-----------+
            //    |--0--|

            // Result:
            // +-----------------+
            //    |--0--|

            // Arrange
            var now = DateTime.Now;
            var dateInterval = new DateInterval(now, now.AddDays(4));

            var dateIntervalEfficiencies = new List<DateIntervalEfficiency>();
            var efficiency1 = new DateIntervalEfficiency(now.AddDays(-1), now.AddDays(2), 0);
            dateIntervalEfficiencies.Add(efficiency1);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(dateIntervalEfficiencies, FixedEndPoint.Max);

            var correctDateInterval = new DateInterval(efficiency1.Min.Value.Add( - (efficiency1.Max.Value - dateInterval.Min.Value) ), dateInterval.Max.Value);

            // Assert
            Assert.AreEqual(correctDateInterval, newDateInterval);
        }
        public void AccountForEfficiencies_Overlap2()
        {
            // +--------------------------+            Duration: 80 mins
            // |--------200%----|			           Duration: 50 mins, Priority
            //    |--50%--|                            Duration: 30 mins starts at 10
            //                     |-300%-|			   Duration: 20 mins finishes at 80 mins

            // Work out the calendar efficiences

            // |--|                                    Duration: 10 mins at 200%
            //    |--50%--|                            Duration: 30 mins
            //            |--200%-|                    Duration: 10 mins
            //                    |-100%-|             Duration: 10 mins
            //                           |-300%-|      Duration: 20 mins

            // 10 mins at 200% => 20 mins at 100%
            // 30 mins at 50%  => 15 mins at 100%
            // 10 mins at 200% => 20 mins at 100%
            // 10 mins at 100% => 10 mins at 100%
            // 20 mins at 300% => 60 mins at 100%

            // 80 - 20 - 15 - 20 - 10 = 15 mins
            // 15 mins at 100% => 5 mins at 300%
            // Total duration is: 10 + 30 + 10 + 10 + 5 = 65 mins

            // Arrange
            DateTime end = this.start.AddMinutes(80);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(50)), 200);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(10), this.start.AddMinutes(40)), 50);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(60), this.start.AddMinutes(80)), 300);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(65));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_Overlap6()
        {
            // +--------------------------+           Duration: 100 mins
            //   |------120%---------|				  Duration: 45 mins, starts at 10
            //     |----100%-------|                  Duration: 35 mins, starts at 15
            //         |-30%-|			      		  Duration: 25 mins, starts at 20

            // Work out the calendar efficiences:

            // Assumption all the calendar periods have the same efficiency. To the lowest efficiency takes precedence

            //|--|									  Duration: 10 mins
            //    |-|                                 Duration: 5 mins at 120%
            //      |-|                               Duration: 5 mins at 100%
            //        |-----|                         Duration: 25 mins at 30%
            //              |-|                       Duration: 5 mins at 100%
            //                |-|                     Duration: 5 mins at 120%
            //                  |-----|               Duration: 45 mins at 100% (which is the default value)

            // 10 mins at 100%	  => 10   mins at 100%
            // 5 mins at 120%	  => 6    mins at 100%
            // 5 mins at 100%     => 5    mins at 100%
            // 25 mins at 30%	  => 7.5  mins at 100%
            // 5 mins at 100%	  => 5    mins at 100%
            // 5 mins at 120%	  => 6    mins at 100%
            // 45 mins at 100%    => 45   mins at 100%

            // Result:
            // 100 - 10 - 6 - 5 - 7.5 - 5 - 6 - 45 = 15.5 mins
            // Total duration is: 10 + 5 + 5 + 25 + 5 + 5 + 45 + 15.5 = 115.5 mins

            // Arrange
            DateTime end = this.start.AddMinutes(100);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(10), this.start.AddMinutes(55)), 120);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(15), this.start.AddMinutes(50)), 100);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(20), this.start.AddMinutes(45)), 30);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(115.5));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_Overlap5()
        {
            //+--------------------------+            Duration: 100 mins
            //   |------120%---------|				  Duration: 45 mins, starts at 10 (PRIORITY)
            //     |----100%-------|                  Duration: 35 mins, starts at 15
            //         |-30%-|			      		  Duration: 25 mins, starts at 20

            // Work out the calendar efficiences:
            // If 120% is the priority then it takes precedence over the 100% and the 30% calendar period
            // Because 100% and 30% have the same priority, 30% takes precedence (lower efficiency)

            // |--|									Duration: 10 mins
            //    |---120%-----------|              Duration: 45 mins
            //                       |-100%-|		Duration: 45 mins

            // 10 mins at 100%	  => 10   mins at 100%
            // 45 mins at 120%	  => 54   mins at 100%
            // 45 mins at 100%    => 45   mins at 100%

            // Result:

            // 100 - 10 - 54 = 36 mins
            // Total duration is: 10 + 45 + 36 = 91

            // Arrange
            DateTime end = this.start.AddMinutes(100);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(10), this.start.AddMinutes(55)), 120, 1);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(15), this.start.AddMinutes(50)), 100);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(20), this.start.AddMinutes(45)), 30);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(91));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_Overlap4()
        {
            // +---------------------------------+       Duration: 90 mins
            //   |------90%----------|			   	     Duration: 40 mins, starts at 10
            //   |--30%--|                               Duration: 15 mins starts at 10
            //                          |-150%-|	     Duration: 10 mins finishes at 80 mins

            // Work out the calendar efficiences

            // |--|										   Duration: 10 mins at 100%
            //     |--30%--|                               Duration: 15 mins
            //             |-----90%----|                  Duration: 25 mins
            //                          |---|              Duration: 20 mins at 100%
            //                               |-150%-|      Duration: 10 mins
            //                                      |--|   Duration: 10 mins at 100%

            // 10 mins at 10%	   => 10   mins at 100%
            // 15 mins at 30%	   => 4.5  mins at 100%
            // 25 mins at 90%      => 22.5   mins at 100%
            // 20 mins at 100%	   => 20   mins at 100%
            // 10 mins at 150%     => 15   mins at 100%
            // 10 mins at 100%	   => 10   mins at 100%

            // Result:
            // 90 - 10 - 4.5 - 22.5 - 20 - 15 - 10 = 8 mins
            // Total duration is: 10 + 15 + 25 + 20 + 10 + 10 + 8 = 98 mins

            // Arrange
            DateTime end = this.start.AddMinutes(90);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(10), this.start.AddMinutes(50)), 90);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(10), this.start.AddMinutes(25)), 30, 1);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(70), this.start.AddMinutes(80)), 150);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(98));
            Assert.AreEqual(result, newDateInterval);
        }
        public void AccountForEfficiencies_NoOverlap_ThreeIntervals()
        {
            // +------------------+                         Duration: 70 mins
            // |------------------|                         Duration: 60 mins at 10%
            //                    |---------|               Duration: 40 mins at 80%
            //                              |---------|     Duration: 80 mins at 200%
            //
            // Result
            // 60 mins at 10%  => 6 mins at 100%
            // 40 mins at 80%  => 32 mins at 100%
            // 80 mins at 200% => 160 mins at 100%
            //
            // 70 - 6 - 32 = 32 mins
            // 32 mins at 100% => 16 mins at 200%
            //
            // Total = 60 + 40 + 16 = 116 mins

            // Arrange
            DateTime end = this.start.AddMinutes(70);

            var dateInterval = new DateInterval(this.start, end);

            var efficiency1 = new DateIntervalEfficiency(new DateInterval(this.start, this.start.AddMinutes(60)), 10);
            var efficiency2 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(60), this.start.AddMinutes(100)), 80);
            var efficiency3 = new DateIntervalEfficiency(new DateInterval(this.start.AddMinutes(100), this.start.AddMinutes(180)), 200);
            this.dateIntervalEfficiencies.Add(efficiency1);
            this.dateIntervalEfficiencies.Add(efficiency2);
            this.dateIntervalEfficiencies.Add(efficiency3);

            // Act
            var newDateInterval = dateInterval.AccountForEfficiencies(this.dateIntervalEfficiencies);

            // Assert
            var result = new DateInterval(this.start, this.start.AddMinutes(116));
            Assert.AreEqual(result, newDateInterval);
        }
示例#18
0
        public void MergeAndIntegrate(DateIntervalEfficiency eff)
        {
            int leftIdx  = this.GetSupportIndexAtTime(eff.Min.Value.Ticks);
              int rightIdx = this.GetSupportIndexAtTime(eff.Max.Value.Ticks);

              IntervalNode leftNode  = this.GetTopNodeAtIndex(leftIdx);
              IntervalNode rightNode = this.GetTopNodeAtIndex(rightIdx);
              IntervalNode newTopNode = null;

              if (leftNode != null) {
            if (leftNode == rightNode)
              // If node is the same on both sides the current interval is fully covered
              return;

            newTopNode = new IntervalNode(null, leftNode.startIdx, rightIdx);

            // Adjust left marker
            leftIdx = leftNode.endIdx;
              }

              if (rightNode != null) {
            if (newTopNode == null) {
              newTopNode = new IntervalNode(null, leftIdx, rightNode.endIdx);
            }
            else
              newTopNode.endIdx = rightNode.endIdx;

            // Adjust right marker
            rightIdx = rightNode.startIdx;
              }

              // Create new leaf node and include the free points from 'leftIdx' to 'rightIdx'
              IntervalNode newLeafNode = new IntervalNode(null, leftIdx, rightIdx);

              // Scanning from left to right

              // Marking the start point, but skipping the integration, since it contains the ticks from the previous delta interval
              this.SupportPoints[leftIdx] = newLeafNode;

              // Mark empty support points inside interval range, while jumping over the already "marked" intervals
              while (++leftIdx <= rightIdx) {
            // Integrate the delta interval
            this.EffectiveDeltaTime[leftIdx] = (long)(this.EffectiveDeltaTime[leftIdx] * 0.01 * eff.Efficiency);

            IntervalNode curTopNode = this.GetTopNodeAtIndex(leftIdx);
            if (curTopNode != null)
              // Jump over existing interval
              leftIdx = curTopNode.endIdx;
            else
              // "Brand" point with the current node
              this.SupportPoints[leftIdx] = newLeafNode;
              }

              // Create links to new top node
              if (newTopNode != null) {
            if (leftNode != null) leftNode.parent = newTopNode;
            if (rightNode != null) rightNode.parent = newTopNode;
            newLeafNode.parent = newTopNode;

            // Check if we have the whole support range covered
            if (newTopNode.startIdx == 0 && newTopNode.endIdx == this.SupportPoints.Length - 1)
              this.IsFullyCovered = true;
              }
        }