//go:build ignore

package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"

	"go/format"
)

var (
	file string
)

func init() {
	flag.StringVar(&file, "o", "", "output")
	flag.Parse()
}

var tables = []struct {
	name   string
	source string
}{
	{
		"cp437_DOSLatinUS",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT",
	},
	{
		"cp737_DOSGreek",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP737.TXT",
	},
	{
		"cp775_DOSBaltRim",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP775.TXT",
	},
	{
		"cp850_DOSLatin1",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP850.TXT",
	},
	{
		"cp852_DOSLatin2",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP852.TXT",
	},
	{
		"cp855_DOSCyrillic",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP855.TXT",
	},
	{
		"cp857_DOSTurkish",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP857.TXT",
	},
	{
		"cp860_DOSPortuguese",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP860.TXT",
	},
	{
		"cp861_DOSIcelandic",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP861.TXT",
	},
	{
		"cp862_DOSHebrew",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP862.TXT",
	},
	{
		"cp863_DOSCanadaF",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP863.TXT",
	},
	{
		"cp864_DOSArabic",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP864.TXT",
	},
	{
		"cp865_DOSNordic",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP865.TXT",
	},
	{
		"cp866_DOSCyrillicRussian",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP866.TXT",
	},
	{
		"cp869_DOSGreek2",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP869.TXT",
	},
	{
		"cp874",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP874.TXT",
	},
	{
		"cp875_IBMGreek",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/EBCDIC/CP875.TXT",
	},
	{
		"cp1026_IBMLatin5Turkish",
		"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/EBCDIC/CP1026.TXT",
	},
}

func main() {

	out := bytes.NewBuffer(nil)

	fmt.Fprintln(out, "//", "Code generated by maketables.go. DO NOT EDIT.")

	fmt.Fprintln(out, "package", "oem")

	for _, e := range tables {
		cp, err := GetCodePage(e.name, e.source)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		fmt.Fprintln(out, "//", e.name)
		fmt.Fprintln(out, "var", e.name, "=", "[256]rune{")
		for i := 0; i < 256; i += 16 {
			fmt.Fprintln(out, strings.Join(cp[i:i+16], ", "), ",")
		}
		fmt.Fprintln(out, "}")
	}

	b, err := format.Source(out.Bytes())
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	f := os.Stdout

	if file != "" && file != "-" {
		f, err = os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		defer f.Close()
	}

	fmt.Fprintln(f, string(b))
}

type CodePage [265]string

func GetCodePage(n string, url string) (*CodePage, error) {

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	reader := bufio.NewReader(resp.Body)

	codePage := CodePage{}

	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		if len(line) == 0 || line[0] == 0x1A || line[0] == '#' {
			// skip '', '^Z', '#'
			continue
		}

		chr, uni, _, err := split3(line)
		if err != nil {
			return nil, err
		}

		chri, err := strconv.ParseInt(chr, 16, 16)
		if err != nil {
			return nil, err
		}

		if uni == "" {
			codePage[chri] = "0xfffd"
		} else {
			codePage[chri] = "0x" + strings.ToLower(uni)
		}
	}

	return &codePage, nil

}

func split3(line []byte) (string, string, string, error) {
	l := strings.Split(string(line), "\t")
	if len(l) != 3 {
		return "", "", "", errors.New("invalid line")
	}
	return strings.TrimSpace(strings.TrimPrefix(l[0], "0x")), strings.TrimSpace(strings.TrimPrefix(l[1], "0x")), strings.TrimPrefix(l[2], "#"), nil
}
