package fzf

import “sync”

// Chunk is a list of Items whose size has the upper limit of chunkSize type Chunk struct {

items [chunkSize]Item
count int

}

// ItemBuilder is a closure type that builds Item object from byte array type ItemBuilder func(*Item, []byte) bool

// ChunkList is a list of Chunks type ChunkList struct {

chunks []*Chunk
mutex  sync.Mutex
trans  ItemBuilder

}

// NewChunkList returns a new ChunkList func NewChunkList(trans ItemBuilder) *ChunkList {

return &ChunkList{
        chunks: []*Chunk{},
        mutex:  sync.Mutex{},
        trans:  trans}

}

func (c *Chunk) push(trans ItemBuilder, data []byte) bool {

if trans(&c.items[c.count], data) {
        c.count++
        return true
}
return false

}

// IsFull returns true if the Chunk is full func (c *Chunk) IsFull() bool {

return c.count == chunkSize

}

func (cl *ChunkList) lastChunk() *Chunk {

return cl.chunks[len(cl.chunks)-1]

}

// CountItems returns the total number of Items func CountItems(cs []*Chunk) int {

if len(cs) == 0 {
        return 0
}
return chunkSize*(len(cs)-1) + cs[len(cs)-1].count

}

// Push adds the item to the list func (cl *ChunkList) Push(data []byte) bool {

cl.mutex.Lock()

if len(cl.chunks) == 0 || cl.lastChunk().IsFull() {
        cl.chunks = append(cl.chunks, &Chunk{})
}

ret := cl.lastChunk().push(cl.trans, data)
cl.mutex.Unlock()
return ret

}

// Clear clears the data func (cl *ChunkList) Clear() {

cl.mutex.Lock()
cl.chunks = nil
cl.mutex.Unlock()

}

// Snapshot returns immutable snapshot of the ChunkList func (cl *ChunkList) Snapshot() ([]*Chunk, int) {

cl.mutex.Lock()

ret := make([]*Chunk, len(cl.chunks))
copy(ret, cl.chunks)

// Duplicate the last chunk
if cnt := len(ret); cnt > 0 {
        newChunk := *ret[cnt-1]
        ret[cnt-1] = &newChunk
}

cl.mutex.Unlock()
return ret, CountItems(ret)

}