// Copyright (c) 2012-2016 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"html/template"
	"log"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

const tplText = `
// Copyright (c) 2012-2016 Eli Janssen
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

// THIS FILE IS AUTOGENERATED. DO NOT EDIT!

package {{.Pkg}}

// https://hpiers.obspm.fr/iers/bul/bulc/Leap_Second.dat
// http://www.stjarnhimlen.se/comp/time.html
var tia64nDifferences = []struct {
    // TAI time
    ttime int64
    // TAI-UTC offset
	offset int64
    // unix UTC time
	utime int64
}{
	{{- range .Entries}}
	{{"{"}}0x{{.Tts|printf "%x"}}, {{.Drift}}, {{.Ts}}{{"}"}}, // {{.TsD}}
	{{- end}}
}

var tia64nSize = len(tia64nDifferences)
`

type srcFile struct {
	Pkg     string
	Entries []entry
}

type entry struct {
	Ts    int64
	TsD   string
	Drift int64
	Tts   int64
}

const datURL = "https://hpiers.obspm.fr/iers/bul/bulc/Leap_Second.dat"

func main() {
	var output, pkg string
	flag.StringVar(&output, "output", "", "output file")
	flag.StringVar(&pkg, "pkg", "", "package name")
	flag.Parse()

	if output == "" {
		log.Fatal("Output option is required")
	}

	if pkg == "" {
		log.Fatal("Package option is required")
	}

	var br *bufio.Reader
	resp, err := http.Get(datURL)
	if err != nil {
		log.Fatalf("Error fetching '%s': %s", datURL, err)
	}
	defer resp.Body.Close()
	br = bufio.NewReader(resp.Body)

	fmt.Printf("Generating '%s' based on '%s'\n", path.Base(output), datURL)

	t, err := template.New("fileTemplate").Parse(strings.TrimLeft(tplText, "\n"))
	if err != nil {
		log.Fatal(err)
	}

	entries := make([]entry, 0)

	for {
		line, err := br.ReadString('\n')
		if err != nil {
			break
		}

		line = strings.TrimSpace(line)
		if line == "" || strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") {
			continue
		}

		parts := strings.Fields(line)
		// parse date of leap second
		t, err := time.Parse("2-1-2006", strings.Join(parts[1:4], "-"))
		if err != nil {
			fmt.Println(err)
			continue
		}

		if t.Before(time.Date(1972, 1, 1, 0, 0, 0, 0, time.UTC)) {
			continue
		}

		// parse TAI-UTC(s)
		s, err := strconv.ParseFloat(parts[4], 32)
		if err != nil {
			fmt.Println(err)
			continue
		}
		// just truncate the float to int
		unixT := t.Unix()
		taiT := (2 << 61) + unixT + int64(s)
		e := entry{unixT, t.Format(time.RFC3339), int64(s), taiT}
		entries = append(entries, e)
	}

	bufr := &bytes.Buffer{}

	srcfile := &srcFile{pkg, entries}
	err = t.Execute(bufr, srcfile)
	if err != nil {
		log.Fatal(err)
	}

	outBytes, err := format.Source(bufr.Bytes())
	if err != nil {
		log.Fatal(err)
	}

	err = os.WriteFile(output, outBytes, 0644)
	if err != nil {
		log.Fatal(err)
	}
}
