package termutil

import (
	"errors"
	"os"
	"os/signal"
	"sync"
	"syscall"
)

var echoLocked bool
var echoLockMutex sync.Mutex
var errLocked = errors.New("terminal locked")

// RawModeOn switches terminal to raw mode
func RawModeOn() (quit chan struct{}, err error) {
	echoLockMutex.Lock()
	defer echoLockMutex.Unlock()
	if echoLocked {
		err = errLocked
		return
	}
	if err = lockEcho(); err != nil {
		return
	}
	echoLocked = true
	quit = make(chan struct{}, 1)
	go catchTerminate(quit)
	return
}

// RawModeOff restore previous terminal state
func RawModeOff() (err error) {
	echoLockMutex.Lock()
	defer echoLockMutex.Unlock()
	if !echoLocked {
		return
	}
	if err = unlockEcho(); err != nil {
		return
	}
	echoLocked = false
	return
}

// listen exit signals and restore terminal state
func catchTerminate(quit chan struct{}) {
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGKILL)
	defer signal.Stop(sig)
	select {
	case <-quit:
		RawModeOff()
	case <-sig:
		RawModeOff()
	}
}
