// Copyright 2015 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 message // import "golang.org/x/text/message"

import (
	
	

	// Include features to facilitate generated catalogs.
	_ 

	
	
	
)

// A Printer implements language-specific formatted I/O analogous to the fmt
// package.
type Printer struct {
	// the language
	tag language.Tag

	toDecimal    number.Formatter
	toScientific number.Formatter

	cat catalog.Catalog
}

type options struct {
	cat catalog.Catalog
	// TODO:
	// - allow %s to print integers in written form (tables are likely too large
	//   to enable this by default).
	// - list behavior
	//
}

// An Option defines an option of a Printer.
type Option func(o *options)

// Catalog defines the catalog to be used.
func ( catalog.Catalog) Option {
	return func( *options) { .cat =  }
}

// NewPrinter returns a Printer that formats messages tailored to language t.
func ( language.Tag,  ...Option) *Printer {
	 := &options{
		cat: DefaultCatalog,
	}
	for ,  := range  {
		()
	}
	 := &Printer{
		tag: ,
		cat: .cat,
	}
	.toDecimal.InitDecimal()
	.toScientific.InitScientific()
	return 
}

// Sprint is like fmt.Sprint, but using language-specific formatting.
func ( *Printer) ( ...interface{}) string {
	 := newPrinter()
	.doPrint()
	 := .String()
	.free()
	return 
}

// Fprint is like fmt.Fprint, but using language-specific formatting.
func ( *Printer) ( io.Writer,  ...interface{}) ( int,  error) {
	 := newPrinter()
	.doPrint()
	,  := io.Copy(, &.Buffer)
	.free()
	return int(), 
}

// Print is like fmt.Print, but using language-specific formatting.
func ( *Printer) ( ...interface{}) ( int,  error) {
	return .Fprint(os.Stdout, ...)
}

// Sprintln is like fmt.Sprintln, but using language-specific formatting.
func ( *Printer) ( ...interface{}) string {
	 := newPrinter()
	.doPrintln()
	 := .String()
	.free()
	return 
}

// Fprintln is like fmt.Fprintln, but using language-specific formatting.
func ( *Printer) ( io.Writer,  ...interface{}) ( int,  error) {
	 := newPrinter()
	.doPrintln()
	,  := io.Copy(, &.Buffer)
	.free()
	return int(), 
}

// Println is like fmt.Println, but using language-specific formatting.
func ( *Printer) ( ...interface{}) ( int,  error) {
	return .Fprintln(os.Stdout, ...)
}

// Sprintf is like fmt.Sprintf, but using language-specific formatting.
func ( *Printer) ( Reference,  ...interface{}) string {
	 := newPrinter()
	lookupAndFormat(, , )
	 := .String()
	.free()
	return 
}

// Fprintf is like fmt.Fprintf, but using language-specific formatting.
func ( *Printer) ( io.Writer,  Reference,  ...interface{}) ( int,  error) {
	 := newPrinter()
	lookupAndFormat(, , )
	,  = .Write(.Bytes())
	.free()
	return , 

}

// Printf is like fmt.Printf, but using language-specific formatting.
func ( *Printer) ( Reference,  ...interface{}) ( int,  error) {
	 := newPrinter()
	lookupAndFormat(, , )
	,  = os.Stdout.Write(.Bytes())
	.free()
	return , 
}

func lookupAndFormat( *printer,  Reference,  []interface{}) {
	.fmt.Reset()
	switch v := .(type) {
	case string:
		if .catContext.Execute() == catalog.ErrNotFound {
			.Render()
			return
		}
	case key:
		if .catContext.Execute(.id) == catalog.ErrNotFound &&
			.catContext.Execute(.fallback) == catalog.ErrNotFound {
			.Render(.fallback)
			return
		}
	default:
		panic("key argument is not a Reference")
	}
}

type rawPrinter struct {
	p *printer
}

func ( rawPrinter) ( string)     { .p.WriteString() }
func ( rawPrinter) ( int) interface{} { return nil }

// Arg implements catmsg.Renderer.
func ( *printer) ( int) interface{} { // TODO, also return "ok" bool
	--
	if uint() < uint(len(.fmt.Args)) {
		return .fmt.Args[]
	}
	return nil
}

// Render implements catmsg.Renderer.
func ( *printer) ( string) {
	.doPrintf()
}

// A Reference is a string or a message reference.
type Reference interface {
	// TODO: also allow []string
}

// Key creates a message Reference for a message where the given id is used for
// message lookup and the fallback is returned when no matches are found.
func ( string,  string) Reference {
	return key{, }
}

type key struct {
	id, fallback string
}