package jitter

import (
	"math/rand"
	"time"
)

var rng = rand.New(rand.NewSource(1))

func init() {
	// casual entropy
	rng.Seed(time.Now().UnixNano())
}

func when(d time.Duration) int64 {
	if d <= 0 {
		d = 0
	}
	t := time.Now().Add(d).UnixNano()
	if t < 0 {
		t = 1<<63 - 1
	}
	return t
}

func sendTime(c interface{}) {
	select {
	case c.(chan time.Time) <- time.Now():
	default:
	}
}

type Timer struct {
	C <-chan time.Time
	t timer
}

func NewTimer(dist Distribution) *Timer {
	c := make(chan time.Time, 1)
	t := &Timer{
		C: c,
		t: timer{
			when: when(dist.delta(rng)),
			f:    sendTime,
			arg:  c,
		},
	}
	addtimer(&t.t)
	return t
}

func newTimer(d time.Duration) *Timer {
	return NewTimer(Constant(d))
}

func (t *Timer) Stop() bool {
	return deltimer(&t.t)
}

type Ticker struct {
	C <-chan time.Time
	t timer
}

func NewTicker(d time.Duration) *Ticker {
	c := make(chan time.Time, 1)
	t := &Ticker{
		C: c,
		t: timer{
			when:   when(d),
			period: d,
			f:      sendTime,
			arg:    c,
		},
	}
	addtimer(&t.t)
	return t
}
