package keeper

/*
	Сторож системных сигналов.
	Мониторит ОС и части сервиса на завершение работы.
	В системе он должен быть только один.
*/

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"wartank/pkg/types"
)

// Сторож -- сторож системных и внутренних сигналов
type Сторож struct {
	kernel types.ИЯдро
	слог   types.ИЛоггер
	chSys  chan os.Signal
}

const (
	стрСторож = "сторож"
)

// НовСторож -- возвращает глобальный объект сторожа *Keeper
func НовСторож(kernel types.ИЯдро) *Сторож {
	if kernel == nil {
		panic("GetKeeper(): IKernel is nil")
	}

	сам := &Сторож{
		kernel: kernel,
		слог:   kernel.Слог(),
		chSys:  make(chan os.Signal, 3),
	}
	ош := сам.kernel.Wg().Add(стрСторож)
	if ош != nil {
		panic(fmt.Sprintf("НовСторож(): при добавлении группы ожидания %q, ош=\n\t%v\n", стрСторож, ош.Error()))
	}
	signal.Notify(сам.chSys, os.Interrupt, syscall.SIGTERM)
	go сам.run()
	сам.слог.Отладка("NewKeeper()\n")
	return сам
}

// Слушает сигналы завершения изнутри и снаружи
func (сам *Сторож) run() {
	сам.слог.Инфо("Keeper.run()\n")
	defer func() {
		сам.слог.Инфо("Keeper.run(): end\n")
		ош := сам.kernel.Wg().Done(стрСторож)
		if ош != nil {
			сам.слог.Ошибка("Keeper.run(): при удалении группы ожидания, ош=\n\t%w", ош)
		}
	}()
	select {
	case sig := <-сам.kernel.Done(): // глобальная отмена контекста
		сам.слог.Инфо("Keeper.run(): intern_sig=%q\n", sig)
	case sig := <-сам.chSys: // Системный сигнал закрытия
		сам.kernel.Отменить()
		сам.слог.Инфо("Keeper.run(): sys_sig=%v\n", sig)
	}
}
