package seafile

import (
	"sync"
	"time"

	"github.com/rclone/rclone/fs"
)

// Renew allows tokens to be renewed on expiry.
type Renew struct {
	ts       *time.Ticker     // timer indicating when it's time to renew the token
	run      func() error     // the callback to do the renewal
	done     chan interface{} // channel to end the go routine
	shutdown *sync.Once
}

// NewRenew creates a new Renew struct and starts a background process
// which renews the token whenever it expires.  It uses the run() call
// to do the renewal.
func NewRenew(every time.Duration, run func() error) *Renew {
	r := &Renew{
		ts:       time.NewTicker(every),
		run:      run,
		done:     make(chan interface{}),
		shutdown: &sync.Once{},
	}
	go r.renewOnExpiry()
	return r
}

func (r *Renew) renewOnExpiry() {
	for {
		select {
		case <-r.ts.C:
			err := r.run()
			if err != nil {
				fs.Errorf(nil, "error while refreshing decryption token: %s", err)
			}

		case <-r.done:
			return
		}
	}
}

// Shutdown stops the ticker and no more renewal will take place.
func (r *Renew) Shutdown() {
	// closing a channel can only be done once
	r.shutdown.Do(func() {
		r.ts.Stop()
		close(r.done)
	})
}