/**
 * Copyright 2024 Beijing Baolande Software Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Runtime Library Exception to the Apache 2.0 License:
 *
 * As an exception, if you use this Software to compile your source code and
 * portions of this Software are embedded into the binary product as a result,
 * you may redistribute such product without providing attribution as would
 * otherwise be required by Sections 4(a), 4(b) and 4(d) of the License.
 */

package hyperion.buffer

/**
 * 底层使用数组的ByteBuffer实现
 *
 * 非线程安全
 *
 * @author yangfuping
 */
public open class ArrayByteBuffer <: ByteBuffer & ToString {
    private var bufferVal: Array<Byte>

    /**
     * 数组起始位置跳过的字节数
     */
    private var skipBytes: Int64

    /**
     * ByteBuffer的引用计数,池化和回收ByteBuffer使用
     */
    private let refCounted: ?ReferenceCounted

    protected init() {
        this(DEFAULT_INITIAL_CAPACITY)
    }

    protected init(initialSize: Int64) {
        super(
            position: 0,
            limit: initialSize,
            capacity: initialSize,
            maxCapacity: DEFAULT_MAX_CAPACITY,
            expandSupport: true
        )

        this.skipBytes = 0
        this.bufferVal = Array<Byte>(initialSize, repeat: 0)
        this.refCounted = None<ReferenceCounted>
    }

    protected init(initialSize: Int64, expandSupport!: Bool) {
        super(
            position: 0,
            limit: initialSize,
            capacity: initialSize,
            maxCapacity: getMaxCapacity(initialSize, expandSupport),
            expandSupport: expandSupport
        )

        this.skipBytes = 0
        this.bufferVal = Array<Byte>(initialSize, repeat: 0)
        this.refCounted = None<ReferenceCounted>
    }

    protected init(
        initialSize: Int64,
        expandSupport!: Bool,
        allocator!: ByteBufferAllocator,
        refCounted!: ReferenceCounted
    ) {
        super(
            position: 0,
            limit: initialSize,
            capacity: initialSize,
            maxCapacity: getMaxCapacity(initialSize, expandSupport),
            expandSupport: expandSupport,
            allocator: allocator
        )

        this.skipBytes = 0
        this.bufferVal = Array<Byte>(initialSize, repeat: 0)
        this.refCounted = refCounted
    }

    protected init(buffer: Array<Byte>, expandSupport!: Bool) {
        super(
            position: 0,
            limit: buffer.size,
            capacity: buffer.size,
            maxCapacity: getMaxCapacity(buffer.size, expandSupport),
            expandSupport: expandSupport
        )

        this.skipBytes = 0
        this.bufferVal = buffer
        this.refCounted = None<ReferenceCounted>
    }

    protected init(
        buffer: Array<Byte>,
        position!: Int64,
        limit!: Int64,
        capacity!: Int64,
        expandSupport!: Bool
    ) {
        super(
            position: position,
            limit: limit,
            capacity: capacity,
            maxCapacity: getMaxCapacity(capacity, expandSupport),
            expandSupport: expandSupport
        )

        this.skipBytes = 0
        this.bufferVal = buffer
        this.refCounted = None<ReferenceCounted>
    }

    protected init(
        buffer: Array<Byte>,
        skipBytes!: Int64,
        position!: Int64,
        limit!: Int64,
        capacity!: Int64,
        expandSupport!: Bool
    ) {
        super(
            position: position,
            limit: limit,
            capacity: capacity,
            maxCapacity: getMaxCapacity(capacity, expandSupport),
            expandSupport: expandSupport
        )

        if (skipBytes < 0) {
            throw IllegalArgumentException("Negative skipBytes values: ${skipBytes}")
        }

        this.skipBytes = skipBytes
        this.bufferVal = buffer
        this.refCounted = None<ReferenceCounted>
    }

    protected init(
        buffer: Array<Byte>,
        skipBytes!: Int64,
        position!: Int64,
        limit!: Int64,
        capacity!: Int64,
        maxCapacity!: Int64,
        expandSupport!: Bool
    ) {
        super(
            position: position,
            limit: limit,
            capacity: capacity,
            maxCapacity: maxCapacity,
            expandSupport: expandSupport
        )

        if (skipBytes < 0) {
            throw IllegalArgumentException("Negative skipBytes values: ${skipBytes}")
        }
        this.skipBytes = skipBytes
        this.bufferVal = buffer
        this.refCounted = None<ReferenceCounted>
    }

    protected init(
        buffer: Array<Byte>,
        skipBytes!: Int64,
        position!: Int64,
        limit!: Int64,
        capacity!: Int64,
        maxCapacity!: Int64,
        expandSupport!: Bool,
        allocator!: ByteBufferAllocator
    ) {
        super(
            position: position,
            limit: limit,
            capacity: capacity,
            maxCapacity: maxCapacity,
            expandSupport: expandSupport,
            allocator: allocator
        )

        if (skipBytes < 0) {
            throw IllegalArgumentException("Negative skipBytes values: ${skipBytes}")
        }
        this.skipBytes = skipBytes
        this.bufferVal = buffer
        this.refCounted = None<ReferenceCounted>
    }

    protected init(
        refCounted: ReferenceCounted,
        buffer: Array<Byte>,
        skipBytes!: Int64,
        position!: Int64,
        limit!: Int64,
        capacity!: Int64,
        maxCapacity!: Int64,
        expandSupport!: Bool
    ) {
        super(
            position: position,
            limit: limit,
            capacity: capacity,
            maxCapacity: maxCapacity,
            expandSupport: expandSupport
        )

        if (skipBytes < 0) {
            throw IllegalArgumentException("Negative skipBytes values: ${skipBytes}")
        }
        this.skipBytes = skipBytes
        this.bufferVal = buffer
        this.refCounted = refCounted
    }

    protected func ix(i: Int64): Int64 {
        return i + skipBytes;
    }

    public func remainingCapacity(): Int64 {
        return this.capacityVal - ix(positionVal)
    }

    /**
     * 从当前的起始位置ix(0)开始,跳过skipSize
     *
     * 需要当前的position大于skipSize时,才能调整
     */
    public func skip(skipSize: Int64): Buffer {
        if (skipBytes < 0) {
            throw IllegalArgumentException("Negative skipSize: ${skipBytes}")
        }

        if (positionVal < skipSize) {
            throw IllegalArgumentException("The skipSize: ${skipSize} should less than postion: ${positionVal}")
        }

        // position, limit, capacity均要调整
        this.positionVal = positionVal - skipSize
        this.limitVal = limitVal - skipSize
        this.capacityVal = capacityVal - skipSize
        // 增加skipBytes
        this.skipBytes = skipBytes + skipSize
        return this
    }

    public open func free(): Unit {
        this.skipBytes = 0
        this.positionVal = 0
        // 容量和limit调整为数组的长度
        this.capacityVal = bufferVal.size
        this.limitVal = bufferVal.size
    }

    public func slice(): ByteBuffer {
        let pos = positionVal
        let lim = limitVal
        var remaining = 0
        if (pos < lim) {
            remaining = lim - pos
        }

        if (let Some(refCounted) <- refCounted) {
            refCounted.retainRef()
            return ArrayByteBuffer(
                refCounted,
                bufferVal,
                skipBytes: ix(pos),
                position: 0,
                limit: remaining,
                capacity: remaining,
                maxCapacity: remaining,
                expandSupport: false // 切片不支持扩展容量
            )
        } else {
            return ArrayByteBuffer(
                bufferVal,
                skipBytes: ix(pos),
                position: 0,
                limit: remaining,
                capacity: remaining,
                maxCapacity: remaining,
                expandSupport: false // 切片不支持扩展容量
            )
        }
    }

    public func slice(index!: Int64, length!: Int64): ByteBuffer {
        if (index < 0) {
            throw IndexOutOfBoundsException("Negative index ${index}")
        }

        if (length < 0) {
            throw IndexOutOfBoundsException("Negative length ${length}")
        }

        if (index + length > limitVal) {
            throw IndexOutOfBoundsException(
                "The sum of index ${index} and length ${length} is out of bounds, limit is ${limitVal}")
        }

        if (let Some(refCounted) <- refCounted) {
            refCounted.retainRef()
            return ArrayByteBuffer(
                refCounted,
                bufferVal,
                skipBytes: ix(index),
                position: 0,
                limit: length,
                capacity: length,
                maxCapacity: length,
                expandSupport: false
            )
        } else {
            return ArrayByteBuffer(
                bufferVal,
                skipBytes: ix(index),
                position: 0,
                limit: length,
                capacity: length,
                maxCapacity: length,
                expandSupport: false
            )
        }
    }

    public func slice(range: Range<Int64>): ByteBuffer {
        var start = 0
        if (range.hasStart) {
            start = range.start
        }

        var end = limitVal
        if (range.hasEnd) {
            end = range.end
        }

        if (!range.isClosed) {
            end = end - 1
        }

        return slice(index: start, length: (end - start) + 1)
    }

    public func compact(): Buffer {
        if (hasRemaining()) {
            bufferVal.copyTo(bufferVal, ix(positionVal), ix(0), remaining())
            position(remaining())
            limit(capacityVal)
        }

        return this
    }

    /**
     * 用于池化的ByteBuffer, 保留引用
     */
    public open func retain(): ByteBuffer {
        if (let Some(refCounted) <- refCounted) {
            refCounted.retainRef()
        }

        return this
    }

    public open func release(): Unit {
        if (let Some(refCounted) <- refCounted) {
            if (refCounted.releaseRef()) {
                if (let Some(delegateBuffer) <- refCounted.getDelegateBuffer()) {
                    if (let Some(allocator) <- delegateBuffer.getAllocator()) {
                        allocator.free(delegateBuffer)
                    }
                }
            }
        }
    }

    /**
     * 扩充容量
     */
    protected func expandCapacity(needCapicity: Int64): ByteBuffer {
        if (needCapicity <= capacityVal) {
            return this
        }

        if (!expandSupport) {
            throw IndexOutOfBoundsException(
                "Expand capacity is not supported, required capicity: ${needCapicity} is exceed capacity: ${capacityVal}"
            )
        }

        if (needCapicity > maxCapacityVal) {
            throw IndexOutOfBoundsException(
                "The required capicity ${needCapicity} is exceed maxCapacityVal: ${maxCapacityVal}")
        }

        let newCapicity: Int64
        if (bufferVal.size << 1 > maxCapacityVal) {
            newCapicity = maxCapacityVal
        } else {
            // 扩容到两倍和需要大小值的最大值
            newCapicity = max(bufferVal.size << 1, needCapicity)
        }

        let expandBuffer = Array<Byte>(newCapicity, repeat: 0)
        bufferVal.copyTo(expandBuffer, 0, 0, bufferVal.size)
        if (limitVal == capacityVal) {
            // 调整limit值为newCapicity
            limitVal = newCapicity
        } else {
            throw IndexOutOfBoundsException(
                "Illegal state to expand capacity, the old limit${limitVal} is not equals to old capacity ${capacityVal}"
            )
        }

        bufferVal = expandBuffer
        capacityVal = newCapicity
        return this
    }

    /**
     * 返回position..=limit区间包含的数组
     */
    public func toArray(): Array<Byte> {
        if (logger.isLoggable(LogLevel.TRACE)) {
            logger.log(
                LogLevel.TRACE,
                "ByteBuffer::toArray, slice [${ix(positionVal)}..${ix(limitVal)}] from ${toString()}"
            )
        }
        return bufferVal[ix(positionVal)..ix(limitVal)]
    }

    /**
     * 返回index..=index+length包含的数组
     */
    public func toArray(index!: Int64, length!: Int64): Array<Byte> {
        if (index < 0) {
            throw IndexOutOfBoundsException("Negative index ${index}")
        }

        if (length < 0) {
            throw IndexOutOfBoundsException("Negative length ${length}")
        }

        if (index + length > limitVal) {
            throw IndexOutOfBoundsException(
                "The sum of index ${index} and length ${length} is out of bounds, limit is ${limitVal}")
        }

        if (logger.isLoggable(LogLevel.TRACE)) {
            logger.log(
                LogLevel.TRACE,
                "ByteBuffer::toArray, slice [${ix(index)}..${ix(index + length)}] from ${toString()}"
            )
        }
        return bufferVal[ix(index)..ix(index + length)]
    }

    public func toArray(range: Range<Int64>): Array<Byte> {
        var start = 0
        if (range.hasStart) {
            start = range.start
        }

        var end = limitVal
        if (range.hasEnd) {
            end = range.end
        }

        if (!range.isClosed) {
            end = end - 1
        }

        return toArray(index: start, length: (end - start) + 1)
    }

    public func getByte(): Byte {
        return bufferVal[ix(nextGetIndex())];
    }

    public func getUInt16(): UInt16 {
        checkIndex(positionVal + 2)
        return UInt16(bufferVal[ix(nextGetIndex())] & 0xff) << 8 | UInt16(bufferVal[ix(nextGetIndex())] & 0xff)
    }

    public func getUInt32(): UInt32 {
        checkIndex(positionVal + 4)
        return UInt32(bufferVal[ix(nextGetIndex())] & 0xff) << 24 | UInt32(bufferVal[ix(nextGetIndex())] & 0xff) << 16 |
            UInt32(bufferVal[ix(nextGetIndex())] & 0xff) << 8 | UInt32(bufferVal[ix(nextGetIndex())] & 0xff)
    }

    public func getUInt64(): UInt64 {
        checkIndex(positionVal + 8)
        return UInt64(bufferVal[ix(nextGetIndex())] & 0xff) << 56 | UInt64(bufferVal[ix(nextGetIndex())] & 0xff) << 48 |
            UInt64(bufferVal[ix(nextGetIndex())] & 0xff) << 40 | UInt64(bufferVal[ix(nextGetIndex())] & 0xff) << 32 |
            UInt64(bufferVal[ix(nextGetIndex())] & 0xff) << 24 | UInt64(bufferVal[ix(nextGetIndex())] & 0xff) << 16 |
            UInt64(bufferVal[ix(nextGetIndex())] & 0xff) << 8 | UInt64(bufferVal[ix(nextGetIndex())] & 0xff)
    }

    @OverflowWrapping
    public func getInt8(): Int8 {
        return Int8(getByte())
    }

    @OverflowWrapping
    public func getInt16(): Int16 {
        return Int16(getUInt16())
    }

    @OverflowWrapping
    public func getInt32(): Int32 {
        return Int32(getUInt32())
    }

    @OverflowWrapping
    public func getInt64(): Int64 {
        return Int64(getUInt64())
    }

    public func getByte(index: Int64): Byte {
        checkIndex(index + 1)
        return bufferVal[ix(index)];
    }

    public func getUInt16(index: Int64): UInt16 {
        checkIndex(index + 2)
        return UInt16(bufferVal[ix(index)] & 0xff) << 8 | UInt16(bufferVal[ix(index + 1)] & 0xff)
    }

    public func getUInt32(index: Int64): UInt32 {
        checkIndex(index + 4)
        return UInt32(bufferVal[ix(index)] & 0xff) << 24 | UInt32(bufferVal[ix(index + 1)] & 0xff) << 16 |
            UInt32(bufferVal[ix(index + 2)] & 0xff) << 8 | UInt32(bufferVal[ix(index + 3)] & 0xff)
    }

    public func getUInt64(index: Int64): UInt64 {
        checkIndex(index + 8)
        return UInt64(bufferVal[ix(index + 0)] & 0xff) << 56 | UInt64(bufferVal[ix(index + 1)] & 0xff) << 48 |
            UInt64(bufferVal[ix(index + 2)] & 0xff) << 40 | UInt64(bufferVal[ix(index + 3)] & 0xff) << 32 |
            UInt64(bufferVal[ix(index + 4)] & 0xff) << 24 | UInt64(bufferVal[ix(index + 5)] & 0xff) << 16 |
            UInt64(bufferVal[ix(index + 6)] & 0xff) << 8 | UInt64(bufferVal[ix(index + 7)] & 0xff)
    }

    @OverflowWrapping
    public func getInt8(index: Int64): Int8 {
        return Int8(getByte(index))
    }

    @OverflowWrapping
    public func getInt16(index: Int64): Int16 {
        return Int16(getUInt16(index))
    }

    @OverflowWrapping
    public func getInt32(index: Int64): Int32 {
        return Int32(getUInt32(index))
    }

    @OverflowWrapping
    public func getInt64(index: Int64): Int64 {
        return Int64(getUInt64(index))
    }

    public func putByte(value: Byte) {
        checkIndex(positionVal + 1)
        bufferVal[ix(nextPutIndex())] = value
    }

    public func putUInt16(val: UInt16): Unit {
        checkIndex(positionVal + 2)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val & 0xFF)
    }

    public func putUInt32(val: UInt32): Unit {
        checkIndex(positionVal + 4)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 24 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 16 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val & 0xFF)
    }

    public func putUInt64(val: UInt64): Unit {
        checkIndex(positionVal + 8)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 56 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 48 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 40 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 32 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 24 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 16 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val & 0xFF)
    }

    @OverflowWrapping
    public func putInt8(val: Int8): Unit {
        putByte(UInt8(val))
    }

    @OverflowWrapping
    public func putInt16(val: Int16): Unit {
        putUInt16(UInt16(val))
    }

    @OverflowWrapping
    public func putInt32(val: Int32): Unit {
        putUInt32(UInt32(val))
    }

    @OverflowWrapping
    public func putInt64(val: Int64): Unit {
        putUInt64(UInt64(val))
    }

    public func putByte(index: Int64, value: Byte): Unit {
        checkIndex(index + 1)
        bufferVal[ix(index)] = value
    }

    public func putUInt16(index: Int64, val: UInt16): Unit {
        checkIndex(index + 2)
        bufferVal[ix(index)] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(index + 1)] = UInt8(val & 0xFF)
    }

    public func putUInt32(index: Int64, val: UInt32): Unit {
        checkIndex(index + 4)
        bufferVal[ix(index)] = UInt8(val >> 24 & 0xFF)
        bufferVal[ix(index + 1)] = UInt8(val >> 16 & 0xFF)
        bufferVal[ix(index + 2)] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(index + 3)] = UInt8(val & 0xFF)
    }

    public func putUInt64(index: Int64, val: UInt64): Unit {
        checkIndex(index + 8)
        bufferVal[ix(index)] = UInt8(val >> 56 & 0xFF)
        bufferVal[ix(index + 1)] = UInt8(val >> 48 & 0xFF)
        bufferVal[ix(index + 2)] = UInt8(val >> 40 & 0xFF)
        bufferVal[ix(index + 3)] = UInt8(val >> 32 & 0xFF)
        bufferVal[ix(index + 4)] = UInt8(val >> 24 & 0xFF)
        bufferVal[ix(index + 5)] = UInt8(val >> 16 & 0xFF)
        bufferVal[ix(index + 6)] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(index + 7)] = UInt8(val & 0xFF)
    }

    @OverflowWrapping
    public func putInt8(index: Int64, val: Int8): Unit {
        putByte(index, UInt8(val))
    }

    @OverflowWrapping
    public func putInt16(index: Int64, val: Int16): Unit {
        putUInt16(index, UInt16(val))
    }

    @OverflowWrapping
    public func putInt32(index: Int64, val: Int32): Unit {
        putUInt32(index, UInt32(val))
    }

    @OverflowWrapping
    public func putInt64(index: Int64, val: Int64): Unit {
        putUInt64(index, UInt64(val))
    }

    public func expandAndPutByte(value: Byte): Unit {
        expandAndCheckIndex(positionVal + 1)
        bufferVal[ix(nextPutIndex())] = value
    }

    public func expandAndPutUInt16(val: UInt16): Unit {
        expandAndCheckIndex(positionVal + 2)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val & 0xFF)
    }

    public func expandAndPutUInt32(val: UInt32): Unit {
        expandAndCheckIndex(positionVal + 4)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 24 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 16 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val & 0xFF)
    }

    public func expandAndPutUInt64(val: UInt64): Unit {
        expandAndCheckIndex(positionVal + 8)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 56 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 48 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 40 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 32 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 24 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 16 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val >> 8 & 0xFF)
        bufferVal[ix(nextPutIndex())] = UInt8(val & 0xFF)
    }

    @OverflowWrapping
    public func expandAndPutInt8(val: Int8): Unit {
        expandAndPutByte(UInt8(val))
    }

    @OverflowWrapping
    public func expandAndPutInt16(val: Int16): Unit {
        expandAndPutUInt16(UInt16(val))
    }

    @OverflowWrapping
    public func expandAndPutInt32(val: Int32): Unit {
        expandAndPutUInt32(UInt32(val))
    }

    @OverflowWrapping
    public func expandAndPutInt64(val: Int64): Unit {
        expandAndPutUInt64(UInt64(val))
    }

    public func get(dst: Array<Byte>, startPos: Int64, length: Int64): Unit {
        checkBounds(dst, startPos, length)
        if (length > remaining()) {
            throw IndexOutOfBoundsException("The required data size: ${length} is exceed remaining: ${remaining()}")
        }

        bufferVal.copyTo(dst, ix(positionVal), startPos, length)
        position(positionVal + length)
    }

    public func get(dst: Array<Byte>): Unit {
        get(dst, 0, dst.size)
    }

    public func get(index: Int64, dst: Array<Byte>, startPos: Int64, length: Int64): Unit {
        checkBounds(dst, startPos, length)
        if (index + length > limitVal) {
            throw IndexOutOfBoundsException("The sum of index ${index} and ${length} is exceeding limit: ${limitVal}")
        }

        bufferVal.copyTo(dst, ix(index), startPos, length)
    }

    public func get(index: Int64, dst: Array<Byte>): Unit {
        return get(index, dst, 0, dst.size)
    }

    public func put(src: Array<Byte>, startPos: Int64, length: Int64): Unit {
        checkBounds(src, startPos, length)
        if (length > remaining()) {
            throw IndexOutOfBoundsException(
                "The required data size: ${length} is exceed remaining ${remaining()}, position: ${positionVal}, limit: ${limitVal}, capacity: ${capacityVal}"
            )
        }

        src.copyTo(bufferVal, startPos, ix(positionVal), length)
        position(positionVal + length)
    }

    public func put(src: Array<Byte>): Unit {
        put(src, 0, src.size)
    }

    public func put(index: Int64, src: Array<Byte>, startPos: Int64, length: Int64): Unit {
        checkBounds(src, startPos, length)
        if (index + length > limitVal) {
            throw IndexOutOfBoundsException(
                "The sum of index ${index} and ${length} is exceeding limit ${limitVal}, remaining: ${remaining()}, position: ${positionVal}, limit: ${limitVal}, capacity: ${capacityVal}"
            )
        }

        src.copyTo(bufferVal, startPos, ix(index), length)
    }

    public func put(index: Int64, src: Array<Byte>): Unit {
        return get(index, src, 0, src.size)
    }

    public func expandAndPut(src: Array<Byte>, startPos: Int64, length: Int64): Unit {
        checkBounds(src, startPos, length)
        // 如果容量不够则扩容容量
        expandAndCheckIndex(positionVal + length)

        if (length > remaining()) {
            throw IndexOutOfBoundsException("The required data size: ${length} is exceed remaining: ${remaining()}")
        }

        src.copyTo(bufferVal, startPos, ix(positionVal), length)
        position(positionVal + length)
    }

    public func expandAndPut(src: Array<Byte>): Unit {
        expandAndPut(src, 0, src.size)
    }

    /**
     * 将数据收集到目标字节数组中,收集到的字节数小于需要收集的字节数不会报错
     *
     * @param index 从ByteBuffer的指定位置开始收集
     * @param dst 目标字节数组
     * @param startPos 数组起始位置
     * @param length 需要收集的字节数
     * @return 收集到的字节数
     */
    public func partialGather(index: Int64, dst: Array<Byte>, startPos: Int64, length: Int64): Int64 {
        checkBounds(dst, startPos, length)
        checkIndex(index)
        let copyLen = min(length, limitVal - index)
        if (copyLen > 0) {
            // 只拷贝,不移动position
            bufferVal.copyTo(dst, ix(index), startPos, copyLen)
        }
        return copyLen
    }

    /**
     * 将数据收集到目标字节数组中,收集到的字节数小于目标数组的长度不会报错
     *
     * @param index 从ByteBuffer的指定位置开始收集
     * @param dst 目标字节数组
     * @param startPos 数组起始位置
     * @param length 需要收集的字节数
     * @return 收集到的字节数
     */
    public func partialGather(index: Int64, dst: Array<Byte>): Int64 {
        return partialGather(index, dst, 0, dst.size)
    }

    /**
     * 将目标数组的数据存储到ByteBuffer中,ByteBuffe存储容量不够不会报错
     *
     * @param index 从ByteBuffer的指定位置开始收集
     * @param dst 目标字节数组
     * @param startPos 数组起始位置
     * @param length 需要村粗的字节数
     * @return 完成存储的字节数
     */
    public func partialOffer(index: Int64, dst: Array<Byte>, startPos: Int64, length: Int64): Int64 {
        if (logger.isTraceEnabled()) {
            logger.log(
                LogLevel.TRACE,
                "PartialOffer array to  ${toString()}: index: ${index}, array size: ${dst.size}, startPos: ${startPos}, length: ${length}"
            )
        }

        checkBounds(dst, startPos, length)
        checkIndex(index)
        let copyLen = min(length, (limitVal - index))
        if (logger.isTraceEnabled()) {
            logger.log(LogLevel.TRACE, "PartialOffer copyed ${copyLen}")
        }

        if (copyLen > 0) {
            dst.copyTo(bufferVal, startPos, ix(index), copyLen)
        }
        return copyLen
    }

    /**
     * 将目标数组的数据存储到ByteBuffer中,ByteBuffe存储容量不够不会报错
     *
     * @param index 从ByteBuffer的指定位置开始收集
     * @param dst 目标字节数组
     * @return 完成存储的字节数
     */
    public func partialOffer(index: Int64, dst: Array<Byte>): Int64 {
        return partialOffer(index, dst, 0, dst.size)
    }

    public func toString() {
        return "ArrayByteBuffer{skipBytes: ${skipBytes}, position:${positionVal},limit:${limitVal},capacity:${capacityVal},maxCapacity: ${maxCapacityVal}}"
    }

    public func indexOf(needle: Buffer, pos: Int64): Int64 {
        if (pos < limitVal && hasRemaining()) {
            if (needle.hasRemaining() && remaining() > needle.remaining()) {
                let max: Int64 = pos + needle.remaining()
                for (i in pos..max) {
                    if (matches(needle, i)) {
                        return i;
                    }
                }
            }
        }

        return -1;
    }

    private func matches(needle: Buffer, pos: Int64): Bool {
        for (i in 0..needle.capacity()) {
            if (getByte(positionVal + pos + i) != needle.getByte(needle.position() + i)) {
                return false;
            }
        }
        return true;
    }

    public func indexOf(value: Byte, pos: Int64): Int64 {
        for (i in pos..capacityVal) {
            if (getByte(positionVal + i) == value) {
                return i;
            }
        }
        return -1;
    }

    public func startsWith(bytes: Array<Byte>): Bool {
        if (capacityVal - positionVal < bytes.size) {
            return false;
        }

        for (i in 0..bytes.size) {
            if (bufferVal[positionVal + i] != bytes[i]) {
                return false;
            }
        }
        return true;
    }
}