// 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

import (
	"os"
	"syscall"
	"sync"
	"container/heap"
)

// The event type represents a single After event.
type event struct {
	t        int64        // The absolute time that the event should fire.
	c        chan<- int64 // The channel to send on.
	sleeping bool         // A sleeper is sleeping for this event.
}

type eventHeap []*event

var events eventHeap
var eventMutex sync.Mutex

func init() {
	events.Push(&event{1 << 62, nil, true}) // sentinel
}

// Sleep pauses the current goroutine for at least ns nanoseconds.
// Higher resolution sleeping may be provided by syscall.Nanosleep 
// on some operating systems.
func Sleep(ns int64) os.Error {
	_, err := sleep(Nanoseconds(), ns)
	return err
}

// sleep takes the current time and a duration,
// pauses for at least ns nanoseconds, and
// returns the current time and an error.
func sleep(t, ns int64) (int64, os.Error) {
	// TODO(cw): use monotonic-time once it's available
	end := t + ns
	for t < end {
		errno := syscall.Sleep(end - t)
		if errno != 0 && errno != syscall.EINTR {
			return 0, os.NewSyscallError("sleep", errno)
		}
		t = Nanoseconds()
	}
	return t, nil
}

// After waits at least ns nanoseconds before sending the current time
// on the returned channel.
func After(ns int64) <-chan int64 {
	c := make(chan int64, 1)
	t := ns + Nanoseconds()
	eventMutex.Lock()
	t0 := events[0].t
	heap.Push(events, &event{t, c, false})
	if t < t0 {
		go sleeper()
	}
	eventMutex.Unlock()
	return c
}

// sleeper continually looks at the earliest event in the queue, marks it
// as sleeping, waits until it happens, then removes any events
// in the queue that are due. It stops when it finds an event that is
// already marked as sleeping. When an event is inserted before the first item,
// a new sleeper is started.
//
// Scheduling vagaries mean that sleepers may not wake up in
// exactly the order of the events that they are waiting for,
// but this does not matter as long as there are at least as
// many sleepers as events marked sleeping (invariant). This ensures that
// there is always a sleeper to service the remaining events.
//
// A sleeper will remove at least the event it has been waiting for
// unless the event has already been removed by another sleeper.  Both
// cases preserve the invariant described above.
func sleeper() {
	eventMutex.Lock()
	e := events[0]
	for !e.sleeping {
		t := Nanoseconds()
		if dt := e.t - t; dt > 0 {
			e.sleeping = true
			eventMutex.Unlock()
			if nt, err := sleep(t, dt); err != nil {
				// If sleep has encountered an error,
				// there's not much we can do. We pretend
				// that time really has advanced by the required
				// amount and lie to the rest of the system.
				t = e.t
			} else {
				t = nt
			}
			eventMutex.Lock()
			e = events[0]
		}
		for t >= e.t {
			e.c <- t
			heap.Pop(events)
			e = events[0]
		}
	}
	eventMutex.Unlock()
}

func (eventHeap) Len() int {
	return len(events)
}

func (eventHeap) Less(i, j int) bool {
	return events[i].t < events[j].t
}

func (eventHeap) Swap(i, j int) {
	events[i], events[j] = events[j], events[i]
}

func (eventHeap) Push(x interface{}) {
	events = append(events, x.(*event))
}

func (eventHeap) Pop() interface{} {
	// TODO: possibly shrink array.
	n := len(events) - 1
	e := events[n]
	events[n] = nil
	events = events[0:n]
	return e
}
