package data

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
)

// WH40K has basic text internationalisation capabilities based on a <lang>.dta
// file that maps string IDs to messages
type I18n struct {
	Name    string
	mapping map[int]Entry
}

// FIXME: this should be put into the config file maybe, or detected from a list
// of possibilities?
const (
	I18nFile = "USEng.dta"
)

// I18n entries may have 1 or 2 items. If two, the first is a menu item and the
// second is a help string for that menu item.
//
// The text or help may contain some magic strings, as mentioned in USEng.data
type Entry struct {
	Text string
	Help string
}

func LoadI18n(filename string) (*I18n, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	defer f.Close()

	out := &I18n{
		Name:    filepath.Base(filename),
		mapping: make(map[int]Entry),
	}

	scanner := bufio.NewScanner(f)
	for i := 0; scanner.Scan(); i++ {
		// Remove comments from lines
		line := bytes.TrimSpace(bytes.SplitN(scanner.Bytes(), []byte("//"), 2)[0])

		// Ignore empty lines
		if len(line) == 0 {
			continue
		}

		// Lines are expected to be in this format:
		// <number> "text that may include \" or not"
		parts := bytes.SplitN(line, []byte(" "), 2)
		if len(parts) != 2 {
			return nil, fmt.Errorf("Bad line in %v at %v: %q", filename, i, scanner.Text())
		}

		num, err := strconv.Atoi(string(parts[0]))
		if err != nil {
			return nil, err
		}

		// Cut off the leading and trailing quote characters of the string
		val := parts[1]
		val = val[1 : len(val)-1]

		// TODO: Replace certain escape characters with their literals?

		if entry, ok := out.mapping[num]; !ok { // first time we've seen this
			out.mapping[num] = Entry{Text: string(val)}
		} else { // Second time, the item is help text
			entry.Help = string(val)
			out.mapping[num] = entry
		}
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return out, nil
}

func (n *I18n) Len() int {
	return len(n.mapping)
}

// Puts the internationalized string into `out` if `in` matches a known ID
func (n *I18n) ReplaceText(in int, out *string) {
	if str, ok := n.mapping[in]; ok {
		*out = str.Text
	}
}

func (n *I18n) ReplaceHelp(in int, out *string) {
	if str, ok := n.mapping[in]; ok {
		*out = str.Help
	}
}
