// Package workerpool
// https://brandur.org/go-worker-pool
// https://gobyexample.com/worker-pools
package workerpool

import "sync"

// Pool is a worker group that runs a number of tasks at a
// configured concurrency.
type Pool struct {
	Tasks []func()

	concurrency int
	ch          chan func()
	wg          sync.WaitGroup
}

// NewPool initializes a new pool with the given tasks and
// at the given concurrency.
func NewPool(concurrency int) *Pool {
	return &Pool{
		Tasks:       make([]func(), 0),
		ch:          make(chan func()),
		concurrency: concurrency,
	}
}

func (p *Pool) AddTask(task func()) {
	p.Tasks = append(p.Tasks, task)
}

// Run runs all work within the pool and blocks until it's
// finished.
func (p *Pool) Run() {
	for i := 0; i < p.concurrency; i++ {
		go func() {
			for task := range p.ch {
				task()
				p.wg.Done()
			}
		}()
	}

	p.wg.Add(len(p.Tasks))
	for _, task := range p.Tasks {
		p.ch <- task
	}

	close(p.ch)

	p.wg.Wait()
}
