package carapace

import (
	
	
	
	
	

	
	
	
	
	
	
)

// Context provides information during completion.
type Context struct {
	// Value contains the value currently being completed (or part of it during an ActionMultiParts).
	Value string
	// Args contains the positional arguments of current (sub)command (exclusive the one currently being completed).
	Args []string
	// Parts contains the splitted Value during an ActionMultiParts (exclusive the part currently being completed).
	Parts []string
	// Env contains environment variables for current context.
	Env []string
	// Dir contains the working directory for current context.
	Dir string

	mockedReplies map[string]string
	cmd           *cobra.Command // needed for ActionCobra
}

// NewContext creates a new context for given arguments.
func ( ...string) Context {
	if len() == 0 {
		 = append(, "")
	}

	 := Context{
		Value: [len()-1],
		Args:  [:len()-1],
		Env:   os.Environ(),
	}

	if ,  := os.Getwd();  == nil {
		.Dir = 
	}

	if ,  := env.Sandbox();  == nil {
		.Dir = .WorkDir()
		.mockedReplies = .Replies
	}
	return 
}

// LookupEnv retrieves the value of the environment variable named by the key.
func ( Context) ( string) (string, bool) {
	 :=  + "="
	for  := len(.Env) - 1;  >= 0; -- {
		if  := .Env[]; strings.HasPrefix(, ) {
			return strings.SplitN(, "=", 2)[1], true
		}
	}
	return "", false
}

// Getenv retrieves the value of the environment variable named by the key.
func ( Context) ( string) string {
	,  := .LookupEnv()
	return 
}

// Setenv sets the value of the environment variable named by the key.
func ( *Context) (,  string) {
	if .Env == nil {
		.Env = []string{}
	}
	.Env = append(.Env, fmt.Sprintf("%v=%v", , ))
}

// Envsubst replaces ${var} in the string based on environment variables in current context.
func ( Context) ( string) (string, error) {
	return envsubst.Eval(, .Getenv)
}

// Command returns the Cmd struct to execute the named program with the given arguments.
// Env and Dir are set using the Context.
// See exec.Command for most details.
func ( Context) ( string,  ...string) *execlog.Cmd {
	if .mockedReplies != nil {
		if ,  := json.Marshal(append([]string{}, ...));  == nil {
			if ,  := .mockedReplies[string()];  {
				return execlog.Command("echo", ) // TODO use mock
			}
		}
	}

	 := execlog.Command(, ...)
	.Env = .Env
	.Dir = .Dir
	return 
}

func expandHome( string) (string, error) {
	if strings.HasPrefix(, "~") {
		if zsh.NamedDirectories.Matches() {
			return zsh.NamedDirectories.Replace(), nil
		}

		,  := os.UserHomeDir()
		if  != nil {
			return "", 
		}
		 = filepath.ToSlash()
		switch  {
		case "~":
			 = 
		default:
			 = strings.Replace(, "~/", +"/", 1)
		}
	}
	return , nil
}

// Abs returns an absolute representation of path.
func ( Context) ( string) (string, error) {
	 = filepath.ToSlash()
	if !strings.HasPrefix(, "/") && !strings.HasPrefix(, "~") && !util.HasVolumePrefix() { // path is relative
		switch .Dir {
		case "":
			 = "./" + 
		default:
			 = .Dir + "/" + 
		}
	}

	,  := expandHome()
	if  != nil {
		return "", 
	}

	if len() == 2 && util.HasVolumePrefix() {
		 += "/" // prevent `C:` -> `C:./current/working/directory`
	}
	,  := filepath.Abs()
	if  != nil {
		return "", 
	}
	 = filepath.ToSlash()

	if strings.HasSuffix(, "/") && !strings.HasSuffix(, "/") {
		 += "/"
	} else if strings.HasSuffix(, "/.") && !strings.HasSuffix(, "/.") {
		 += "/."
	}
	return , nil
}