From 81e72126ce7c85af9437ca06743dbd11324fe5c2 Mon Sep 17 00:00:00 2001
From: Kevin Jahns <kevin.jahns@rwth-aachen.de>
Date: Tue, 14 Jun 2016 21:27:42 +0200
Subject: [PATCH] implemented new extention for awaitOps. It fixes several
 consistency issues (they were previously hard to detect), and it is also
 pretty efficient. It still has some debugger statements, so enjoy with care

---
 src/SpecHelper.js |   2 +-
 src/Utils.js      | 146 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+), 1 deletion(-)

diff --git a/src/SpecHelper.js b/src/SpecHelper.js
index 831a6622..bcb827af 100644
--- a/src/SpecHelper.js
+++ b/src/SpecHelper.js
@@ -97,7 +97,7 @@ function * applyTransactions (relAmount, numberOfTransactions, objects, users, t
           type.eventHandler.awaiting = 1
           type.eventHandler._debuggingAwaiting = true
         } else {
-        // fixAwaitingInType will handle _debuggingAwaiting
+          // fixAwaitingInType will handle _debuggingAwaiting
           return fixAwaitingInType(type)
         }
       })(getRandom(objects))
diff --git a/src/Utils.js b/src/Utils.js
index b8cf7a19..418bc455 100644
--- a/src/Utils.js
+++ b/src/Utils.js
@@ -92,6 +92,152 @@ module.exports = function (Y /* : any*/) {
     receivedOp (op) {
       if (this.awaiting <= 0) {
         this.onevent(op)
+      } else if (op.struct === 'Delete') {
+        var self = this
+        function checkDelete (d) {
+          if (d.length == null) {
+            throw new Error('This shouldn\'t happen! d.length must be defined!')
+          }
+          // we check if o deletes something in self.waiting
+          // if so, we remove the deleted operation
+          for (var w = 0; w < self.waiting.length; w++) {
+            var i = self.waiting[w]
+            if (i.struct === 'Insert' && i.id[0] === d.target[0]) {
+              var iLength = i.hasOwnProperty('content') ? i.content.length : 1
+              var dStart = d.target[1]
+              var dEnd = d.target[1] + (d.length || 1)
+              var iStart = i.id[1]
+              var iEnd = i.id[1] + iLength
+              // Check if they don't overlap
+              if (iEnd <= dStart || dEnd <= iStart) {
+                // no overlapping
+                continue
+              }
+              // we check all overlapping cases. All cases:
+              /*
+                1)  iiiii
+                      ddddd
+                    --> modify i and d
+                2)  iiiiiii
+                      ddddd
+                    --> modify i, remove d
+                3)  iiiiiii
+                      ddd
+                    --> remove d, modify i, and create another i (for the right hand side)
+                4)  iiiii
+                    ddddddd
+                    --> remove i, modify d
+                5)  iiiiiii
+                    ddddddd
+                    --> remove both i and d (**)
+                6)  iiiiiii
+                    ddddd
+                    --> modify i, remove d
+                7)    iii
+                    ddddddd
+                    --> remove i, create and apply two d with checkDelete(d) (**)
+                8)    iiiii
+                    ddddddd
+                    --> remove i, modify d (**)
+                9)    iiiii
+                    ddddd
+                    --> modify i and d
+                (**) (also check if i contains content or type)
+              */
+              // TODO: I left some debugger statements, because I want to debug all cases once in production. REMEMBER END TODO
+              if (iStart < dStart) {
+                if (dStart < iEnd) {
+                  if (iEnd < dEnd) {
+                    // Case 1
+                    debugger
+                    // remove the right part of i's content
+                    i.content.splice(dStart - iStart)
+                    // remove the start of d's deletion
+                    d.length = dEnd - iEnd
+                    d.target = [d.target[0], iEnd]
+                    continue
+                  } else if (iEnd === dEnd) {
+                    // Case 2
+                    i.content.splice(dStart - iStart)
+                    // remove d, we do that by simply ending this function
+                    return
+                  } else { // (dEnd < iEnd)
+                    // Case 3
+                    var newI = {
+                      id: [i.id[0], dEnd],
+                      content: i.content.slice(dEnd - iStart),
+                      struct: 'Insert'
+                    }
+                    self.waiting.push(newI)
+                    i.content.splice(dStart - iStart)
+                    return
+                  }
+                }
+              } else if (dStart === iStart) {
+                if (iEnd < dEnd) {
+                  // Case 4
+                  debugger
+                  d.length = dEnd - iEnd
+                  d.target = [d.target[0], iEnd]
+                  i.content = []
+                  continue
+                } else if (iEnd === dEnd) {
+                  // Case 5
+                  self.waiting.splice(w, 1)
+                  return
+                } else { // (dEnd < iEnd)
+                  // Case 6
+                  i.content = i.content.slice(dEnd - iStart)
+                  i.id = [i.id[0], dEnd]
+                  return
+                }
+              } else { // (dStart < iStart)
+                /*
+                7)    iii
+                    ddddddd
+                    --> remove i, create and apply two d with checkDelete(d) (**)
+                8)    iiiii
+                    ddddddd
+                    --> remove i, modify d (**)
+                9)    iiiii
+                    ddddd
+                    --> modify i and d
+                */
+                if (iEnd < dEnd) {
+                  // Case 7
+                  debugger
+                  self.waiting.splice(w, 1)
+                  checkDelete({
+                    target: [d.target[0], dStart],
+                    length: iStart - dStart,
+                    struct: 'Delete'
+                  })
+                  checkDelete({
+                    target: [d.target[0], iEnd],
+                    length: iEnd - dEnd,
+                    struct: 'Delete'
+                  })
+                  return
+                } else if (iEnd === dEnd) {
+                  // Case 8
+                  debugger
+                  self.waiting.splice(w, 1)
+                  return
+                } else { // dEnd < iEnd
+                  // Case 9
+                  debugger
+                  d.length = iStart - dStart
+                  i.content.splice(dEnd - iStart)
+                  i.id = [i.id[0], dEnd]
+                  continue
+                }
+              }
+            }
+          }
+          // finished with remaining operations
+          self.waiting.push(d)
+        }
+        checkDelete(op)
       } else {
         this.waiting.push(op)
       }
-- 
GitLab