// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package time

// TODO(rsc): This implementation of Tick is a
// simple placeholder.  Eventually, there will need to be
// a single central time server no matter how many tickers
// are active.
//
// Also, if timeouts become part of the select statement,
// perhaps the Ticker is just:
//
//	func Ticker(ns int64, c chan int64) {
//		for {
//			select { timeout ns: }
//			nsec, err := Nanoseconds();
//			c <- nsec;
//		}


// A Ticker holds a synchronous channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
	C		<-chan int64;	// The channel on which the ticks are delivered.
	ns		int64;
	shutdown	bool;
}

// Stop turns off a ticker.  After Stop, no more ticks will be delivered.
func (t *Ticker) Stop() {
	t.shutdown = true;
}

func (t *Ticker) ticker(c chan<- int64) {
	now := Nanoseconds();
	when := now;
	for !t.shutdown {
		when += t.ns;	// next alarm

		// if c <- now took too long, skip ahead
		if when < now {
			// one big step
			when += (now-when) / t.ns * t.ns;
		}
		for when <= now {
			// little steps until when > now
			when += t.ns;
		}

		Sleep(when-now);
		now = Nanoseconds();
		if t.shutdown {
			return;
		}
		c <- now;
	}
}

// Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only.  Useful for clients that have no need to shut down the ticker.
func Tick(ns int64) <-chan int64 {
	if ns <= 0 {
		return nil;
	}
	return NewTicker(ns).C;
}

// Ticker returns a new Ticker containing a synchronous channel that will
// send the time, in nanoseconds, every ns nanoseconds.  It adjusts the
// intervals to make up for pauses in delivery of the ticks.
func NewTicker(ns int64) *Ticker {
	if ns <= 0 {
		return nil;
	}
	c := make(chan int64);
	t := &Ticker{c, ns, false};
	go t.ticker(c);
	return t;
}
