class IntegerCoder {

    public static ByteBuffer encodeLong(long value, int minBytes)
    {
        assert minBytes >= 1 && minBytes <= 8;

        byte[] buf = new byte[9];
        BitOps.putLongAsLittleEndian(buf, 1, value);

        int count = buf.length - 1; // int lastNonZeroByteIndex = count;
        while (count > minBytes && buf[count] == 0) {
            count--;
        }

        int firstByteValue = 0xFF & (1 << (7 - count + minBytes));
        // 1 <= minBytes <= 8
        // minBytes <= count <= 8
        // max(-count + minBytes) when count equals minBytes
        // min(-count + minBytes) == -8 + 1 = -7
        // 1 << ( 7 - 8 + 1) == 1 << 0 == 1;
        // 1 << ( 7 - 0 ) == 128
        // firstByteValue is a power of 2 in range: 1 <= firstByteValue <= 128

        if ((0xFF & buf[count]) >= firstByteValue) {
            buf[0] = (byte) ~ (firstByteValue - 1);
            count++;
        } else if (count > minBytes) {
            buf[0] = (byte) ((~ (firstByteValue * 2 - 1)) | buf[count]);
        } else {
            buf[0] = buf[count];
        }

        return ByteBuffer.wrap(buf, 0, count);
    }

}

class IntegerCoderTest {

    private static final int _minBytes;
    private long _input;
    private ByteBuffer _expected;

    @Test
    public void testEncodingCorrectness()
    {

        ByteBuffer actual = IntegerCoder.encodeLong(_input, _minBytes);
        assertEquals(String.format("encode %d -> %s, expected %s (minBytes=%d)",
                                   _input,
                                   Text.byteBufferToString(actual),
                                   Text.byteBufferToString(_expected),
                                   _minBytes),
                     _expected, actual);
    }

}