// Copyright 2018-2020 opcua authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file

package main

import (
	"bytes"
	"encoding/csv"
	"flag"
	"go/format"
	"log"
	"os"
	"strings"
	"text/template"
)

func main() {
	log.SetFlags(0)

	in := flag.String("in", "schema/NodeIds.csv", "path to NodeIds.csv")
	out := flag.String("out", "id/id_gen.go", "path to generated file")
	flag.Parse()

	if *in == "" {
		log.Fatal("-in is required")
	}
	if *out == "" {
		log.Fatal("-out is required")
	}

	f, err := os.Open(*in)
	if err != nil {
		log.Fatalf("Error reading %s: %v", *in, err)
	}
	defer f.Close()

	rows, err := csv.NewReader(f).ReadAll()
	if err != nil {
		log.Fatalf("Error parsing %s: %v", *in, err)
	}

	for i := range rows {
		rows[i][0] = goName(rows[i][0])
	}

	var b bytes.Buffer
	if err := tmpl.Execute(&b, rows); err != nil {
		log.Fatalf("Error generating code: %v", err)
	}

	bfmt, err := format.Source(b.Bytes())
	if err != nil {
		log.Fatalf("Error formatting code: %v", err)
	}

	if err := os.WriteFile(*out, bfmt, 0644); err != nil {
		log.Fatalf("Error writing %s: %v", *out, err)
	}
	log.Printf("Wrote %s", *out)
}

var tmpl = template.Must(template.New("").Parse(`
// Copyright 2018-2020 opcua authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

// Code generated by cmd/id. DO NOT EDIT!

package id

import "strconv"

func Name(id uint32) string {
	if s, ok := name[id]; ok {
		return s
	}
	return strconv.FormatUint(uint64(id), 10)
}

const (
	{{range .}}{{index . 0}} = {{index . 1}}
	{{end}}
)

var name = map[uint32]string{
	{{- range .}}
	{{index . 1}}: "{{index . 0}}",
	{{- end}}
}
`))

func goName(s string) string {
	r1 := strings.NewReplacer(
		"Guid", "GUID",
		"Id", "ID",
		"Json", "JSON",
		"QualityOfService", "QoS",
		"Uadp", "UADP",
		"Uri", "URI",
		"Url", "URL",
		"Xml", "XML",
	)
	r2 := strings.NewReplacer(
		"IDentity", "Identity",
	)
	return r2.Replace(r1.Replace(s))
}
