package complete

import (
	

	
	
	
)

var parent = parse.Parent

var completers = []completer{
	completeCommand,
	completeIndex,
	completeRedir,
	completeVariable,
	completeArg,
}

type completer func(parse.Node, Config) (*context, []RawItem, error)

type context struct {
	name     string
	seed     string
	quote    parse.PrimaryType
	interval diag.Ranging
}

func ( parse.Node,  Config) (*context, []RawItem, error) {
	 := .PureEvaler
	if ,  := .(*parse.Sep);  {
		if ,  := parent().(*parse.Form);  && .Head != nil {
			// Case 1: starting a new argument.
			 := &context{"argument", "", parse.Bareword, range0(.Range().To)}
			 := purelyEvalForm(, "", .Range().To, )
			,  := .ArgGenerator()
			return , , 
		}
	}
	if ,  := .(*parse.Primary);  {
		if ,  := primaryInSimpleCompound(, );  != nil {
			if ,  := parent().(*parse.Form);  {
				if .Head != nil && .Head !=  {
					// Case 2: in an incomplete argument.
					 := &context{"argument", , .Type, .Range()}
					 := purelyEvalForm(, , .Range().From, )
					,  := .ArgGenerator()
					return , , 
				}
			}
		}
	}
	return nil, nil, errNoCompletion
}

func ( parse.Node,  Config) (*context, []RawItem, error) {
	 := .PureEvaler
	 := func( int) (*context, []RawItem, error) {
		 := &context{"command", "", parse.Bareword, range0()}
		,  := generateCommands("", )
		return , , 
	}

	if is(, aChunk) {
		// Case 1: The leaf is a Chunk. That means that the chunk is empty
		// (nothing entered at all) and it is a correct place for completing a
		// command.
		return (.Range().To)
	}
	if is(, aSep) {
		 := parent()
		switch {
		case is(, aChunk), is(, aPipeline):
			// Case 2: Just after a newline, semicolon, or a pipe.
			return (.Range().To)
		case is(, aPrimary):
			 := .(*parse.Primary).Type
			if  == parse.OutputCapture ||  == parse.ExceptionCapture {
				// Case 3: At the beginning of output or exception capture.
				return (.Range().To)
			}
		}
	}

	if ,  := .(*parse.Primary);  {
		if ,  := primaryInSimpleCompound(, );  != nil {
			if ,  := parent().(*parse.Form);  {
				if .Head ==  {
					// Case 4: At an already started command.
					 := &context{
						"command", , .Type, .Range()}
					,  := generateCommands(, )
					return , , 
				}
			}
		}
	}
	return nil, nil, errNoCompletion
}

// NOTE: This now only supports a single level of indexing; for instance,
// $a[<Tab> is supported, but $a[x][<Tab> is not.
func ( parse.Node,  Config) (*context, []RawItem, error) {
	 := .PureEvaler
	 := func( interface{},  int) (*context, []RawItem, error) {
		 := &context{"index", "", parse.Bareword, range0()}
		return , generateIndices(), nil
	}

	if is(, aSep) {
		if is(parent(), aIndexing) {
			// We are just after an opening bracket.
			 := parent().(*parse.Indexing)
			if len(.Indicies) == 1 {
				if  := .PurelyEvalPrimary(.Head);  != nil {
					return (, .Range().To)
				}
			}
		}
		if is(parent(), aArray) {
			 := parent()
			if is(parent(), aIndexing) {
				// We are after an existing index and spaces.
				 := parent().(*parse.Indexing)
				if len(.Indicies) == 1 {
					if  := .PurelyEvalPrimary(.Head);  != nil {
						return (, .Range().To)
					}
				}
			}
		}
	}

	if is(, aPrimary) {
		 := .(*parse.Primary)
		,  := primaryInSimpleCompound(, )
		if  != nil {
			if is(parent(), aArray) {
				 := parent()
				if is(parent(), aIndexing) {
					// We are just after an incomplete index.
					 := parent().(*parse.Indexing)
					if len(.Indicies) == 1 {
						if  := .PurelyEvalPrimary(.Head);  != nil {
							 := &context{
								"index", , .Type, .Range()}
							return , generateIndices(), nil
						}
					}
				}
			}
		}
	}
	return nil, nil, errNoCompletion
}

func ( parse.Node,  Config) (*context, []RawItem, error) {
	 := .PureEvaler
	if is(, aSep) {
		if is(parent(), aRedir) {
			// Empty redirection target.
			 := &context{"redir", "", parse.Bareword, range0(.Range().To)}
			,  := generateFileNames("", false)
			return , , 
		}
	}
	if ,  := .(*parse.Primary);  {
		if ,  := primaryInSimpleCompound(, );  != nil {
			if is(parent(), &parse.Redir{}) {
				// Non-empty redirection target.
				 := &context{
					"redir", , .Type, .Range()}
				,  := generateFileNames(, false)
				return , , 
			}
		}
	}
	return nil, nil, errNoCompletion
}

func ( parse.Node,  Config) (*context, []RawItem, error) {
	 := .PureEvaler
	,  := .(*parse.Primary)
	if ! || .Type != parse.Variable {
		return nil, nil, errNoCompletion
	}
	,  := eval.SplitSigil(.Value)
	,  := eval.SplitIncompleteQNameNs()
	// Move past "$", "@" and "<ns>:".
	 := .Range().From + 1 + len() + len()

	 := &context{
		"variable", , parse.Bareword,
		diag.Ranging{From: , To: .Range().To}}

	var  []RawItem
	.EachVariableInNs(, func( string) {
		 = append(, noQuoteItem(parse.QuoteVariableName()))
	})

	.EachNs(func( string) {
		// This is to match namespaces that are "nested" under the current
		// namespace.
		if hasProperPrefix(, ) {
			 = append(, noQuoteItem(parse.QuoteVariableName([len():])))
		}
	})

	return , , nil
}

func ( int) diag.Ranging {
	return diag.Ranging{From: , To: }
}

func (,  string) bool {
	return len() > len() && strings.HasPrefix(, )
}