// single pass attempt to copy if any can not accept the data then they are skipped
  // and true will be returned instead of false.
  private static boolean doingCopy(
      TapeWriteStage ss,
      int byteTailPos,
      int primaryTailPos,
      int totalPrimaryCopy,
      int totalBytesCopy) {

    IntBuffer primaryInts = RingBuffer.wrappedStructuredLayoutRingBuffer(ss.source);
    ByteBuffer secondaryBytes = RingBuffer.wrappedUnstructuredLayoutRingBufferA(ss.source);

    primaryInts.position(primaryTailPos);
    primaryInts.limit(
        primaryTailPos
            + totalPrimaryCopy); // TODO: AA, this will not work on the wrap, we must mask and do
                                 // muliple copies

    secondaryBytes.position(byteTailPos);
    secondaryBytes.limit(byteTailPos + totalBytesCopy);

    ss.header.clear();
    ss.headerAsInts.put(totalBytesCopy + (totalPrimaryCopy << 2));
    ss.headerAsInts.put(totalPrimaryCopy << 2);

    // TODO: must return false if there is no room to write.

    // TODO: BB, this creates a bit of garbage for the map, perhaps we should map larger blocks
    // expecting to use them for multiple writes.
    MappedByteBuffer mapped;
    try {
      mapped =
          ss.fileChannel.map(
              MapMode.READ_WRITE,
              ss.fileChannel.position(),
              8 + totalBytesCopy + (totalPrimaryCopy << 2));
      mapped.put(ss.header);

      IntBuffer asIntBuffer = mapped.asIntBuffer();
      asIntBuffer.position(2);
      asIntBuffer.put(primaryInts);

      mapped.position(mapped.position() + (totalPrimaryCopy << 2));
      mapped.put(secondaryBytes);

    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return true;
  }
  private static boolean processAvailData(TapeWriteStage ss) {
    int byteHeadPos;
    long headPos;

    // get the new head position
    byteHeadPos = RingBuffer.bytesHeadPosition(ss.source);
    headPos = RingBuffer.headPosition(ss.source);
    while (byteHeadPos != RingBuffer.bytesHeadPosition(ss.source)
        || headPos != RingBuffer.headPosition(ss.source)) {
      byteHeadPos = RingBuffer.bytesHeadPosition(ss.source);
      headPos = RingBuffer.headPosition(ss.source);
    }

    // we have established the point that we can read up to, this value is changed by the writer on
    // the other side

    // get the start and stop locations for the copy
    // now find the point to start reading from, this is moved forward with each new read.
    int pMask = ss.source.mask;
    long tempTail = RingBuffer.tailPosition(ss.source);
    int primaryTailPos = pMask & (int) tempTail;
    long totalPrimaryCopy = (headPos - tempTail);
    if (totalPrimaryCopy <= 0) {
      assert (totalPrimaryCopy == 0);
      return false; // nothing to copy so come back later
    }

    int bMask = ss.source.byteMask;
    int tempByteTail = RingBuffer.bytesTailPosition(ss.source);
    int byteTailPos = bMask & tempByteTail;
    int totalBytesCopy = (bMask & byteHeadPos) - byteTailPos;
    if (totalBytesCopy < 0) {
      totalBytesCopy += (bMask + 1);
    }

    // now do the copies
    if (doingCopy(ss, byteTailPos, primaryTailPos, (int) totalPrimaryCopy, totalBytesCopy)) {

      // TODO: play back file with those cunks into indexer to do it after the fact

      // release tail so data can be written
      int i = RingBuffer.BYTES_WRAP_MASK & (tempByteTail + totalBytesCopy);
      RingBuffer.setBytesWorkingTail(ss.source, i);
      RingBuffer.setBytesTail(ss.source, i);
      RingBuffer.publishWorkingTailPosition(ss.source, tempTail + totalPrimaryCopy);

      return true;
    }
    return false; // finished all the copy  for now
  }
 public String toString() {
   return getClass().getSimpleName()
       + (-2 == moreToCopy ? " not running " : " moreToCopy:" + moreToCopy)
       + " source content "
       + RingBuffer.contentRemaining(source);
 }