// Copyright 2013-2023 The Cobra Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cobra

import (
	
	
	

	flag 
)

const (
	requiredAsGroupAnnotation   = "cobra_annotation_required_if_others_set"
	oneRequiredAnnotation       = "cobra_annotation_one_required"
	mutuallyExclusiveAnnotation = "cobra_annotation_mutually_exclusive"
)

// MarkFlagsRequiredTogether marks the given flags with annotations so that Cobra errors
// if the command is invoked with a subset (but not all) of the given flags.
func ( *Command) ( ...string) {
	.mergePersistentFlags()
	for ,  := range  {
		 := .Flags().Lookup()
		if  == nil {
			panic(fmt.Sprintf("Failed to find flag %q and mark it as being required in a flag group", ))
		}
		if  := .Flags().SetAnnotation(, requiredAsGroupAnnotation, append(.Annotations[requiredAsGroupAnnotation], strings.Join(, " ")));  != nil {
			// Only errs if the flag isn't found.
			panic()
		}
	}
}

// MarkFlagsOneRequired marks the given flags with annotations so that Cobra errors
// if the command is invoked without at least one flag from the given set of flags.
func ( *Command) ( ...string) {
	.mergePersistentFlags()
	for ,  := range  {
		 := .Flags().Lookup()
		if  == nil {
			panic(fmt.Sprintf("Failed to find flag %q and mark it as being in a one-required flag group", ))
		}
		if  := .Flags().SetAnnotation(, oneRequiredAnnotation, append(.Annotations[oneRequiredAnnotation], strings.Join(, " ")));  != nil {
			// Only errs if the flag isn't found.
			panic()
		}
	}
}

// MarkFlagsMutuallyExclusive marks the given flags with annotations so that Cobra errors
// if the command is invoked with more than one flag from the given set of flags.
func ( *Command) ( ...string) {
	.mergePersistentFlags()
	for ,  := range  {
		 := .Flags().Lookup()
		if  == nil {
			panic(fmt.Sprintf("Failed to find flag %q and mark it as being in a mutually exclusive flag group", ))
		}
		// Each time this is called is a single new entry; this allows it to be a member of multiple groups if needed.
		if  := .Flags().SetAnnotation(, mutuallyExclusiveAnnotation, append(.Annotations[mutuallyExclusiveAnnotation], strings.Join(, " ")));  != nil {
			panic()
		}
	}
}

// ValidateFlagGroups validates the mutuallyExclusive/oneRequired/requiredAsGroup logic and returns the
// first error encountered.
func ( *Command) () error {
	if .DisableFlagParsing {
		return nil
	}

	 := .Flags()

	// groupStatus format is the list of flags as a unique ID,
	// then a map of each flag name and whether it is set or not.
	 := map[string]map[string]bool{}
	 := map[string]map[string]bool{}
	 := map[string]map[string]bool{}
	.VisitAll(func( *flag.Flag) {
		processFlagForGroupAnnotation(, , requiredAsGroupAnnotation, )
		processFlagForGroupAnnotation(, , oneRequiredAnnotation, )
		processFlagForGroupAnnotation(, , mutuallyExclusiveAnnotation, )
	})

	if  := validateRequiredFlagGroups();  != nil {
		return 
	}
	if  := validateOneRequiredFlagGroups();  != nil {
		return 
	}
	if  := validateExclusiveFlagGroups();  != nil {
		return 
	}
	return nil
}

func hasAllFlags( *flag.FlagSet,  ...string) bool {
	for ,  := range  {
		 := .Lookup()
		if  == nil {
			return false
		}
	}
	return true
}

func processFlagForGroupAnnotation( *flag.FlagSet,  *flag.Flag,  string,  map[string]map[string]bool) {
	,  := .Annotations[]
	if  {
		for ,  := range  {
			if [] == nil {
				 := strings.Split(, " ")

				// Only consider this flag group at all if all the flags are defined.
				if !hasAllFlags(, ...) {
					continue
				}

				[] = make(map[string]bool, len())
				for ,  := range  {
					[][] = false
				}
			}

			[][.Name] = .Changed
		}
	}
}

func validateRequiredFlagGroups( map[string]map[string]bool) error {
	 := sortedKeys()
	for ,  := range  {
		 := []

		 := []string{}
		for ,  := range  {
			if ! {
				 = append(, )
			}
		}
		if len() == len() || len() == 0 {
			continue
		}

		// Sort values, so they can be tested/scripted against consistently.
		sort.Strings()
		return fmt.Errorf("if any flags in the group [%v] are set they must all be set; missing %v", , )
	}

	return nil
}

func validateOneRequiredFlagGroups( map[string]map[string]bool) error {
	 := sortedKeys()
	for ,  := range  {
		 := []
		var  []string
		for ,  := range  {
			if  {
				 = append(, )
			}
		}
		if len() >= 1 {
			continue
		}

		// Sort values, so they can be tested/scripted against consistently.
		sort.Strings()
		return fmt.Errorf("at least one of the flags in the group [%v] is required", )
	}
	return nil
}

func validateExclusiveFlagGroups( map[string]map[string]bool) error {
	 := sortedKeys()
	for ,  := range  {
		 := []
		var  []string
		for ,  := range  {
			if  {
				 = append(, )
			}
		}
		if len() == 0 || len() == 1 {
			continue
		}

		// Sort values, so they can be tested/scripted against consistently.
		sort.Strings()
		return fmt.Errorf("if any flags in the group [%v] are set none of the others can be; %v were all set", , )
	}
	return nil
}

func sortedKeys( map[string]map[string]bool) []string {
	 := make([]string, len())
	 := 0
	for  := range  {
		[] = 
		++
	}
	sort.Strings()
	return 
}

// enforceFlagGroupsForCompletion will do the following:
// - when a flag in a group is present, other flags in the group will be marked required
// - when none of the flags in a one-required group are present, all flags in the group will be marked required
// - when a flag in a mutually exclusive group is present, other flags in the group will be marked as hidden
// This allows the standard completion logic to behave appropriately for flag groups
func ( *Command) () {
	if .DisableFlagParsing {
		return
	}

	 := .Flags()
	 := map[string]map[string]bool{}
	 := map[string]map[string]bool{}
	 := map[string]map[string]bool{}
	.Flags().VisitAll(func( *flag.Flag) {
		processFlagForGroupAnnotation(, , requiredAsGroupAnnotation, )
		processFlagForGroupAnnotation(, , oneRequiredAnnotation, )
		processFlagForGroupAnnotation(, , mutuallyExclusiveAnnotation, )
	})

	// If a flag that is part of a group is present, we make all the other flags
	// of that group required so that the shell completion suggests them automatically
	for ,  := range  {
		for ,  := range  {
			if  {
				// One of the flags of the group is set, mark the other ones as required
				for ,  := range strings.Split(, " ") {
					_ = .MarkFlagRequired()
				}
			}
		}
	}

	// If none of the flags of a one-required group are present, we make all the flags
	// of that group required so that the shell completion suggests them automatically
	for ,  := range  {
		 := false

		for _,  = range  {
			if  {
				break
			}
		}

		// None of the flags of the group are set, mark all flags in the group
		// as required
		if ! {
			for ,  := range strings.Split(, " ") {
				_ = .MarkFlagRequired()
			}
		}
	}

	// If a flag that is mutually exclusive to others is present, we hide the other
	// flags of that group so the shell completion does not suggest them
	for ,  := range  {
		for ,  := range  {
			if  {
				// One of the flags of the mutually exclusive group is set, mark the other ones as hidden
				// Don't mark the flag that is already set as hidden because it may be an
				// array or slice flag and therefore must continue being suggested
				for ,  := range strings.Split(, " ") {
					if  !=  {
						 := .Flags().Lookup()
						.Hidden = true
					}
				}
			}
		}
	}
}