package udt

import (
	"sync"
	"time"

	"github.com/PeernetOfficial/core/udt/packet"
)

type sendPacketEntry struct {
	pkt *packet.DataPacket

	// data specific to sending packets
	tim time.Time
	ttl time.Duration
}

// sendPacketHeap stores a list of packets. Packets are identified by their sequences.
// Access to the list via functions is thread safe.
// This isn't the fastest implementation on the planet since each operation iterates over the entire list. However, it works and is thread safe (the previous code was neither).
type sendPacketHeap struct {
	// list contains all packets
	list []sendPacketEntry

	sync.RWMutex
}

func createPacketHeap() (heap *sendPacketHeap) {
	return &sendPacketHeap{}
}

// Add adds a packet to the list. Deduplication is not performed.
func (heap *sendPacketHeap) Add(newPacket sendPacketEntry) {
	heap.Lock()
	defer heap.Unlock()

	heap.list = append(heap.list, newPacket)
}

// Remove removes all packets with the sequence from the list.
func (heap *sendPacketHeap) Remove(sequence uint32) {
	heap.Lock()
	defer heap.Unlock()

	var newList []sendPacketEntry

	for n := range heap.list {
		if heap.list[n].pkt.Seq.Seq != sequence {
			newList = append(newList, heap.list[n])
		}
	}

	heap.list = newList
}

// Count returns the number of packets stored
func (heap *sendPacketHeap) Count() (count int) {
	return len(heap.list)
}

// Find searches for the packet
func (heap *sendPacketHeap) Find(sequence uint32) (result sendPacketEntry, found bool) {
	heap.RLock()
	defer heap.RUnlock()

	for n := range heap.list {
		if heap.list[n].pkt.Seq.Seq == sequence {
			return heap.list[n], true
		}
	}

	return result, false // not found
}

// RemoveRange removes all packets that are within the given range. Check is from >= and to <.
func (heap *sendPacketHeap) RemoveRange(sequenceFrom, sequenceTo packet.PacketID) {
	heap.Lock()
	defer heap.Unlock()

	var newList []sendPacketEntry

	for n := range heap.list {
		if !(heap.list[n].pkt.Seq.IsBiggerEqual(sequenceFrom) && heap.list[n].pkt.Seq.IsLess(sequenceTo)) {
			newList = append(newList, heap.list[n])
		}
	}

	heap.list = newList
}

// Range returns all packets that are within the given range. Check is from >= and to <.
func (heap *sendPacketHeap) Range(sequenceFrom, sequenceTo packet.PacketID) (result []sendPacketEntry) {
	heap.RLock()
	defer heap.RUnlock()

	for n := range heap.list {
		if heap.list[n].pkt.Seq.IsBiggerEqual(sequenceFrom) && heap.list[n].pkt.Seq.IsLess(sequenceTo) {
			result = append(result, heap.list[n])
		}
	}

	return result
}
