package main

import (
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

func main() {
	// create channel for task
	taskChannel := make(chan bool, 1)

	// create wait-group
	wg := new(sync.WaitGroup)

	// wait for all tasks to finish
	defer func(*sync.WaitGroup) {
		wg.Wait()
		fmt.Printf("All processes stopped, shutting down.\n")
	}(wg)

	// add the task to the wait-group
	wg.Add(1)
	// start task loop
	go infiniteTask(wg, taskChannel, time.Duration(time.Second*5))

	// keep program running until a shutdown signal is received
	forever(taskChannel)
}

func forever(collector chan<- bool) {
	// create signal channel
	s := make(chan os.Signal, 1)
	signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)

	// wait for signal
	sig := <-s
	fmt.Printf("\nstarting shutdown procedure, detected signal: %s\n", sig)

	// send shutdown to collector
	collector <- true
}

func infiniteTask(wg *sync.WaitGroup, shutdown <-chan bool, timeout time.Duration) {
	// set initial time length
	t := time.NewTimer(timeout)
	// stop the time when the process ends
	defer t.Stop()

	// start infinite loop
	for {
		select {
		// catch timer signal
		case <-t.C:
			// trigger task
			doTask()
			// reset timer
			t.Reset(timeout)
		// catch shutdown signal
		case <-shutdown:
			fmt.Printf("Collector Stopped\n")
			// clear the task from the wait-group
			wg.Done()
			// end the loop
			return
		// non-blocking channel receiver to allow for checking of either signal
		default:
			// wait 1 second to keep the program from eating un-necessary cycles
			time.Sleep(time.Second * 1)
		}
	}
}

func doTask() {
	fmt.Printf("Starting task\n")
	time.Sleep(time.Second * 30)
	fmt.Printf("Task finished\n")
}