docs: int insert(Object caller, int version, bbBlock curr, int pos, int len)
      {
          assert mutation_in_progress(caller, version);
          // DEBUG: int amountMoved = 0;
          // DEBUG: int before = this._buf_limit;
          // DEBUG: assert _validate();
          // if there's room in the current block - just
          // move the "trailing" bytes down and we're done
          int neededSpace = len - curr.unusedBlockCapacity();
          if (neededSpace <= 0) {
              // we have all the space we need in the current block
              // DEBUG: amountMoved =
              insertInCurrOnly(caller, version, curr, pos, len);
          }
          else {
              // we'll need at least some additional space beyond the curr
              // block, see if there's room in the
              // next one, otherwise we'll make more (blocks)
              bbBlock next = null;
              if (curr._idx < this._next_block_position - 1) {
                  // if there is another block
                  next = this._blocks.get(curr._idx + 1);
              }
              if (next != null &&
                  (neededSpace <= next.unusedBlockCapacity())
              ) {
                  // with the addition of the free space in the following block we have enough
                  // DEBUG: amountMoved =
                  insertInCurrAndNext(caller, version, curr, pos, len, next);
              }
              else {
                  // we'll have to make one or more new blocks
                  // first figure out much will be in the first
                  // and last blocks (i.e. ignoring the whole
                  // blocks
                  int lenNeededInLastAddedBlock = neededSpace % _blockSizeUpperLimit;
                  int tailLen = curr.bytesAvailableToRead(pos);
                  if (lenNeededInLastAddedBlock < tailLen) lenNeededInLastAddedBlock = tailLen;
                  if (lenNeededInLastAddedBlock < neededSpace
                   && neededSpace < this._blockSizeUpperLimit) {
                      // if we need less than the largest block then we should
                      // make *one* block with all of the needed space
                      lenNeededInLastAddedBlock = neededSpace;
                  }
                  bbBlock newblock = insertMakeNewTailBlock(caller, version, curr, lenNeededInLastAddedBlock);
                  // now see if the curr block and this newblock have enough
                  // available space to do the job, and if there's some trailing
                  // data from curr that will end up staying in curr
                  if (len <= (curr.unusedBlockCapacity()
                             + newblock.unusedBlockCapacity())
                  ) {
                      // insert this as a zero length block immediately  after _curr
                      // insertBlock also adjusts the trailing blocks idx values
                      insertBlock(newblock);
                      // now pretend we just have the "push into the next block" case
                      // DEBUG: amountMoved =
                      insertInCurrAndNext(caller, version, curr, pos, len, newblock);
                  }
                  else {
                      // and last we have the case of having to insert more than 1 block
                      // which means all of the trailing bytes in _curr move into the last
                      // block
                      // DEBUG: amountMoved =
                      insertAsManyBlocksAsNeeded(caller, version, curr, pos, len, newblock);
                  }
              }
          }
          // DEBUG: if (this._buf_limit - before != len
          // DEBUG: || amountMoved != len) {
          // DEBUG: throw new BlockedBufferException("insert went wrong #1 !!!");
          // DEBUG: }
          assert _validate();
          return len;
      }