package arg

import (
	
	
	
)

// the width of the left column
const colWidth = 25

// Fail prints usage information to p.Config.Out and exits with status code 2.
func ( *Parser) ( string) {
	.FailSubcommand()
}

// FailSubcommand prints usage information for a specified subcommand to p.Config.Out,
// then exits with status code 2. To write usage information for a top-level
// subcommand, provide just the name of that subcommand. To write usage
// information for a subcommand that is nested under another subcommand, provide
// a sequence of subcommand names starting with the top-level subcommand and so
// on down the tree.
func ( *Parser) ( string,  ...string) error {
	 := .WriteUsageForSubcommand(.config.Out, ...)
	if  != nil {
		return 
	}

	fmt.Fprintln(.config.Out, "error:", )
	.config.Exit(2)
	return nil
}

// WriteUsage writes usage information to the given writer
func ( *Parser) ( io.Writer) {
	.WriteUsageForSubcommand(, .subcommand...)
}

// WriteUsageForSubcommand writes the usage information for a specified
// subcommand. To write usage information for a top-level subcommand, provide
// just the name of that subcommand. To write usage information for a subcommand
// that is nested under another subcommand, provide a sequence of subcommand
// names starting with the top-level subcommand and so on down the tree.
func ( *Parser) ( io.Writer,  ...string) error {
	,  := .lookupCommand(...)
	if  != nil {
		return 
	}

	var , ,  []*spec
	for ,  := range .specs {
		switch {
		case .positional:
			 = append(, )
		case .long != "":
			 = append(, )
		case .short != "":
			 = append(, )
		}
	}

	// print the beginning of the usage string
	fmt.Fprintf(, "Usage: %s", .cmd.name)
	for ,  := range  {
		fmt.Fprint(, " "+)
	}

	// write the option component of the usage message
	for ,  := range  {
		// prefix with a space
		fmt.Fprint(, " ")
		if !.required {
			fmt.Fprint(, "[")
		}
		fmt.Fprint(, synopsis(, "-"+.short))
		if !.required {
			fmt.Fprint(, "]")
		}
	}

	for ,  := range  {
		// prefix with a space
		fmt.Fprint(, " ")
		if !.required {
			fmt.Fprint(, "[")
		}
		fmt.Fprint(, synopsis(, "--"+.long))
		if !.required {
			fmt.Fprint(, "]")
		}
	}

	// When we parse positionals, we check that:
	//  1. required positionals come before non-required positionals
	//  2. there is at most one multiple-value positional
	//  3. if there is a multiple-value positional then it comes after all other positionals
	// Here we merely print the usage string, so we do not explicitly re-enforce those rules

	// write the positionals in following form:
	//    REQUIRED1 REQUIRED2
	//    REQUIRED1 REQUIRED2 [OPTIONAL1 [OPTIONAL2]]
	//    REQUIRED1 REQUIRED2 REPEATED [REPEATED ...]
	//    REQUIRED1 REQUIRED2 [REPEATEDOPTIONAL [REPEATEDOPTIONAL ...]]
	//    REQUIRED1 REQUIRED2 [OPTIONAL1 [REPEATEDOPTIONAL [REPEATEDOPTIONAL ...]]]
	var  int
	for ,  := range  {
		fmt.Fprint(, " ")
		if !.required {
			fmt.Fprint(, "[")
			 += 1
		}
		if .cardinality == multiple {
			fmt.Fprintf(, "%s [%s ...]", .placeholder, .placeholder)
		} else {
			fmt.Fprint(, .placeholder)
		}
	}
	fmt.Fprint(, strings.Repeat("]", ))

	// if the program supports subcommands, give a hint to the user about their existence
	if len(.subcommands) > 0 {
		fmt.Fprint(, " <command> [<args>]")
	}

	fmt.Fprint(, "\n")
	return nil
}

// print prints a line like this:
//
//	--option FOO            A description of the option [default: 123]
//
// If the text on the left is longer than a certain threshold, the description is moved to the next line:
//
//	--verylongoptionoption VERY_LONG_VARIABLE
//	                        A description of the option [default: 123]
//
// If multiple "extras" are provided then they are put inside a single set of square brackets:
//
//	--option FOO            A description of the option [default: 123, env: FOO]
func print( io.Writer, ,  string,  ...string) {
	 := "  " + 
	fmt.Fprint(, )
	if  != "" {
		if len()+2 < colWidth {
			fmt.Fprint(, strings.Repeat(" ", colWidth-len()))
		} else {
			fmt.Fprint(, "\n"+strings.Repeat(" ", colWidth))
		}
		fmt.Fprint(, )
	}

	var  string
	for ,  := range  {
		if  != "" {
			if  != "" {
				 += ", "
			}
			 += 
		}
	}

	if  != "" {
		fmt.Fprintf(, " [%s]", )
	}
	fmt.Fprint(, "\n")
}

func withDefault( string) string {
	if  == "" {
		return ""
	}
	return "default: " + 
}

func withEnv( string) string {
	if  == "" {
		return ""
	}
	return "env: " + 
}

// WriteHelp writes the usage string followed by the full help string for each option
func ( *Parser) ( io.Writer) {
	.WriteHelpForSubcommand(, .subcommand...)
}

// WriteHelpForSubcommand writes the usage string followed by the full help
// string for a specified subcommand. To write help for a top-level subcommand,
// provide just the name of that subcommand. To write help for a subcommand that
// is nested under another subcommand, provide a sequence of subcommand names
// starting with the top-level subcommand and so on down the tree.
func ( *Parser) ( io.Writer,  ...string) error {
	,  := .lookupCommand(...)
	if  != nil {
		return 
	}

	var , , ,  []*spec
	var  bool
	for ,  := range .specs {
		switch {
		case .positional:
			 = append(, )
		case .long != "":
			 = append(, )
			if .long == "version" {
				 = true
			}
		case .short != "":
			 = append(, )
		case .short == "" && .long == "":
			 = append(, )
		}
	}

	// obtain a flattened list of options from all ancestors
	// also determine if any ancestor has a version option spec
	var  []*spec
	 := .parent
	for  != nil {
		for ,  := range .specs {
			if .long == "version" {
				 = true
				break
			}
		}
		 = append(, .specs...)
		 = .parent
	}

	if .description != "" {
		fmt.Fprintln(, .description)
	}

	if ! && .version != "" {
		fmt.Fprintln(, .version)
	}

	.WriteUsageForSubcommand(, ...)

	// write the list of positionals
	if len() > 0 {
		fmt.Fprint(, "\nPositional arguments:\n")
		for ,  := range  {
			print(, .placeholder, .help, withDefault(.defaultString), withEnv(.env))
		}
	}

	// write the list of options with the short-only ones first to match the usage string
	if len()+len() > 0 || .parent == nil {
		fmt.Fprint(, "\nOptions:\n")
		for ,  := range  {
			.printOption(, )
		}
		for ,  := range  {
			.printOption(, )
		}
	}

	// write the list of global options
	if len() > 0 {
		fmt.Fprint(, "\nGlobal options:\n")
		for ,  := range  {
			.printOption(, )
		}
	}

	// write the list of built in options
	.printOption(, &spec{
		cardinality: zero,
		long:        "help",
		short:       "h",
		help:        "display this help and exit",
	})
	if ! && .version != "" {
		.printOption(, &spec{
			cardinality: zero,
			long:        "version",
			help:        "display version and exit",
		})
	}

	// write the list of environment only variables
	if len() > 0 {
		fmt.Fprint(, "\nEnvironment variables:\n")
		for ,  := range  {
			.printEnvOnlyVar(, )
		}
	}

	// write the list of subcommands
	if len(.subcommands) > 0 {
		fmt.Fprint(, "\nCommands:\n")
		for ,  := range .subcommands {
			 := append([]string{.name}, .aliases...)
			print(, strings.Join(, ", "), .help)
		}
	}

	if .epilogue != "" {
		fmt.Fprintln(, "\n"+.epilogue)
	}
	return nil
}

func ( *Parser) ( io.Writer,  *spec) {
	 := make([]string, 0, 2)
	if .long != "" {
		 = append(, synopsis(, "--"+.long))
	}
	if .short != "" {
		 = append(, synopsis(, "-"+.short))
	}
	if len() > 0 {
		print(, strings.Join(, ", "), .help, withDefault(.defaultString), withEnv(.env))
	}
}

func ( *Parser) ( io.Writer,  *spec) {
	 := make([]string, 0, 2)
	if .required {
		 = append(, "Required.")
	} else {
		 = append(, "Optional.")
	}

	if .help != "" {
		 = append(, .help)
	}

	print(, .env, strings.Join(, " "), withDefault(.defaultString))
}

func synopsis( *spec,  string) string {
	// if the user omits the placeholder tag then we pick one automatically,
	// but if the user explicitly specifies an empty placeholder then we
	// leave out the placeholder in the help message
	if .cardinality == zero || .placeholder == "" {
		return 
	}
	return  + " " + .placeholder
}