package uuid

/****************
 * Date: 14/02/14
 * Time: 7:46 PM
 ***************/

import (
	"time"
)

const (
	// A tick is 100 ns
	ticksPerSecond = 10000000

	// Difference between
	gregorianToUNIXOffset uint64 = 0x01B21DD213814000

	// set the following to the number of 100ns ticks of the actual
	// resolution of your system's clock
	idsPerTimestamp = 1024
)

var (
	lastTimestamp    Timestamp
	idsThisTimestamp = idsPerTimestamp
)

// **********************************************  Timestamp

type Timestamp uint64

// TODO Create c version same as package runtime and time
func Now() (sec int64, nsec int32) {
	t := time.Now()
	sec = t.Unix()
	nsec = int32(t.Nanosecond())
	return
}

// Converts Unix formatted time to RFC4122 UUID formatted times
// UUID UTC base time is October 15, 1582.
// Unix base time is January 1, 1970.
// Converts time to 100 nanosecond ticks since epoch
// There are 1000000000 nanoseconds in a second,
// 1000000000 / 100 = 10000000 tiks per second
func timestamp() Timestamp {
	sec, nsec := Now()
	return Timestamp(uint64(sec)*ticksPerSecond +
		uint64(nsec)/100 + gregorianToUNIXOffset)
}

func (o Timestamp) Unix() time.Time {
	t := uint64(o) - gregorianToUNIXOffset
	return time.Unix(0, int64(t*100))
}

// Get time as 60-bit 100ns ticks since UUID epoch.
// Compensate for the fact that real clock resolution is
// less than 100ns.
func currentUUIDTimestamp() Timestamp {
	var timeNow Timestamp
	for {
		timeNow = timestamp()

		// if clock reading changed since last UUID generated
		if lastTimestamp != timeNow {
			// reset count of UUIDs with this timestamp
			idsThisTimestamp = 0
			lastTimestamp = timeNow
			break
		}
		if idsThisTimestamp < idsPerTimestamp {
			idsThisTimestamp++
			break
		}
		// going too fast for the clock; spin
	}
	// add the count of UUIDs to low order bits of the clock reading
	return timeNow + Timestamp(idsThisTimestamp)
}