/ ==========================================================================
// $Id: semaphore.go,v 1.1 2020/01/28 23:16:28 jlang Exp $
// CSI2120 GO: Concurrency - semaphores and waitgroup
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   EECS, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada.
//   http://www.eecs.uottawa.ca
//
// Creator: Jochen Lang
// Email:   jlang@eecs.uottawa.ca
// ==========================================================================
// $Log: semaphore.go,v $
// Revision 1.1  2020/01/28 23:16:28  jlang
// Added semaphore and waitgroup example.
//
// ==========================================================================
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// Channel with buffer size 10
var sem = make(chan int, 10)

var wg sync.WaitGroup

type Request struct {
	Num int
}

func NewRequest(i int) *Request {
	var r Request
	r.Num = i
	return &r
}

func handle(r *Request) {
	process(r) // Process the request
	<-sem      // Done, room for next request.
	return
}

func process(r *Request) {
	defer wg.Done()
	ms := rand.Intn(1000)
	time.Sleep(time.Duration(ms) * time.Millisecond)
	fmt.Printf("Done %d \n", r.Num)
	return
}

func MyServer(queue chan *Request) {
	for {
		req := <-queue // receive a new request
		sem <- 1       // Are we below 10, if not wait
		go handle(req)
	}
	return
}

func main() {
	rand.Seed(42)
	queue := make(chan *Request)
	go MyServer(queue)
	for i := 0; i < 50; i++ {
		wg.Add(1)
		go func(j int) {
			queue <- NewRequest(j)
		}(i)
	}
	wg.Wait()
}
