// go.cypherpunks.su/tai64n -- Pure Go TAI64/TAI64N implementation
// Copyright (C) 2020-2025 Sergey Matveev <stargrave@stargrave.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// TAI64/TAI64N (http://cr.yp.to/libtai/tai64.html) dealing library.
// You can convert time to TAI64/TAI64N and vice versa with it.
//
//	var tai tai64n.TAI64N
//	tai.FromTime(time.Now())
//	printable := tai.Encode()
//	decoded, err := tai64n.Decode(printable)
//	tai.Time() == decoded
package tai64n

import (
	"encoding/binary"
	"time"
)

const (
	TAI64Size   = 8
	TAI64NSize  = TAI64Size + 4
	TAI64NASize = TAI64NSize + 4
	Base        = 0x4000000000000000
)

type (
	TAI64   [TAI64Size]byte
	TAI64N  [TAI64NSize]byte
	TAI64NA [TAI64NASize]byte
)

func (tai *TAI64) FromTime(src time.Time) {
	binary.BigEndian.PutUint64(tai[:], uint64(Base)+uint64(src.Unix()))
}

func (tai *TAI64N) FromTime(src time.Time) {
	binary.BigEndian.PutUint64(tai[:], uint64(Base)+uint64(src.Unix()))
	binary.BigEndian.PutUint32(tai[TAI64Size:], uint32(src.Nanosecond()))
}

func (tai *TAI64) Time() time.Time {
	return time.Unix(int64(binary.BigEndian.Uint64(tai[:TAI64Size]))-Base, 0).In(time.UTC)
}

func (tai *TAI64N) Time() time.Time {
	return time.Unix(
		int64(binary.BigEndian.Uint64(tai[:TAI64Size]))-Base,
		int64(binary.BigEndian.Uint32(tai[TAI64Size:])),
	).In(time.UTC)
}
