protected Operation transform(DeleteOperation delA, DeleteOperation delB) {

    int posA = delA.getPosition();
    int lenA = delA.getTextLength();
    int posB = delB.getPosition();
    int lenB = delB.getTextLength();

    if (posB >= (posA + lenA)) {
      /*
       * Operation A is completely before operation B.
       */
      return delA;
    } else if (posA >= (posB + lenB)) {
      /*
       * Operation A starts at the end or after operation B. Index of
       * operation A' must be reduced by the length of the text of
       * operation B.
       */
      return new DeleteOperation(posA - lenB, delA.getText());
    } else {
      /*
       * Operation A and operation B are overlapping.
       */
      if ((posB <= posA) && ((posA + lenA) <= (posB + lenB))) {
        /*
         * Operation B starts before or at the same position like
         * operation A and ends after or at the same position like
         * operation A.
         */
        return new NoOperation();
      } else if ((posB <= posA) && ((posA + lenA) > (posB + lenB))) {
        /*
         * Operation B starts before or at the same position like
         * operation A and ends before operation A.
         */
        return new DeleteOperation(posB, delA.getText().substring(posB + lenB - posA, lenA));
      } else if ((posB > posA) && ((posB + lenB) >= (posA + lenA))) {
        /*
         * Operation B starts after operation A and ends after or at the
         * same position like operation A.
         */
        return new DeleteOperation(posA, delA.getText().substring(0, posB - posA));
      } else {
        /*
         * Operation B is fully in operation A.
         */
        return new DeleteOperation(
            posA,
            delA.getText().substring(0, posB - posA)
                + delA.getText().substring(posB + lenB - posA, lenA));
      }
    }
  }
  protected Operation transform(DeleteOperation delA, InsertOperation insB) {

    int posA = delA.getPosition();
    int lenA = delA.getTextLength();
    int posB = insB.getPosition();
    int lenB = insB.getTextLength();

    if (posB >= (posA + lenA)) {
      /*
       * Operation B is completely after operation A.
       */
      return delA;
    } else if (posB <= posA) {
      /*
       * Operation B starts before or at the same position like operation
       * A
       */
      return new DeleteOperation(posA + lenB, delA.getText());
    } else {
      /*
       * Operation B (insert) is in the range of operation A (delete).
       * Operation A' must be split up into two delete operations. (A):
       * "123456" (A'): "1" "23456"
       */
      DeleteOperation del1 = new DeleteOperation(posA, delA.getText().substring(0, posB - posA));
      DeleteOperation del2 =
          new DeleteOperation(posA + lenB, delA.getText().substring(posB - posA, lenA));
      return new SplitOperation(del1, del2);
    }
  }
  protected Operation transform(InsertOperation insA, DeleteOperation delB) {

    int posA = insA.getPosition();
    int posB = delB.getPosition();
    int lenB = delB.getTextLength();

    if (posA <= posB) {
      /*
       * Operation A starts before or at the same position like operation
       */
      return insA;
    } else if (posA > (posB + lenB)) {
      /*
       * Operation A starts after operation B. Index of operation A' must
       * be reduced by the length of the text of operation B.
       */
      return new InsertOperation(posA - lenB, insA.getText(), insA.getOrigin());
    } else {
      /*
       * Operation A starts in operation B. Index of A' must be the index
       * of operation B.
       */
      return new InsertOperation(posB, insA.getText(), insA.getOrigin());
    }
  }