package clock

import (
	
	
)

// TickerScheduler is the interface implemented by a clock that provides an
// optimized implementation of Ticker.
type TickerScheduler interface {
	Scheduler

	// Ticker returns a new Ticker containing a channel that will send the time
	// on the channel after each tick. The period of the ticks is specified by the
	// duration argument. The ticker will adjust the time interval or drop ticks to
	// make up for slow receivers. The duration d must be greater than zero; if
	// not, Ticker will panic. Stop the ticker to release associated resources.
	Ticker(d time.Duration) Ticker
}

// A Ticker holds a channel that delivers “ticks” of a clock at intervals.
type Ticker interface {
	// C returns the channel on which the ticks are delivered.
	C() <-chan time.Time
	// Stop turns off a ticker. After Stop, no more ticks will be sent. Stop does
	// not close the channel, to prevent a concurrent goroutine reading from the
	// channel from seeing an erroneous “tick”.
	Stop()
	// Reset stops a ticker and resets its period to the specified duration. The
	// next tick will arrive after the new period elapses. The duration d must be
	// greater than zero; if not, Reset will panic.
	Reset(d time.Duration)
}

// Ticker returns a new Ticker containing a channel that will send the current
// time on the channel after each tick. The period of the ticks is specified by
// the duration argument. The ticker will adjust the time interval or drop ticks
// to make up for slow receivers. The duration d must be greater than zero; if
// not, Ticker will panic. Stop the ticker to release associated resources.
//
// Unless the underlying Scheduler implements TickerScheduler, Ticker calls
// Timer and resets the returned timer on each tick.
func ( *Clock) ( time.Duration) Ticker {
	if  <= 0 {
		panic("non-positive interval for Ticker")
	}

	 := .sched()

	if ,  := .(TickerScheduler);  {
		return .Ticker()
	}
	return newEventTicker(, )
}

// eventTicker implements Ticker interface using a Timer. It intercepts timer’s
// channel and then resets it to continue ticking.
type eventTicker struct {
	t Timer
	c chan time.Time

	mu sync.Mutex
	wg sync.WaitGroup

	resetc  chan time.Duration
	stopc   chan struct{}
	stopped bool

	resetTimer bool
}

func ( *Clock,  time.Duration) *eventTicker {
	 := &eventTicker{
		t:      .Timer(),
		c:      make(chan time.Time, 1),
		resetc: make(chan time.Duration),
		stopc:  make(chan struct{}),
	}
	.start()
	return 
}

// C implements the Ticker interface.
func ( *eventTicker) () <-chan time.Time {
	return .c
}

// Stop implements the Ticker interface.
func ( *eventTicker) () {
	.stop()
}

// Reset implements the Ticker interface.
func ( *eventTicker) ( time.Duration) {
	if  <= 0 {
		panic("non-positive interval for Ticker.Reset")
	}
	.reset()
}

func ( *eventTicker) ( time.Duration) {
	.wg.Add(1)
	go func() {
		defer .wg.Done()
		.run()
	}()
}

func ( *eventTicker) ( time.Duration) {
	 := .t
	 := .C()
	if .resetTimer {
		.Reset()
	}
	.resetTimer = true

	for {
		select {
		case <-.stopc:
			.stopTimer()
			return
		case  = <-.resetc:
			.stopTimer()
			.Reset()
		case  := <-:
			.Reset()
			select {
			case .c <- :
			default:
			}
		}
	}
}

func ( *eventTicker) ( time.Duration) {
	.mu.Lock()
	defer .mu.Unlock()

	if .stopped {
		.stopped = false
		.start()
		return
	}
	.resetc <- 
}

func ( *eventTicker) () {
	.mu.Lock()
	defer .mu.Unlock()

	if .stopped {
		return
	}
	.stopped = true
	.stopc <- struct{}{}
	.wg.Wait()
}

func ( *eventTicker) () {
	if .t.Stop() {
		return
	}
	<-.t.C()
}