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

	
	
	
	
)

// TODO: consider deleting this interface. Maybe VisibleDigits is always
// sufficient and practical.

// 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 ( int,  string,  ...interface{}) catalog.Message {
	var  parser
	// Intercept the formatting parameters of format by doing a dummy print.
	fmt.Fprintf(io.Discard, , &)
	 := &message{, kindDefault, 0, }
	switch .verb {
	case 'g':
		.kind = kindPrecision
		.scale = .scale
	case 'f':
		.kind = kindScale
		.scale = .scale
	case 'e':
		.kind = kindScientific
		.scale = .scale
	case 'd':
		.kind = kindScale
		.scale = 0
	default:
		// TODO: do we need to handle errors?
	}
	return 
}

type parser struct {
	verb  rune
	scale int
}

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

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 ( *message) ( *catmsg.Encoder) error {
	.EncodeMessageType(handle)

	.EncodeUint(uint64(.arg))

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

	 := validForms(cardinal, .Language())

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

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

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

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