// 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 plural

import (
	"fmt"
	"io/ioutil"
	"reflect"
	"strconv"

	"golang.org/x/text/internal/catmsg"
	"golang.org/x/text/internal/number"
	"golang.org/x/text/language"
	"golang.org/x/text/message/catalog"
)

// Interface is used for types that can determine their own plural form.
type Interface interface {
	// PluralForm reports the plural form for the given language of the
	// underlying value. It also returns the integer value. If the integer value
	// is larger than fits in n, PluralForm may return a value modulo
	// 10,000,000.
	PluralForm(t language.Tag, scale int) (f Form, n int)
}

// Selectf returns the first case for which its selector is a match for the
// arg-th substitution argument to a formatting call, formatting it as indicated
// by format.
//
// The cases argument are pairs of selectors and messages. Selectors are of type
// string or Form. Messages are of type string or catalog.Message. A selector
// matches an argument if:
//    - it is "other" or Other
//    - it matches the plural form of the argument: "zero", "one", "two", "few",
//      or "many", or the equivalent Form
//    - it is of the form "=x" where x is an integer that matches the value of
//      the argument.
//    - it is of the form "<x" where x is an integer that is larger than the
//      argument.
//
// The format argument determines the formatting parameters for which to
// determine the plural form. This is especially relevant for non-integer
// values.
//
// The format string may be "", in which case a best-effort attempt is made to
// find a reasonable representation on which to base the plural form. Examples
// of format strings are:
//   - %.2f   decimal with scale 2
//   - %.2e   scientific notation with precision 3 (scale + 1)
//   - %d     integer
func Selectf(arg int, format string, cases ...interface{}) catalog.Message {
	var p parser
	// Intercept the formatting parameters of format by doing a dummy print.
	fmt.Fprintf(ioutil.Discard, format, &p)
	m := &message{arg, kindDefault, 0, cases}
	switch p.verb {
	case 'g':
		m.kind = kindPrecision
		m.scale = p.scale
	case 'f':
		m.kind = kindScale
		m.scale = p.scale
	case 'e':
		m.kind = kindScientific
		m.scale = p.scale
	case 'd':
		m.kind = kindScale
		m.scale = 0
	default:
		// TODO: do we need to handle errors?
	}
	return m
}

type parser struct {
	verb  rune
	scale int
}

func (p *parser) Format(s fmt.State, verb rune) {
	p.verb = verb
	p.scale = -1
	if prec, ok := s.Precision(); ok {
		p.scale = prec
	}
}

type message struct {
	arg   int
	kind  int
	scale int
	cases []interface{}
}

const (
	// Start with non-ASCII to allow skipping values.
	kindDefault    = 0x80 + iota
	kindScale      // verb f, number of fraction digits follows
	kindScientific // verb e, number of fraction digits follows
	kindPrecision  // verb g, number of significant digits follows
)

var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)

func (m *message) Compile(e *catmsg.Encoder) error {
	e.EncodeMessageType(handle)

	e.EncodeUint(uint64(m.arg))

	e.EncodeUint(uint64(m.kind))
	if m.kind > kindDefault {
		e.EncodeUint(uint64(m.scale))
	}

	forms := validForms(cardinal, e.Language())

	for i := 0; i < len(m.cases); {
		if err := compileSelector(e, forms, m.cases[i]); err != nil {
			return err
		}
		if i++; i >= len(m.cases) {
			return fmt.Errorf("plural: no message defined for selector %v", m.cases[i-1])
		}
		var msg catalog.Message
		switch x := m.cases[i].(type) {
		case string:
			msg = catalog.String(x)
		case catalog.Message:
			msg = x
		default:
			return fmt.Errorf("plural: message of type %T; must be string or catalog.Message", x)
		}
		if err := e.EncodeMessage(msg); err != nil {
			return err
		}
		i++
	}
	return nil
}

func compileSelector(e *catmsg.Encoder, valid []Form, selector interface{}) error {
	form := Other
	switch x := selector.(type) {
	case string:
		if x == "" {
			return fmt.Errorf("plural: empty selector")
		}
		if c := x[0]; c == '=' || c == '<' {
			val, err := strconv.ParseUint(x[1:], 10, 16)
			if err != nil {
				return fmt.Errorf("plural: invalid number in selector %q: %v", selector, err)
			}
			e.EncodeUint(uint64(c))
			e.EncodeUint(val)
			return nil
		}
		var ok bool
		form, ok = countMap[x]
		if !ok {
			return fmt.Errorf("plural: invalid plural form %q", selector)
		}
	case Form:
		form = x
	default:
		return fmt.Errorf("plural: selector of type %T; want string or Form", selector)
	}

	ok := false
	for _, f := range valid {
		if f == form {
			ok = true
			break
		}
	}
	if !ok {
		return fmt.Errorf("plural: form %q not supported for language %q", selector, e.Language())
	}
	e.EncodeUint(uint64(form))
	return nil
}

func execute(d *catmsg.Decoder) bool {
	lang := d.Language()
	argN := int(d.DecodeUint())
	kind := int(d.DecodeUint())
	scale := -1 // default
	if kind > kindDefault {
		scale = int(d.DecodeUint())
	}
	form := Other
	n := -1
	if arg := d.Arg(argN); arg == nil {
		// Default to Other.
	} else if x, ok := arg.(Interface); ok {
		// This covers lists and formatters from the number package.
		form, n = x.PluralForm(lang, scale)
	} else {
		var f number.Formatter
		switch kind {
		case kindScale:
			f.InitDecimal(lang)
			f.SetScale(scale)
		case kindScientific:
			f.InitScientific(lang)
			f.SetScale(scale)
		case kindPrecision:
			f.InitDecimal(lang)
			f.SetPrecision(scale)
		case kindDefault:
			// sensible default
			f.InitDecimal(lang)
			if k := reflect.TypeOf(arg).Kind(); reflect.Int <= k && k <= reflect.Uintptr {
				f.SetScale(0)
			} else {
				f.SetScale(2)
			}
		}
		var dec number.Decimal // TODO: buffer in Printer
		dec.Convert(f.RoundingContext, arg)
		v := number.FormatDigits(&dec, f.RoundingContext)
		if !v.NaN && !v.Inf {
			form, n = cardinal.matchDisplayDigits(d.Language(), &v)
		}
	}
	for !d.Done() {
		f := d.DecodeUint()
		if (f == '=' && n == int(d.DecodeUint())) ||
			(f == '<' && 0 <= n && n < int(d.DecodeUint())) ||
			form == Form(f) ||
			Other == Form(f) {
			return d.ExecuteMessage()
		}
		d.SkipMessage()
	}
	return false
}
