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

import (
	
	

	
)

// TODO:
// - grouping of fractions
// - allow user-defined superscript notation (such as <sup>4</sup>)
// - same for non-breaking spaces, like &nbsp;

// A VisibleDigits computes digits, comma placement and trailing zeros as they
// will be shown to the user.
type VisibleDigits interface {
	Digits(buf []byte, t language.Tag, scale int) Digits
	// TODO: Do we also need to add the verb or pass a format.State?
}

// Formatting proceeds along the following lines:
// 0) Compose rounding information from format and context.
// 1) Convert a number into a Decimal.
// 2) Sanitize Decimal by adding trailing zeros, removing leading digits, and
//    (non-increment) rounding. The Decimal that results from this is suitable
//    for determining the plural form.
// 3) Render the Decimal in the localized form.

// Formatter contains all the information needed to render a number.
type Formatter struct {
	Pattern
	Info
}

func ( *Formatter) ( language.Tag,  []uint8) {
	.Info = InfoFromTag()
	.Pattern = formats[[tagToID()]]
}

// InitPattern initializes a Formatter for the given Pattern.
func ( *Formatter) ( language.Tag,  *Pattern) {
	.Info = InfoFromTag()
	.Pattern = *
}

// InitDecimal initializes a Formatter using the default Pattern for the given
// language.
func ( *Formatter) ( language.Tag) {
	.init(, tagToDecimal)
}

// InitScientific initializes a Formatter using the default Pattern for the
// given language.
func ( *Formatter) ( language.Tag) {
	.init(, tagToScientific)
	.Pattern.MinFractionDigits = 0
	.Pattern.MaxFractionDigits = -1
}

// InitEngineering initializes a Formatter using the default Pattern for the
// given language.
func ( *Formatter) ( language.Tag) {
	.init(, tagToScientific)
	.Pattern.MinFractionDigits = 0
	.Pattern.MaxFractionDigits = -1
	.Pattern.MaxIntegerDigits = 3
	.Pattern.MinIntegerDigits = 1
}

// InitPercent initializes a Formatter using the default Pattern for the given
// language.
func ( *Formatter) ( language.Tag) {
	.init(, tagToPercent)
}

// InitPerMille initializes a Formatter using the default Pattern for the given
// language.
func ( *Formatter) ( language.Tag) {
	.init(, tagToPercent)
	.Pattern.DigitShift = 3
}

func ( *Formatter) ( []byte,  interface{}) []byte {
	var  Decimal
	 := .RoundingContext
	.Convert(, )
	return .Render(, FormatDigits(&, ))
}

func ( *Decimal,  RoundingContext) Digits {
	if .isScientific() {
		return scientificVisibleDigits(, )
	}
	return decimalVisibleDigits(, )
}

func ( *Formatter) ( []byte,  *Decimal) []byte {
	return .Render(, FormatDigits(, .RoundingContext))
}

func ( *Formatter) ( []byte,  Digits) []byte {
	var  []byte
	var ,  int
	if .IsScientific {
		, ,  = appendScientific(, , &)
	} else {
		, ,  = appendDecimal(, , &)
	}
	if .PadRune == 0 {
		return 
	}
	 := int(.FormatWidth)
	if  := utf8.RuneCount();  <  {
		 := 0
		switch .Flags & PadMask {
		case PadAfterPrefix:
			 = 
		case PadBeforeSuffix:
			 = 
		case PadAfterSuffix:
			 = len()
		}
		 :=  - 
		 := [utf8.UTFMax]byte{' '}
		 := 1
		if  := .PadRune;  != 0 {
			 = utf8.EncodeRune([:], )
		}
		 :=  * 
		if  := len() + ;  < cap() {
			 = [:]
			copy([+:], [:])
		} else {
			 := make([]byte, )
			copy(, [:])
			copy([+:], [:])
			 = 
		}
		for ;  > 0; -- {
			 += copy([:], [:])
		}
	}
	return 
}

// decimalVisibleDigits converts d according to the RoundingContext. Note that
// the exponent may change as a result of this operation.
func decimalVisibleDigits( RoundingContext,  *Decimal) Digits {
	if .NaN || .Inf {
		return Digits{digits: digits{Neg: .Neg, NaN: .NaN, Inf: .Inf}}
	}
	 := Digits{digits: .normalize().digits}

	 := .Exp
	 += int32(.DigitShift)

	// Cap integer digits. Remove *most-significant* digits.
	if .MaxIntegerDigits > 0 {
		if  := int() - int(.MaxIntegerDigits);  > 0 {
			if  > len(.Digits) {
				 = len(.Digits)
			}
			if .Digits = .Digits[:]; len(.Digits) == 0 {
				 = 0
			} else {
				 -= int32()
			}
			// Strip leading zeros.
			for len(.Digits) > 0 && .Digits[0] == 0 {
				.Digits = .Digits[1:]
				--
			}
		}
	}

	// Rounding if not already done by Convert.
	 := len(.Digits)
	if  := int(.MaxSignificantDigits);  > 0 {
		 = 
	}
	if  := int(.MaxFractionDigits);  >= 0 {
		if  := int() + ;  <  {
			 = int() + 
		}
		if  < 0 {
			 = 0
		}
	}
	.round(.Mode, )

	// set End (trailing zeros)
	.End = int32(len(.Digits))
	if .End == 0 {
		 = 0
		if .MinFractionDigits > 0 {
			.End = int32(.MinFractionDigits)
		}
		if  := int32(.MinSignificantDigits) - 1;  > .End {
			.End = 
		}
	} else {
		if  :=  + int32(.MinFractionDigits);  > .End {
			.End = 
		}
		if .End < int32(.MinSignificantDigits) {
			.End = int32(.MinSignificantDigits)
		}
	}
	.Exp = 
	return 
}

// appendDecimal appends a formatted number to dst. It returns two possible
// insertion points for padding.
func appendDecimal( []byte,  *Formatter,  *Digits) ( []byte, ,  int) {
	if ,  := .renderSpecial(, );  {
		return , 0, len()
	}
	 := .Digits
	 := .Exp

	// Split in integer and fraction part.
	var ,  []byte
	 := 0
	 := int(.End - .Exp)
	if  > 0 {
		 = int()
		if int() >= len() { // ddddd | ddddd00
			 = 
		} else { // ddd.dd
			 = [:]
			 = [:]
		}
	} else {
		 = 
	}

	 := .Neg
	,  := .getAffixes()
	 = appendAffix(, , , )
	 := len()

	 := int(.MinIntegerDigits)
	if  == 0 && .MinSignificantDigits > 0 {
		 = 1
	}
	// add leading zeros
	for  := ;  > ; -- {
		 = .AppendDigit(, 0)
		if .needsSep() {
			 = append(, .Symbol(SymGroup)...)
		}
	}
	 := 0
	for ;  < len(); ++ {
		 = .AppendDigit(, [])
		if .needsSep( - ) {
			 = append(, .Symbol(SymGroup)...)
		}
	}
	for ;  < ; ++ {
		 = .AppendDigit(, 0)
		if .needsSep( - ) {
			 = append(, .Symbol(SymGroup)...)
		}
	}

	if  > 0 || .Flags&AlwaysDecimalSeparator != 0 {
		 = append(, .Symbol(SymDecimal)...)
	}
	// Add trailing zeros
	 = 0
	for  := -int(.Exp);  < ; ++ {
		 = .AppendDigit(, 0)
	}
	for ,  := range  {
		++
		 = .AppendDigit(, )
	}
	for ;  < ; ++ {
		 = .AppendDigit(, 0)
	}
	return appendAffix(, , , ), , len()
}

func scientificVisibleDigits( RoundingContext,  *Decimal) Digits {
	if .NaN || .Inf {
		return Digits{digits: digits{Neg: .Neg, NaN: .NaN, Inf: .Inf}}
	}
	 := Digits{digits: .normalize().digits, IsScientific: true}

	// Normalize to have at least one digit. This simplifies engineering
	// notation.
	if len(.Digits) == 0 {
		.Digits = append(.Digits, 0)
		.Exp = 1
	}

	// Significant digits are transformed by the parser for scientific notation
	// and do not need to be handled here.
	,  := int(.MaxIntegerDigits), int(.MinIntegerDigits)
	if  == 0 {
		 = 1
	}

	// If a maximum number of integers is specified, the minimum must be 1
	// and the exponent is grouped by this number (e.g. for engineering)
	if  >  {
		// Correct the exponent to reflect a single integer digit.
		 = 1
		// engineering
		// 0.01234 ([12345]e-1) -> 1.2345e-2  12.345e-3
		// 12345   ([12345]e+5) -> 1.2345e4  12.345e3
		 := int(.Exp-1) % 
		if  < 0 {
			 += 
		}
		 += 
	}

	 := len(.Digits)
	if  := int(.MaxSignificantDigits);  > 0 {
		 = 
	}
	if  := int(.MaxFractionDigits);  >= 0 && + <  {
		 =  + 
	}
	.round(.Mode, )

	.Comma = uint8()
	.End = int32(len(.Digits))
	if  := int32(.MinFractionDigits) + int32(); .End <  {
		.End = 
	}
	return 
}

// appendScientific appends a formatted number to dst. It returns two possible
// insertion points for padding.
func appendScientific( []byte,  *Formatter,  *Digits) ( []byte, ,  int) {
	if ,  := .renderSpecial(, );  {
		return , 0, 0
	}
	 := .Digits
	 := int(.Comma)
	 := int(.End) - int(.Comma)

	var ,  []byte
	if  <= len() {
		 = [:]
		 = [:]
	} else {
		 = 
	}
	 := .Neg
	,  := .getAffixes()
	 = appendAffix(, , , )
	 := len()

	 := 0
	for ;  < len(); ++ {
		 = .AppendDigit(, [])
		if .needsSep( - ) {
			 = append(, .Symbol(SymGroup)...)
		}
	}
	for ;  < ; ++ {
		 = .AppendDigit(, 0)
		if .needsSep( - ) {
			 = append(, .Symbol(SymGroup)...)
		}
	}

	if  > 0 || .Flags&AlwaysDecimalSeparator != 0 {
		 = append(, .Symbol(SymDecimal)...)
	}
	 = 0
	for ;  < len(); ++ {
		 = .AppendDigit(, [])
	}
	for ;  < ; ++ {
		 = .AppendDigit(, 0)
	}

	// exp
	 := [12]byte{}
	// TODO: use exponential if superscripting is not available (no Latin
	// numbers or no tags) and use exponential in all other cases.
	 := .Exp - int32(.Comma)
	 := .Symbol(SymExponential)
	if  == "E" {
		 = append(, .Symbol(SymSuperscriptingExponent)...)
		 = .AppendDigit(, 1)
		 = .AppendDigit(, 0)
		switch {
		case  < 0:
			 = append(, superMinus...)
			 = -
		case .Flags&AlwaysExpSign != 0:
			 = append(, superPlus...)
		}
		 = strconv.AppendUint([:0], uint64(), 10)
		for  := len();  < int(.MinExponentDigits); ++ {
			 = append(, superDigits[0]...)
		}
		for ,  := range  {
			 = append(, superDigits[-'0']...)
		}
	} else {
		 = append(, ...)
		switch {
		case  < 0:
			 = append(, .Symbol(SymMinusSign)...)
			 = -
		case .Flags&AlwaysExpSign != 0:
			 = append(, .Symbol(SymPlusSign)...)
		}
		 = strconv.AppendUint([:0], uint64(), 10)
		for  := len();  < int(.MinExponentDigits); ++ {
			 = .AppendDigit(, 0)
		}
		for ,  := range  {
			 = .AppendDigit(, -'0')
		}
	}
	return appendAffix(, , , ), , len()
}

const (
	superMinus = "\u207B" // SUPERSCRIPT HYPHEN-MINUS
	superPlus  = "\u207A" // SUPERSCRIPT PLUS SIGN
)

var (
	// Note: the digits are not sequential!!!
	superDigits = []string{
		"\u2070", // SUPERSCRIPT DIGIT ZERO
		"\u00B9", // SUPERSCRIPT DIGIT ONE
		"\u00B2", // SUPERSCRIPT DIGIT TWO
		"\u00B3", // SUPERSCRIPT DIGIT THREE
		"\u2074", // SUPERSCRIPT DIGIT FOUR
		"\u2075", // SUPERSCRIPT DIGIT FIVE
		"\u2076", // SUPERSCRIPT DIGIT SIX
		"\u2077", // SUPERSCRIPT DIGIT SEVEN
		"\u2078", // SUPERSCRIPT DIGIT EIGHT
		"\u2079", // SUPERSCRIPT DIGIT NINE
	}
)

func ( *Formatter) ( bool) (,  string) {
	 := .Affix
	if  != "" {
		if .NegOffset > 0 {
			if  {
				 = [.NegOffset:]
			} else {
				 = [:.NegOffset]
			}
		}
		 := 1 + [0]
		 = [1:]
		 = [+1:]
	}
	// TODO: introduce a NeedNeg sign to indicate if the left pattern already
	// has a sign marked?
	if .NegOffset == 0 && ( || .Flags&AlwaysSign != 0) {
		 = "-" + 
	}
	return , 
}

func ( *Formatter) ( []byte,  *Digits) ( []byte,  bool) {
	if .NaN {
		return fmtNaN(, ), true
	}
	if .Inf {
		return fmtInfinite(, , ), true
	}
	return , false
}

func fmtNaN( []byte,  *Formatter) []byte {
	return append(, .Symbol(SymNan)...)
}

func fmtInfinite( []byte,  *Formatter,  *Digits) []byte {
	,  := .getAffixes(.Neg)
	 = appendAffix(, , , .Neg)
	 = append(, .Symbol(SymInfinity)...)
	 = appendAffix(, , , .Neg)
	return 
}

func appendAffix( []byte,  *Formatter,  string,  bool) []byte {
	 := false
	 := false
	for ,  := range  {
		switch {
		case :
			// escaping occurs both inside and outside of quotes
			 = append(, string()...)
			 = false
		case  == '\\':
			 = true
		case  == '\'':
			 = !
		case :
			 = append(, string()...)
		case  == '%':
			if .DigitShift == 3 {
				 = append(, .Symbol(SymPerMille)...)
			} else {
				 = append(, .Symbol(SymPercentSign)...)
			}
		case  == '-' ||  == '+':
			if  {
				 = append(, .Symbol(SymMinusSign)...)
			} else if .Flags&ElideSign == 0 {
				 = append(, .Symbol(SymPlusSign)...)
			} else {
				 = append(, ' ')
			}
		default:
			 = append(, string()...)
		}
	}
	return 
}