package main

// lazy filled list
type listLazy struct {
	update  func(int) []*videoContainer
	dry     bool
	state   int
	content []*videoContainer
	par     int
}

// listUpdateChunk concurrently runs the lists update function and
// returns a channel, which sends the data when the update is finished.
func (l *listLazy) listUpdateChunk(state int) chan []*videoContainer {
	chn := make(chan []*videoContainer)
	go func() {
		chn <- l.update(state)
	}()
	return chn
}

// listNew creates a new lazy list with the given update function and a
// parallel update count of 5.
func listNew(update func(int) []*videoContainer) *listLazy {
	return &listLazy{update, false, 0, []*videoContainer{}, 5}
}

// listPar sets the number of parallel update functions to be executed on each
// triggered list update. The count is always >= 1.
func (l *listLazy) listPar(count int) {
	if count < 1 {
		count = 1
	}
	l.par = count
}

// listGet returns the element with the given index from the list. If
// the list is too short the lists update function will be called until
// the requested element is available. If the element could not be acquired
// nil is returned.
func (l *listLazy) listGet(index int) *videoContainer {
	for index >= len(l.content) && !l.dry {
		temp := make([]chan []*videoContainer, l.par)

		for i, _ := range temp {
			temp[i] = l.listUpdateChunk(l.state + i)
		}

		for _, c := range temp {
			data := <-c
			if len(data) == 0 {
				l.dry = true
			}
			l.content = append(l.content, data...)
			l.state++
		}
	}

	if index < len(l.content) {
		return l.content[index]
	}

	return nil
}

// listCached returns all cached entries of the underlying list slice.
func (l *listLazy) listCached() []*videoContainer {
	return l.content
}

// listSlice tries to return the requested slice from the list. If the
// list is too short the lists update function will be called until
// the length is sufficient. If the list is too small, a smaller slice
// then requested may be returned.
func (l *listLazy) listSlice(begin, end int) []*videoContainer {
	if l.listGet(end) == nil {
		if l.listGet(begin) == nil {
			return l.content[0:0]
		}
		return l.content[begin:]
	}
	return l.content[begin:end]
}