// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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.

package buffer

import (
	"container/list"
	"errors"
	"fmt"
	"io"
	"sync"
	"time"

	"github.com/sirupsen/logrus"

	"github.com/apache/skywalking-rover/pkg/logger"
	"github.com/apache/skywalking-rover/pkg/tools/enums"
	"github.com/apache/skywalking-rover/pkg/tools/host"
)

var (
	ErrNotComplete = errors.New("socket: not complete event")
	emptyList      = list.New()

	log = logger.GetLogger("tools", "buffer")

	PooledBuffer = sync.Pool{
		New: func() any {
			return &[20480]byte{}
		},
	}
)

func BorrowNewBuffer() *[20480]byte {
	return PooledBuffer.Get().(*[20480]byte)
}

type SocketDataBuffer interface {
	// Protocol of the buffer
	Protocol() enums.ConnectionProtocol
	// GenerateConnectionID for identity the buffer belong which connection
	GenerateConnectionID() string
	// BufferData of the buffer
	BufferData() []byte
	// TotalSize of socket data, the data may exceed the size of the BufferData()
	TotalSize() uint64
	// Direction of the data, send or receive
	Direction() enums.SocketDataDirection
	// BufferStartPosition the buffer start index
	BufferStartPosition() int
	// BufferLen the buffer data length
	BufferLen() int
	// DataID data id of the buffer
	DataID() uint64
	// PrevDataID the previous data id of the buffer
	PrevDataID() uint64
	// DataSequence the data sequence under same data id
	DataSequence() int
	// IsStart this buffer is start of the same data id
	IsStart() bool
	// IsFinished this buffer is finish of the same data id
	IsFinished() bool
	// HaveReduceDataAfterChunk check have reduced data after current buffer
	HaveReduceDataAfterChunk() bool

	// StartTime the data start timestamp
	StartTime() uint64
	// EndTime the data end timestamp
	EndTime() uint64

	ReleaseBuffer() *[20480]byte
}

type SocketDataDetail interface {
	// DataID data id of the buffer
	DataID() uint64
	// Time (BPF) of the detail event
	Time() uint64
}

type DataIDRange struct {
	From                   uint64
	To                     uint64
	IsToBufferReadFinished bool
}

func (i *DataIDRange) String() string {
	return fmt.Sprintf("from: %d, to: %d, isToBufferReadFinished: %t", i.From, i.To, i.IsToBufferReadFinished)
}

type Buffer struct {
	dataEvents   *list.List
	detailEvents *list.List
	validated    bool // the events list is validated or not

	// shouldResetPosition means the buffer have new buffer appended into the buffer
	// so the position should reset to the head, and re-read the buffer
	shouldResetPosition bool

	eventLocker sync.RWMutex

	head    *Position
	current *Position

	// record the latest expired data id in connection for expire the older socket detail
	// because the older socket detail may not be received in buffer
	latestExpiredDataID uint64

	// originalBuffer record this buffer is from Buffer.Slice or CombineSlices
	// if it's not empty, then when getting the details should query from originalBuffer
	// Because the BPF Queue is unsorted and can be delayed, so the details should query by real buffer
	originalBuffer *Buffer
	// endPosition record the end position of the originalBuffer
	endPosition *Position
}

type SocketDataEventLimited struct {
	SocketDataBuffer
	From int
	Size int
}

func (s *SocketDataEventLimited) Protocol() enums.ConnectionProtocol {
	return s.SocketDataBuffer.Protocol()
}

func (s *SocketDataEventLimited) BufferData() []byte {
	return s.SocketDataBuffer.BufferData()[s.From:s.Size]
}

func (s *SocketDataEventLimited) BufferLen() int {
	return s.Size - s.From
}

func (s *SocketDataEventLimited) BufferStartPosition() int {
	return s.From
}

func (i *DataIDRange) IsIncludeAllDetails(l *list.List) bool {
	if l.Len() == 0 {
		return false
	}
	for e := l.Front(); e != nil; e = e.Next() {
		if e.Value.(SocketDataDetail).DataID() < i.From || e.Value.(SocketDataDetail).DataID() > i.To {
			return false
		}
	}
	return true
}

func (i *DataIDRange) Append(other *DataIDRange) *DataIDRange {
	if other.From < i.From {
		i.From = other.From
	}
	if other.To > i.To {
		i.To = other.To
	}
	i.IsToBufferReadFinished = other.IsToBufferReadFinished
	return i
}

func (i *DataIDRange) DeleteDetails(buf *Buffer) {
	if buf.originalBuffer != nil {
		i.DeleteDetails(buf.originalBuffer)
	}
	for e := buf.detailEvents.Front(); e != nil; {
		next := e.Next()
		dataID := e.Value.(SocketDataDetail).DataID()
		if dataID >= i.From && dataID <= i.To {
			if !i.IsToBufferReadFinished && dataID == i.To {
				break
			}
			buf.detailEvents.Remove(e)
			log.Debugf("delete detail event from buffer, data id: %d, ref: %p, range: %d-%d(%t)",
				dataID, buf, i.From, i.To, i.IsToBufferReadFinished)
		}
		e = next
	}
}

type Position struct {
	// element of the event list
	element *list.Element
	// bufIndex the buffer index of the element
	bufIndex int
}

func (p *Position) Clone() *Position {
	return &Position{element: p.element, bufIndex: p.bufIndex}
}

func (p *Position) DataID() uint64 {
	return p.element.Value.(SocketDataBuffer).DataID()
}

func (p *Position) PrevDataID() uint64 {
	return p.element.Value.(SocketDataBuffer).PrevDataID()
}

func (p *Position) Seq() int {
	return p.element.Value.(SocketDataBuffer).DataSequence()
}

func NewBuffer() *Buffer {
	return &Buffer{
		dataEvents:   list.New(),
		detailEvents: list.New(),
		validated:    false,
	}
}

func (r *Buffer) FindFirstDataBuffer(dataID uint64) SocketDataBuffer {
	for e := r.dataEvents.Front(); e != nil; e = e.Next() {
		cur := e.Value.(SocketDataBuffer)
		if cur.DataID() == dataID {
			return cur
		}
	}
	return nil
}

func (r *Buffer) BuildTotalDataIDRange() *DataIDRange {
	if r.dataEvents.Len() == 0 {
		return nil
	}
	var toIndex uint64
	var isToBufferReadFinished bool
	if r.endPosition != nil {
		toIndex = r.endPosition.DataID()
		isToBufferReadFinished = r.endPosition.bufIndex == r.endPosition.element.Value.(SocketDataBuffer).BufferLen()
	} else {
		toIndex = r.current.DataID()
		isToBufferReadFinished = r.current.bufIndex == r.current.element.Value.(SocketDataBuffer).BufferLen()
	}
	return &DataIDRange{
		From:                   r.head.DataID(),
		To:                     toIndex,
		IsToBufferReadFinished: isToBufferReadFinished,
	}
}

func (r *Buffer) Position() *Position {
	return r.current.Clone()
}

func (r *Buffer) Clean() {
	r.eventLocker.Lock()
	defer r.eventLocker.Unlock()

	r.dataEvents = list.New()
	r.detailEvents = list.New()
	r.head = nil
	r.current = nil
	r.endPosition = nil
}

// nolint
func (r *Buffer) Slice(validated bool, start, end *Position) *Buffer {
	dataEvents := list.New()
	for nextElement := start.element; nextElement != end.element; nextElement = nextElement.Next() {
		if nextElement == nil || nextElement.Value == nil {
			break
		}
		currentBuffer := nextElement.Value.(SocketDataBuffer)
		dataEvents.PushBack(currentBuffer)
	}
	lastBuffer := end.element.Value.(SocketDataBuffer)
	dataEvents.PushBack(&SocketDataEventLimited{SocketDataBuffer: lastBuffer, Size: end.bufIndex})

	return &Buffer{
		dataEvents:     dataEvents,
		detailEvents:   emptyList,
		validated:      validated,
		head:           &Position{element: dataEvents.Front(), bufIndex: start.bufIndex},
		current:        &Position{element: dataEvents.Front(), bufIndex: start.bufIndex},
		originalBuffer: r,
		endPosition:    end,
	}
}

func (r *Buffer) Len() int {
	if r == nil || r.head == nil {
		return 0
	}
	var result int
	var startIndex = r.head.bufIndex
	for e := r.head.element; e != nil; e = e.Next() {
		result += r.head.element.Value.(SocketDataBuffer).BufferLen() - startIndex
		startIndex = 0
	}
	return result
}

func (r *Buffer) BuildDetails() *list.List {
	// if the original buffer is not empty, then query the details from original buffer
	if r.originalBuffer != nil {
		events := list.New()
		fromDataID := r.head.DataID()
		var endDataID uint64
		if r.endPosition != nil {
			endDataID = r.endPosition.DataID()
		} else {
			endDataID = r.current.DataID()
		}

		for e := r.originalBuffer.detailEvents.Front(); e != nil; e = e.Next() {
			if e.Value == nil {
				continue
			}
			if e.Value.(SocketDataDetail).DataID() >= fromDataID && e.Value.(SocketDataDetail).DataID() <= endDataID {
				events.PushBack(e.Value)
			}
		}
		if events.Len() == 0 && log.Enable(logrus.DebugLevel) {
			dataIDList := make([]uint64, 0)
			for e := r.originalBuffer.detailEvents.Front(); e != nil; e = e.Next() {
				if e.Value != nil {
					dataIDList = append(dataIDList, e.Value.(SocketDataDetail).DataID())
				}
			}
			log.Infof("cannot found details from original buffer, from data id: %d, end data id: %d, "+
				"ref: %p, existing details data id list: %v", fromDataID, endDataID, r.originalBuffer, dataIDList)
		}

		return events
	}
	return r.detailEvents
}

func (r *Buffer) DataSize() int64 {
	if r == nil {
		return 0
	}
	var result int64
	var headPosition = r.head
	if headPosition == nil {
		if !r.PrepareForReading() {
			return 0
		}
		defer func() {
			r.ResetForLoopReading()
		}()
		headPosition = r.head
	}

	isFirst := true
	for e := headPosition.element; e != nil; e = e.Next() {
		if isFirst {
			result += int64(e.Value.(SocketDataBuffer).BufferLen() - headPosition.bufIndex)
			isFirst = false
		} else {
			result += int64(e.Value.(SocketDataBuffer).BufferLen())
		}
	}
	return result
}

func (r *Buffer) FirstSocketBuffer() SocketDataBuffer {
	if r == nil || r.dataEvents == nil || r.dataEvents.Len() == 0 {
		return nil
	}
	return r.dataEvents.Front().Value.(SocketDataBuffer)
}

func (r *Buffer) LastSocketBuffer() SocketDataBuffer {
	if r == nil || r.dataEvents == nil || r.dataEvents.Len() == 0 {
		return nil
	}
	return r.dataEvents.Back().Value.(SocketDataBuffer)
}

func (r *Buffer) TotalBuffer() []SocketDataBuffer {
	if r == nil || r.dataEvents == nil || r.dataEvents.Len() == 0 {
		return nil
	}
	result := make([]SocketDataBuffer, 0, r.dataEvents.Len())
	for e := r.dataEvents.Front(); e != nil; e = e.Next() {
		if e.Value == nil {
			continue
		}
		result = append(result, e.Value.(SocketDataBuffer))
	}
	return result
}

// DetectNotSendingLastPosition detect the buffer contains not sending data: the BPF limited socket data count
func (r *Buffer) DetectNotSendingLastPosition() *Position {
	if r == nil || r.dataEvents.Len() == 0 {
		return nil
	}

	for e := r.dataEvents.Front(); e != nil; e = e.Next() {
		buf := e.Value.(SocketDataBuffer)
		// the buffer is sent finished but still have reduced data not send
		if buf.IsFinished() && buf.HaveReduceDataAfterChunk() {
			return &Position{element: e, bufIndex: buf.BufferLen()}
		}
	}
	return nil
}

func CombineSlices(validated bool, originalBuffer *Buffer, buffers ...*Buffer) *Buffer {
	if len(buffers) == 0 {
		return nil
	}
	if len(buffers) == 1 {
		return buffers[0]
	}
	dataEvents := list.New()
	for _, b := range buffers {
		if b == nil || b.head == nil {
			continue
		}
		if b.head.bufIndex > 0 {
			headBuffer := b.dataEvents.Front().Value.(SocketDataBuffer)
			dataEvents.PushBack(&SocketDataEventLimited{SocketDataBuffer: headBuffer,
				From: b.head.bufIndex, Size: headBuffer.BufferLen()})
			for next := b.dataEvents.Front().Next(); next != nil; next = next.Next() {
				dataEvents.PushBack(next.Value)
			}
		} else {
			dataEvents.PushBackList(b.dataEvents)
		}
	}

	var endPosition *Position
	for i := len(buffers) - 1; i >= 0; i-- {
		if buffers[i] == nil {
			continue
		}
		if buffers[i].endPosition != nil {
			endPosition = buffers[i].endPosition
			break
		} else if buffers[i].Position() != nil {
			endPosition = buffers[i].Position()
			break
		}
	}
	return &Buffer{
		dataEvents:     dataEvents,
		detailEvents:   emptyList, // for the combined buffer, the details list should be queried from original buffer
		validated:      validated,
		head:           &Position{element: dataEvents.Front(), bufIndex: 0},
		current:        &Position{element: dataEvents.Front(), bufIndex: 0},
		originalBuffer: originalBuffer,
		endPosition:    endPosition,
	}
}

func (r *Buffer) Peek(p []byte) (n int, err error) {
	// save the index temporary
	tmpPosition := r.current.Clone()
	// restore the index
	defer func() {
		r.current = tmpPosition
	}()
	readIndex := 0
	for readIndex < len(p) {
		count, err := r.Read(p[readIndex:])
		if err != nil {
			return 0, err
		}
		readIndex += count
	}
	return readIndex, nil
}

func (r *Buffer) OffsetPosition(offset int) *Position {
	var nextElement func(e *list.Element) *list.Element
	if offset == 0 {
		return r.current.Clone()
	} else if offset > 0 {
		nextElement = func(e *list.Element) *list.Element {
			return e.Next()
		}
	} else {
		nextElement = func(e *list.Element) *list.Element {
			return e.Prev()
		}
	}

	var curEle = r.current.element
	var curIndex = r.current.bufIndex
	for ; curEle != nil; curEle = nextElement(curEle) {
		nextOffset := curIndex + offset
		bufferLen := curEle.Value.(SocketDataBuffer).BufferLen()
		if nextOffset >= 0 && nextOffset < bufferLen {
			curIndex += offset
			break
		}

		if offset > 0 {
			offset -= bufferLen - curIndex
			curIndex = 0
		} else {
			offset += curIndex
			next := nextElement(curEle)
			if next == nil {
				curEle = next
				break
			}
			curIndex = curEle.Value.(SocketDataBuffer).BufferLen()
		}
	}

	if curEle == nil {
		return nil
	}
	return &Position{element: curEle, bufIndex: curIndex}
}

func (r *Buffer) Read(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}
	if r.current == nil || r.current.element == nil {
		return 0, io.EOF
	}
	element, n := r.ReadFromCurrent(p)
	if n > 0 {
		return n, nil
	}

	curEvent := element.Value.(SocketDataBuffer)
	next := r.nextElement(element)
	if next == nil {
		return 0, io.EOF
	}
	nextEvent := next.Value.(SocketDataBuffer)

	var shouldRead = false
	if r.validated {
		shouldRead = true
		// same data id and sequence orders
	} else if (curEvent.DataID() == nextEvent.DataID() && curEvent.DataSequence()+1 == nextEvent.DataSequence()) ||
		// cur event is finished and next event is start
		(nextEvent.IsStart() && curEvent.IsFinished()) ||
		// same data id and sequence but have difference buffer index
		(curEvent.DataID() == nextEvent.DataID() && curEvent.DataSequence() == nextEvent.DataSequence() &&
			r.current.bufIndex <= nextEvent.BufferStartPosition()) {
		shouldRead = true
	}

	if !shouldRead {
		return 0, ErrNotComplete
	}

	return r.read0(next, nextEvent, p)
}

func (r *Buffer) ReadFromCurrent(p []byte) (element *list.Element, n int) {
	element = r.current.element
	curEvent := element.Value.(SocketDataBuffer)
	residueSize := curEvent.BufferLen() - r.current.bufIndex
	if residueSize > 0 {
		readLen := len(p)
		if residueSize < readLen {
			readLen = residueSize
		}

		n = copy(p, curEvent.BufferData()[r.current.bufIndex:r.current.bufIndex+readLen])
		r.current.bufIndex += n
		return element, n
	}
	return element, 0
}

func (r *Buffer) ReadUntilBufferFull(data []byte) error {
	reduceLen := len(data)
	currentIndex := 0
	for reduceLen > 0 {
		readCount, err := r.Read(data[:reduceLen])
		if err != nil {
			return err
		}
		reduceLen -= readCount
		currentIndex += readCount
	}
	return nil
}

func (r *Buffer) Merge(other *Buffer) {
	if other == nil {
		return
	}
	for e := other.dataEvents.Front(); e != nil; e = e.Next() {
		if v, ok := e.Value.(SocketDataBuffer); ok && v != nil {
			r.AppendDataEvent(v)
		}
	}
	for e := other.detailEvents.Front(); e != nil; e = e.Next() {
		if v, ok := e.Value.(SocketDataDetail); ok && v != nil {
			r.AppendDetailEvent(v)
		}
	}
}

func (r *Buffer) read0(currentElement *list.Element, currentBuffer SocketDataBuffer, p []byte) (n int, err error) {
	readLen := len(p)
	if currentBuffer.BufferLen() < readLen {
		readLen = currentBuffer.BufferLen()
	}

	copy(p, currentBuffer.BufferData()[:readLen])
	r.current.element = currentElement
	r.current.bufIndex = readLen
	return readLen, nil
}

// IsCurrentPacketReadFinished means to validate the current reading package is reading finished
func (r *Buffer) IsCurrentPacketReadFinished() bool {
	return r.current.bufIndex == r.current.element.Value.(SocketDataBuffer).BufferLen()
}

func (r *Buffer) ResetForLoopReading() {
	r.head = nil
	r.current = nil
}

func (r *Buffer) PrepareForReading() bool {
	if r.dataEvents.Len() == 0 {
		return false
	}
	// if the buffer should reset, then reset the position and cannot be read from current position
	if r.shouldResetPosition {
		r.ResetForLoopReading()
		r.shouldResetPosition = false
		return r.PrepareForReading()
	}
	if r.head == nil || r.head.element == nil {
		// read in the first element
		r.eventLocker.RLock()
		defer r.eventLocker.RUnlock()
		r.head = &Position{element: r.dataEvents.Front(), bufIndex: 0}
		r.current = r.head.Clone()
	} else {
		// make sure we can read from head
		r.current = r.head.Clone()
	}

	return true
}

// nolint
func (r *Buffer) RemoveReadElements(includeDetails bool) bool {
	r.eventLocker.Lock()
	defer r.eventLocker.Unlock()

	// delete until the last data id
	if includeDetails && r.head.element != nil && r.current.element != nil {
		firstDataID := r.head.element.Value.(SocketDataBuffer).DataID()
		currentBuffer := r.current.element.Value.(SocketDataBuffer)
		lastDataID := currentBuffer.DataID()
		startDelete := false
		for e := r.detailEvents.Front(); e != nil; {
			event := e.Value.(SocketDataDetail)
			if firstDataID == lastDataID && currentBuffer.BufferLen() != r.current.bufIndex {
				// current buffer is not finished, so the detail cannot be deleted
				break
			}
			if !startDelete && event.DataID() >= firstDataID && event.DataID() <= lastDataID {
				startDelete = true
			} else if startDelete && event.DataID() > lastDataID {
				// out of the data id, just break
				break
			}

			if startDelete {
				tmp := e.Next()
				r.detailEvents.Remove(e)
				log.Debugf("delete detail event from readed buffer, data id: %d, ref: %p", event.DataID(), r)
				e = tmp
			} else {
				e = e.Next()
			}
		}
	}

	// delete until to current position
	next := r.head.element
	stillCurrent := true
	for ; next != nil && next != r.current.element; next = r.removeElement0(next) {
		stillCurrent = false
	}
	// not enough data, then return
	if !stillCurrent && next == nil {
		return true
	}

	if next != nil && next.Value.(SocketDataBuffer).BufferLen() == r.current.bufIndex { // all buffer finished, then delete it
		// the last event already read finished, then delete it
		r.head.element = r.removeElement0(next)
		r.head.bufIndex = 0
	} else {
		if !stillCurrent {
			r.head.element = next
		}
		// still have reduced buffer, then keep reading from current index in next loop
		r.head.bufIndex = r.current.bufIndex
	}
	return false
}

// SkipCurrentElement skip current element in reader, if return true means have read finished
func (r *Buffer) SkipCurrentElement() bool {
	r.head.element = r.nextElement(r.current.element)
	r.current.bufIndex = 0

	return r.head.element == nil
}

func (r *Buffer) removeElement0(element *list.Element) *list.Element {
	if element == nil {
		return nil
	}
	result := element.Next()
	r.dataEvents.Remove(element)
	if element.Value != nil {
		if b, ok := element.Value.(SocketDataBuffer); ok && b != nil {
			PooledBuffer.Put(b.ReleaseBuffer())
		}
	}
	return result
}

func (r *Buffer) AppendDetailEvent(event SocketDataDetail) {
	r.eventLocker.Lock()
	defer r.eventLocker.Unlock()

	if r.detailEvents.Len() == 0 {
		r.detailEvents.PushFront(event)
		return
	}
	if r.detailEvents.Back().Value == nil {
		r.detailEvents.PushFront(event)
		return
	}
	if r.detailEvents.Back().Value.(SocketDataDetail).DataID() < event.DataID() {
		r.detailEvents.PushBack(event)
		return
	}
	beenAdded := false
	for element := r.detailEvents.Front(); element != nil; element = element.Next() {
		existEvent, ok := element.Value.(SocketDataDetail)
		if !ok {
			continue
		}
		if existEvent.DataID() > event.DataID() {
			// data id needs order
			beenAdded = true
		}
		if beenAdded {
			r.detailEvents.InsertBefore(event, element)
			break
		}
	}
	if !beenAdded {
		r.detailEvents.PushBack(event)
	}
}

// AppendDataEvent insert the event to the event list following the order
func (r *Buffer) AppendDataEvent(event SocketDataBuffer) {
	r.eventLocker.Lock()
	defer r.eventLocker.Unlock()

	defer func() {
		// if the current position is not nil and the current reading data id is bigger than the event data id
		if r.current != nil && r.current.DataID() > event.DataID() {
			r.shouldResetPosition = true
		}
	}()

	if r.dataEvents.Len() == 0 {
		r.dataEvents.PushFront(event)
		r.shouldResetPosition = true
		return
	}
	if r.dataEvents.Back().Value.(SocketDataBuffer).DataID() < event.DataID() {
		r.dataEvents.PushBack(event)
		return
	}
	beenAdded := false
	for element := r.dataEvents.Front(); element != nil; element = element.Next() {
		existEvent := element.Value.(SocketDataBuffer)
		if existEvent.DataID() > event.DataID() {
			// data id needs order
			beenAdded = true
		} else if existEvent.DataID() == event.DataID() && existEvent.DataSequence() > event.DataSequence() {
			// following the sequence order
			beenAdded = true
		}
		if beenAdded {
			r.dataEvents.InsertBefore(event, element)
			break
		}
	}
	if !beenAdded {
		r.dataEvents.PushBack(event)
	}
}

func (r *Buffer) DeleteExpireEvents(expireDuration time.Duration) int {
	r.eventLocker.Lock()
	defer r.eventLocker.Unlock()

	expireTime := time.Now().Add(-expireDuration)
	// data event queue
	count := r.deleteEventsWithJudgement(r.dataEvents, func(element *list.Element) bool {
		if element.Value == nil {
			return true
		}
		buffer := element.Value.(SocketDataBuffer)
		startTime := host.Time(buffer.StartTime())
		if expireTime.After(startTime) {
			r.latestExpiredDataID = buffer.DataID()
			PooledBuffer.Put(buffer.ReleaseBuffer())
			return true
		}
		return false
	})

	// detail event queue
	count += r.deleteEventsWithJudgement(r.detailEvents, func(element *list.Element) bool {
		detail, ok := element.Value.(SocketDataDetail)
		if !ok {
			return true
		}
		isDelete := r.latestExpiredDataID > 0 && detail.DataID() <= r.latestExpiredDataID ||
			(detail.Time() > 0 && expireTime.After(host.Time(detail.Time())))
		if isDelete {
			log.Debugf("delete expired detail event, data id: %d, buf: %p", detail.DataID(), r)
		}
		return isDelete
	})
	return count
}

func (r *Buffer) DataLength() int {
	r.eventLocker.RLock()
	defer r.eventLocker.RUnlock()
	if r.dataEvents == nil {
		return 0
	}
	return r.dataEvents.Len()
}

func (r *Buffer) deleteEventsWithJudgement(l *list.List, checker func(element *list.Element) bool) int {
	count := 0
	for e := l.Front(); e != nil; {
		if checker(e) {
			count++
			cur := e
			e = e.Next()
			l.Remove(cur)
		} else {
			break
		}
	}
	return count
}

func (r *Buffer) nextElement(e *list.Element) *list.Element {
	if e == nil {
		return nil
	}
	r.eventLocker.RLock()
	defer r.eventLocker.RUnlock()
	return e.Next()
}
