// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cldrtree

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"

	"golang.org/x/text/internal/gen"
)

func generate(b *Builder, t *Tree, w *gen.CodeWriter) error {
	fmt.Fprintln(w, `import "golang.org/x/text/internal/cldrtree"`)
	fmt.Fprintln(w)

	fmt.Fprintf(w, "var tree = &cldrtree.Tree{locales, indices, buckets}\n\n")

	w.WriteComment("Path values:\n%s", b.stats())
	fmt.Fprintln(w)

	// Generate enum types.
	for _, e := range b.enums {
		// Build enum types.
		w.WriteComment("%s specifies a property of a CLDR field.", e.name)
		fmt.Fprintf(w, "type %s uint16\n", e.name)
	}

	d, err := getEnumData(b)
	if err != nil {
		return err
	}
	fmt.Fprintln(w, "const (")
	for i, k := range d.keys {
		fmt.Fprintf(w, "%s %s = %d // %s\n", toCamel(k), d.enums[i], d.m[k], k)
	}
	fmt.Fprintln(w, ")")

	w.WriteVar("locales", t.Locales)
	w.WriteVar("indices", t.Indices)

	// Generate string buckets.
	fmt.Fprintln(w, "var buckets = []string{")
	for i := range t.Buckets {
		fmt.Fprintf(w, "bucket%d,\n", i)
	}
	fmt.Fprint(w, "}\n\n")
	w.Size += int(reflect.TypeOf("").Size()) * len(t.Buckets)

	// Generate string buckets.
	for i, bucket := range t.Buckets {
		w.WriteVar(fmt.Sprint("bucket", i), bucket)
	}
	return nil
}

func generateTestData(b *Builder, w *gen.CodeWriter) error {
	d, err := getEnumData(b)
	if err != nil {
		return err
	}

	fmt.Fprintln(w)
	fmt.Fprintln(w, "var enumMap = map[string]uint16{")
	fmt.Fprintln(w, `"": 0,`)
	for _, k := range d.keys {
		fmt.Fprintf(w, "%q: %d,\n", k, d.m[k])
	}
	fmt.Fprintln(w, "}")
	return nil
}

func toCamel(s string) string {
	p := strings.Split(s, "-")
	for i, s := range p[1:] {
		p[i+1] = strings.Title(s)
	}
	return strings.Replace(strings.Join(p, ""), "/", "", -1)
}

func (b *Builder) stats() string {
	w := &bytes.Buffer{}

	b.rootMeta.validate()
	for _, es := range b.enums {
		fmt.Fprintf(w, "<%s>\n", es.name)
		printEnumValues(w, es, 1, nil)
	}
	fmt.Fprintln(w)
	printEnums(w, b.rootMeta.typeInfo, 0)
	fmt.Fprintln(w)
	fmt.Fprintln(w, "Nr elem:           ", len(b.strToBucket))
	fmt.Fprintln(w, "uniqued size:      ", b.size)
	fmt.Fprintln(w, "total string size: ", b.sizeAll)
	fmt.Fprintln(w, "bucket waste:      ", b.bucketWaste)

	return w.String()
}

func printEnums(w io.Writer, s *typeInfo, indent int) {
	idStr := strings.Repeat("  ", indent) + "- "
	e := s.enum
	if e == nil {
		if len(s.entries) > 0 {
			panic(fmt.Errorf("has entries but no enum values: %#v", s.entries))
		}
		return
	}
	if e.name != "" {
		fmt.Fprintf(w, "%s<%s>\n", idStr, e.name)
	} else {
		printEnumValues(w, e, indent, s)
	}
	if s.sharedKeys() {
		for _, v := range s.entries {
			printEnums(w, v, indent+1)
			break
		}
	}
}

func printEnumValues(w io.Writer, e *enum, indent int, info *typeInfo) {
	idStr := strings.Repeat("  ", indent) + "- "
	for i := 0; i < len(e.keys); i++ {
		fmt.Fprint(w, idStr)
		k := e.keys[i]
		if u, err := strconv.ParseUint(k, 10, 16); err == nil {
			fmt.Fprintf(w, "%s", k)
			// Skip contiguous integers
			var v, last uint64
			for i++; i < len(e.keys); i++ {
				k = e.keys[i]
				if v, err = strconv.ParseUint(k, 10, 16); err != nil {
					break
				}
				last = v
			}
			if u < last {
				fmt.Fprintf(w, `..%d`, last)
			}
			fmt.Fprintln(w)
			if err != nil {
				fmt.Fprintf(w, "%s%s\n", idStr, k)
			}
		} else if k == "" {
			fmt.Fprintln(w, `""`)
		} else {
			fmt.Fprintf(w, "%s\n", k)
		}
		if info != nil && !info.sharedKeys() {
			if e := info.entries[enumIndex(i)]; e != nil {
				printEnums(w, e, indent+1)
			}
		}
	}
}

func getEnumData(b *Builder) (*enumData, error) {
	d := &enumData{m: map[string]int{}}
	if errStr := d.insert(b.rootMeta.typeInfo); errStr != "" {
		// TODO: consider returning the error.
		return nil, fmt.Errorf("cldrtree: %s", errStr)
	}
	return d, nil
}

type enumData struct {
	m     map[string]int
	keys  []string
	enums []string
}

func (d *enumData) insert(t *typeInfo) (errStr string) {
	e := t.enum
	if e == nil {
		return ""
	}
	for i, k := range e.keys {
		if _, err := strconv.ParseUint(k, 10, 16); err == nil {
			// We don't include any enum that has integer values.
			break
		}
		if v, ok := d.m[k]; ok {
			if v != i {
				return fmt.Sprintf("%q has value %d and %d", k, i, v)
			}
		} else {
			d.m[k] = i
			if k != "" {
				d.keys = append(d.keys, k)
				d.enums = append(d.enums, e.name)
			}
		}
	}
	for i := range t.enum.keys {
		if e := t.entries[enumIndex(i)]; e != nil {
			if errStr := d.insert(e); errStr != "" {
				return fmt.Sprintf("%q>%v", t.enum.keys[i], errStr)
			}
		}
	}
	return ""
}
