From 03579f33f19b6e9693c5a1e50e253c8b1e27a904 Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Tue, 20 Dec 2016 21:38:32 -0500
Subject: [PATCH] Fixed multi-coverage insertion, via an appropriate test.

---
 .../Clock SignalTests/PCMPatchedTrackTests.mm | 35 ++++++++++++++++++-
 Storage/Disk/PCMPatchedTrack.cpp              | 18 ++++++----
 2 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm b/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm
index bafdf4ec8..41120fedf 100644
--- a/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm	
+++ b/OSBindings/Mac/Clock SignalTests/PCMPatchedTrackTests.mm	
@@ -134,7 +134,7 @@
 	XCTAssert(total_length == Storage::Time(1), @"Total track length should still be 1");
 }
 
-- (void)testMultiReplace
+- (std::shared_ptr<Storage::Disk::Track>)fourSegmentPatchedTrack
 {
 	std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
 	Storage::Disk::PCMPatchedTrack *patchable = static_cast<Storage::Disk::PCMPatchedTrack *>(patchableTrack.get());
@@ -149,6 +149,13 @@
 		patchable->add_segment(Storage::Time(c, 4), segment);
 	}
 
+	return patchableTrack;
+}
+
+- (void)testMultiSegmentTrack
+{
+	std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
+
 	Storage::Time total_length;
 	std::vector<Storage::Disk::Track::Event> events;
 	while(1)
@@ -162,4 +169,30 @@
 	XCTAssert(total_length == Storage::Time(1), @"Total track length should still be 1");
 }
 
+- (void)testMultiReplace
+{
+	std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
+	Storage::Disk::PCMPatchedTrack *patchable = static_cast<Storage::Disk::PCMPatchedTrack *>(patchableTrack.get());
+
+	Storage::Disk::PCMSegment segment;
+	segment.data = {0x00};
+	segment.number_of_bits = 8;
+	segment.length_of_a_bit.length = 1;
+	segment.length_of_a_bit.clock_rate = 16;
+	patchable->add_segment(Storage::Time(1, 8), segment);
+
+	Storage::Time total_length;
+	std::vector<Storage::Disk::Track::Event> events;
+	while(1)
+	{
+		events.push_back(patchableTrack->get_next_event());
+		total_length += events.back().length;
+		if(events.back().type == Storage::Disk::Track::Event::IndexHole) break;
+	}
+
+	XCTAssert(events.size() == 17, @"Should still be 17 total events");
+	XCTAssert(events[4].length == Storage::Time(17, 32), @"Should have added a 17/32 gap after the fourth event");
+	XCTAssert(total_length == Storage::Time(1), @"Total track length should still be 1");
+}
+
 @end
diff --git a/Storage/Disk/PCMPatchedTrack.cpp b/Storage/Disk/PCMPatchedTrack.cpp
index b67ccf414..c25b00f3b 100644
--- a/Storage/Disk/PCMPatchedTrack.cpp
+++ b/Storage/Disk/PCMPatchedTrack.cpp
@@ -103,7 +103,8 @@ void PCMPatchedTrack::insert_period(const Period &period)
 	}
 	else
 	{
-		bool should_insert;
+		bool should_insert = false;
+		std::vector<Period>::difference_type insertion_offset = 0;
 
 		if(start_period->start_time == period.start_time)
 		{
@@ -117,20 +118,25 @@ void PCMPatchedTrack::insert_period(const Period &period)
 			// start_period starts before period. So trim and plan to insert afterwards.
 			start_period->trim_end_to_time(period.start_time);
 			should_insert = true;
+			insertion_offset = start_period + 1 - periods_.begin();
 		}
 
-		if(end_period->end_time > period.end_time)
+		if(end_period->end_time == period.end_time)
 		{
-			// end_period exactly after period does. So exclude it from the list to delete
-			end_period--;
+			// end_period ends exactly when period does. So include it from the list to delete
+			end_period++;
+		}
+		else
+		{
+			end_period->push_start_to_time(period.end_time);
 		}
 
 		// remove everything that is exiting in between
-		periods_.erase(start_period + 1, end_period - 1);
+		periods_.erase(start_period + 1, end_period);
 
 		// insert the new period if required
 		if(should_insert)
-			periods_.insert(start_period + 1, period);
+			periods_.insert(periods_.begin()+insertion_offset, period);
 	}
 }