package carapace

import (
	
	
	

	
	

	
	
)

// TODO storage needs better naming and structure

type entry struct {
	flag          ActionMap
	flagMutex     sync.RWMutex
	positional    []Action
	positionalAny *Action
	dash          []Action
	dashAny       *Action
	preinvoke     func(cmd *cobra.Command, flag *pflag.Flag, action Action) Action
	prerun        func(cmd *cobra.Command, args []string)
	bridged       bool
	initialized   bool
}

type _storage map[*cobra.Command]*entry

var storageMutex sync.RWMutex

func ( _storage) ( *cobra.Command) *entry {
	storageMutex.RLock()
	,  := []
	storageMutex.RUnlock()

	if ! {
		storageMutex.Lock()
		defer storageMutex.Unlock()
		if ,  = []; ! {
			 = &entry{}
			[] = 
		}
	}
	return 
}

var bridgeMutex sync.Mutex

func ( _storage) ( *cobra.Command) {
	if  := storage.get(); !.bridged {
		bridgeMutex.Lock()
		defer bridgeMutex.Unlock()

		if  := storage.get(); !.bridged {
			cobra.OnInitialize(func() {
				if !.initialized {
					bridgeMutex.Lock()
					defer bridgeMutex.Unlock()

					if !.initialized {
						registerValidArgsFunction()
						registerFlagCompletion()
						.initialized = true
					}

				}
			})
			.bridged = true
		}
	}
}

func ( _storage) ( *cobra.Command,  string) bool {
	if  := .LocalFlags().Lookup();  == nil && .HasParent() {
		return .(.Parent(), )
	} else {
		 := .get()
		.flagMutex.RLock()
		defer .flagMutex.RUnlock()
		,  := .flag[]
		return 
	}
}

func ( _storage) ( *cobra.Command,  string) Action {
	if  := .LocalFlags().Lookup();  == nil && .HasParent() {
		return .(.Parent(), )
	} else {
		 := .get()
		.flagMutex.RLock()
		defer .flagMutex.RUnlock()

		,  := .flag[]
		if ! {
			if ,  := .GetFlagCompletionFunc();  {
				 = ActionCobra()
			}
		}

		 := .preinvoke(, , )

		return ActionCallback(func( Context) Action { // TODO verify order of execution is correct
			 := .Invoke()
			if .action.meta.Usage == "" {
				.action.meta.Usage = .Usage
			}
			return .ToA()
		})
	}
}

func ( _storage) ( *cobra.Command,  []string) {
	if  := .get(); .prerun != nil {
		LOG.Printf("executing PreRun for %#v with args %#v", .Name(), )
		.prerun(, )
	}
}

func ( _storage) ( *cobra.Command,  *pflag.Flag,  Action) Action {
	 := 
	if  := .get(); .preinvoke != nil {
		 = ActionCallback(func( Context) Action {
			return .preinvoke(, , )
		})
	}

	if .HasParent() {
		return .(.Parent(), , )
	}
	return 
}

func ( _storage) ( *cobra.Command,  int) bool {
	 := .get()
	 := common.IsDash()

	// TODO fallback to cobra defined completion if exists

	switch {
	case ! && len(.positional) > :
		return true
	case !:
		return .positionalAny != nil
	case len(.dash) > :
		return true
	default:
		return .dashAny != nil
	}
}

func ( _storage) ( *cobra.Command,  int) Action {
	 := .get()
	 := common.IsDash()

	var  Action
	switch {
	case ! && len(.positional) > :
		 = .positional[]
	case !:
		if .positionalAny != nil {
			 = *.positionalAny
		} else {
			 = ActionCobra(.ValidArgsFunction)
		}
	case len(.dash) > :
		 = .dash[]
	default:
		if .dashAny != nil {
			 = *.dashAny
		} else {
			 = ActionCobra(.ValidArgsFunction)
		}
	}
	 = .preinvoke(, nil, )

	return ActionCallback(func( Context) Action {
		 := .Invoke()
		if .action.meta.Usage == "" && len(strings.Fields(.Use)) > 1 {
			.action.meta.Usage = .Use
		}
		return .ToA()
	})
}

func ( _storage) () []string {
	 := make([]string, 0)
	for ,  := range  {
		func() {
			.flagMutex.RLock()
			defer .flagMutex.RUnlock()

			for  := range .flag {
				if  := .LocalFlags().Lookup();  == nil {
					 = append(, fmt.Sprintf("unknown flag for %s: %s\n", uid.Command(), ))
				}
			}
		}()
	}
	return 
}

var storage = make(_storage)