// Copyright 2013 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 language

import (
	
	
	
	

	
)

// ValueError is returned by any of the parsing functions when the
// input is well-formed but the respective subtag is not recognized
// as a valid value.
type ValueError interface {
	error

	// Subtag returns the subtag for which the error occurred.
	Subtag() string
}

// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
// failed it returns an error and any part of the tag that could be parsed.
// If parsing succeeded but an unknown value was found, it returns
// ValueError. The Tag returned in this case is just stripped of the unknown
// value. All other values are preserved. It accepts tags in the BCP 47 format
// and extensions to this standard defined in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// The resulting tag is canonicalized using the default canonicalization type.
func ( string) ( Tag,  error) {
	return Default.Parse()
}

// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
// failed it returns an error and any part of the tag that could be parsed.
// If parsing succeeded but an unknown value was found, it returns
// ValueError. The Tag returned in this case is just stripped of the unknown
// value. All other values are preserved. It accepts tags in the BCP 47 format
// and extensions to this standard defined in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// The resulting tag is canonicalized using the canonicalization type c.
func ( CanonType) ( string) ( Tag,  error) {
	defer func() {
		if recover() != nil {
			 = Tag{}
			 = language.ErrSyntax
		}
	}()

	,  := language.Parse()
	if  != nil {
		return makeTag(), 
	}
	,  := canonicalize(, )
	if  {
		.RemakeString()
	}
	return makeTag(), 
}

// Compose creates a Tag from individual parts, which may be of type Tag, Base,
// Script, Region, Variant, []Variant, Extension, []Extension or error. If a
// Base, Script or Region or slice of type Variant or Extension is passed more
// than once, the latter will overwrite the former. Variants and Extensions are
// accumulated, but if two extensions of the same type are passed, the latter
// will replace the former. For -u extensions, though, the key-type pairs are
// added, where later values overwrite older ones. A Tag overwrites all former
// values and typically only makes sense as the first argument. The resulting
// tag is returned after canonicalizing using the Default CanonType. If one or
// more errors are encountered, one of the errors is returned.
func ( ...interface{}) ( Tag,  error) {
	return Default.Compose(...)
}

// Compose creates a Tag from individual parts, which may be of type Tag, Base,
// Script, Region, Variant, []Variant, Extension, []Extension or error. If a
// Base, Script or Region or slice of type Variant or Extension is passed more
// than once, the latter will overwrite the former. Variants and Extensions are
// accumulated, but if two extensions of the same type are passed, the latter
// will replace the former. For -u extensions, though, the key-type pairs are
// added, where later values overwrite older ones. A Tag overwrites all former
// values and typically only makes sense as the first argument. The resulting
// tag is returned after canonicalizing using CanonType c. If one or more errors
// are encountered, one of the errors is returned.
func ( CanonType) ( ...interface{}) ( Tag,  error) {
	defer func() {
		if recover() != nil {
			 = Tag{}
			 = language.ErrSyntax
		}
	}()

	var  language.Builder
	if  = update(&, ...);  != nil {
		return und, 
	}
	.Tag, _ = canonicalize(, .Tag)
	return makeTag(.Make()), 
}

var errInvalidArgument = errors.New("invalid Extension or Variant")

func update( *language.Builder,  ...interface{}) ( error) {
	for ,  := range  {
		switch v := .(type) {
		case Tag:
			.SetTag(.tag())
		case Base:
			.Tag.LangID = .langID
		case Script:
			.Tag.ScriptID = .scriptID
		case Region:
			.Tag.RegionID = .regionID
		case Variant:
			if .variant == "" {
				 = errInvalidArgument
				break
			}
			.AddVariant(.variant)
		case Extension:
			if .s == "" {
				 = errInvalidArgument
				break
			}
			.SetExt(.s)
		case []Variant:
			.ClearVariants()
			for ,  := range  {
				.AddVariant(.variant)
			}
		case []Extension:
			.ClearExtensions()
			for ,  := range  {
				.SetExt(.s)
			}
		// TODO: support parsing of raw strings based on morphology or just extensions?
		case error:
			if  != nil {
				 = 
			}
		}
	}
	return
}

var errInvalidWeight = errors.New("ParseAcceptLanguage: invalid weight")
var errTagListTooLarge = errors.New("tag list exceeds max length")

// ParseAcceptLanguage parses the contents of an Accept-Language header as
// defined in http://www.ietf.org/rfc/rfc2616.txt and returns a list of Tags and
// a list of corresponding quality weights. It is more permissive than RFC 2616
// and may return non-nil slices even if the input is not valid.
// The Tags will be sorted by highest weight first and then by first occurrence.
// Tags with a weight of zero will be dropped. An error will be returned if the
// input could not be parsed.
func ( string) ( []Tag,  []float32,  error) {
	defer func() {
		if recover() != nil {
			 = nil
			 = nil
			 = language.ErrSyntax
		}
	}()

	if strings.Count(, "-") > 1000 {
		return nil, nil, errTagListTooLarge
	}

	var  string
	for  != "" {
		if ,  = split(, ',');  == "" {
			continue
		}

		,  := split(, ';')

		// Scan the language.
		,  := Parse()
		if  != nil {
			,  := acceptFallback[]
			if ! {
				return nil, nil, 
			}
			 = makeTag(language.Tag{LangID: })
		}

		// Scan the optional weight.
		 := 1.0
		if  != "" {
			 = consume(, 'q')
			 = consume(, '=')
			// consume returns the empty string when a token could not be
			// consumed, resulting in an error for ParseFloat.
			if ,  = strconv.ParseFloat(, 32);  != nil {
				return nil, nil, errInvalidWeight
			}
			// Drop tags with a quality weight of 0.
			if  <= 0 {
				continue
			}
		}

		 = append(, )
		 = append(, float32())
	}
	sort.Stable(&tagSort{, })
	return , , nil
}

// consume removes a leading token c from s and returns the result or the empty
// string if there is no such token.
func consume( string,  byte) string {
	if  == "" || [0] !=  {
		return ""
	}
	return strings.TrimSpace([1:])
}

func split( string,  byte) (,  string) {
	if  := strings.IndexByte(, );  >= 0 {
		return strings.TrimSpace([:]), strings.TrimSpace([+1:])
	}
	return strings.TrimSpace(), ""
}

// Add hack mapping to deal with a small number of cases that occur
// in Accept-Language (with reasonable frequency).
var acceptFallback = map[string]language.Language{
	"english": _en,
	"deutsch": _de,
	"italian": _it,
	"french":  _fr,
	"*":       _mul, // defined in the spec to match all languages.
}

type tagSort struct {
	tag []Tag
	q   []float32
}

func ( *tagSort) () int {
	return len(.q)
}

func ( *tagSort) (,  int) bool {
	return .q[] > .q[]
}

func ( *tagSort) (,  int) {
	.tag[], .tag[] = .tag[], .tag[]
	.q[], .q[] = .q[], .q[]
}