package main

// This program expects cldr zip present in the project root.
// You can download it at https://unicode.org/Public/cldr/44/cldr-common-44.0.zip

import (
	"fmt"
	"os"
	"strings"

	"golang.org/x/text/language"
	"golang.org/x/text/unicode/cldr"
)

type CharacterOrder string

func (o CharacterOrder) HTMLDir() (string, bool) {
	switch o {
	case LTR:
		return "ltr", true
	case RTL:
		return "rtl", true
	default:
		return "", false
	}
}

const RTL CharacterOrder = "right-to-left"
const LTR CharacterOrder = "left-to-right"
const TTB CharacterOrder = "top-to-bottom"

func NewCharacterOrder(raw string) (CharacterOrder, error) {
	switch raw {
	case string(LTR):
		return LTR, nil
	case string(RTL):
		return RTL, nil
	case string(TTB):
		return TTB, nil
	}
	return "", fmt.Errorf("unknown character order: %v", raw)
}

func ReadCLDR() (map[string]string, error) {
	var d cldr.Decoder

	commonZip, err := os.Open("./cldr-common-44.0.zip")
	if err != nil {
		return nil, err
	}

	// We only care about character order.
	d.SetDirFilter("main")
	d.SetSectionFilter("layout")

	cldr, err := d.DecodeZip(commonZip)
	if err != nil {
		return nil, err
	}

	out := make(map[string]string)

	locales := cldr.Locales()
	for _, locale := range locales {
		// Ignore the root locale.
		if locale == "root" {
			continue
		}

		ldml := cldr.RawLDML(locale)
		layout := ldml.Layout

		// Ignore locales that do not have layout.
		if layout == nil {
			continue

		}

		var rawCharacterOrder string
		for _, o := range layout.Orientation {
			for _, order := range o.CharacterOrder {
				rawCharacterOrder = order.Data()
			}
		}

		// Ignore locales that do not have character order.
		if rawCharacterOrder == "" {
			continue
		}

		characterOrder, err := NewCharacterOrder(rawCharacterOrder)
		if err != nil {
			return nil, err
		}

		// Ignore locales whose character order is rtl.
		dir, ok := characterOrder.HTMLDir()
		if !ok {
			continue
		}

		if dir != "rtl" {
			continue
		}

		t, err := language.Parse(locale)
		if err != nil {
			return nil, err
		}

		out[t.String()] = dir
	}

	return out, nil
}

func WriteGoSourceFile(m map[string]string) (string, error) {
	mm := make(map[string]string)

	for tag := range m {
		parts := strings.Split(tag, "-")
		if len(parts) != 1 && len(parts) != 2 {
			return "", fmt.Errorf("expected locale to be lang or lang-Script: %v", tag)
		}

		lang := parts[0]
		var script string
		if len(parts) == 2 {
			script = parts[1]
			if len(script) != 4 {
				return "", fmt.Errorf("invalid script: %v", tag)
			}
		}

		_, ok := mm[lang]
		if ok {
			return "", fmt.Errorf("do not expect lang to repeat: %v", lang)
		}
		mm[lang] = script
	}

	var buf strings.Builder
	buf.WriteString("package intl\n")
	buf.WriteString("\n")
	buf.WriteString("// This file is generated by devtools/characterorder/main.go\n")
	buf.WriteString("// DO NOT edit it manually!")
	buf.WriteString("\n")
	buf.WriteString("\n")
	buf.WriteString(fmt.Sprintf("var rtlMap = %#v\n", mm))
	return buf.String(), nil
}

func main() {
	m, err := ReadCLDR()
	if err != nil {
		panic(err)
	}

	contents, err := WriteGoSourceFile(m)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%v", contents)
}
