*            Key in which the newly elected edge key will be returned
     * @param spareKey
     *            A spare Key in which intermediate key values can be
     *            accumulated
     * @param policy
     *            JoinPolicy used to choose optimal rebalance point
     * @return the join offset as described above
     */

    int joinMeasureRebalanceOffset(final Buffer buffer, final int virtualSize, final int foundAt1, final int foundAt2,
            final int adjustmentForNewEbc, final JoinPolicy policy) {

        int joinBest = 0;
        int joinOffset = 0;
        int leftSize = 0;

        //
        // Working variables
        //
        int kbData; // content of a key block
        int tbData; // content of a tail block header
        int tail; // offset within page of a tail block
        int klength; // length of the key portion of a tail block
        //
        // Search the left page for good rebalance point.
        //
        for (int p = KEY_BLOCK_START; p < foundAt1; p += KEYBLOCK_LENGTH) {
            kbData = getInt(p);
            int ebc = decodeKeyBlockEbc(kbData);
            tail = decodeKeyBlockTail(kbData);
            tbData = getInt(tail);
            int size = decodeTailBlockSize(tbData);
            klength = decodeTailBlockKLength(tbData);

            int delta = ((size + ebc + ~TAILBLOCK_MASK) & TAILBLOCK_MASK) - ((size + ~TAILBLOCK_MASK) & TAILBLOCK_MASK);

            int candidateRightSize = virtualSize - leftSize + delta;

            int candidateLeftSize = leftSize + KEYBLOCK_LENGTH + ((klength + ~TAILBLOCK_MASK) & TAILBLOCK_MASK)
                    + _tailHeaderSize;

            int rightKeyCount = ((buffer.getKeyBlockEnd() - foundAt2) + (foundAt1 - p)) / KEYBLOCK_LENGTH;

            int joinFit = policy.rebalanceFit(this, buffer, p, foundAt1, foundAt2, virtualSize, candidateLeftSize,
                    candidateRightSize, _bufferSize - KEY_BLOCK_START);

            if (joinFit > joinBest && rightKeyCount < _pool.getMaxKeys()) {
                joinBest = joinFit;
                joinOffset = p;
            }

            leftSize += KEYBLOCK_LENGTH + ((size + ~TAILBLOCK_MASK) & TAILBLOCK_MASK);
        }

        /*
         * Search the right page for good rebalance point.
         */
        for (int p = foundAt2; p < buffer._keyBlockEnd; p += KEYBLOCK_LENGTH) {
            kbData = buffer.getInt(p);
            int ebc = decodeKeyBlockEbc(kbData);
            tail = decodeKeyBlockTail(kbData);
            tbData = buffer.getInt(tail);
            int size = decodeTailBlockSize(tbData);
            klength = decodeTailBlockKLength(tbData);

            /*
             * This is the amount by which the tail block for the candidate
             * rebalance key would have to grow if it became the first key on
             * the right page and its ebc became zero.
             */
            int delta = ((size + ebc + ~TAILBLOCK_MASK) & TAILBLOCK_MASK) - ((size + ~TAILBLOCK_MASK) & TAILBLOCK_MASK);

            /*
             * Amount by which the current tail block needs to grow to
             * accommodate reduced ebc.
             */
            int adjustment = (p == foundAt2) ? adjustmentForNewEbc : 0;

            int candidateRightSize = virtualSize - leftSize + delta;

            int candidateLeftSize = leftSize + ((klength + ~TAILBLOCK_MASK) & TAILBLOCK_MASK) + adjustment
                    + _tailHeaderSize + KEYBLOCK_LENGTH;

            int leftKeyCount = ((foundAt1 - KEY_BLOCK_START) + (p - foundAt2)) / KEYBLOCK_LENGTH;

            int joinFit = policy.rebalanceFit(this, buffer, p, foundAt1, foundAt2, virtualSize, candidateLeftSize,
                    candidateRightSize, _bufferSize - KEY_BLOCK_START);

            if (joinFit > joinBest && leftKeyCount < _pool.getMaxKeys()) {
                joinBest = joinFit;
                joinOffset = -p;
            }

            leftSize += KEYBLOCK_LENGTH + ((size + ~TAILBLOCK_MASK) & TAILBLOCK_MASK) + adjustment;
        }
        return joinOffset;

    }