package d2ir

import (
	

	
)

func ( *Map) ( []string,  func(*Field) bool) ([]*Field, bool) {
	var  []*Field
	if d2ast.IsDoubleGlob() {
		._doubleGlob(&, )
		return , true
	}
	if d2ast.IsTripleGlob() {
		._tripleGlob(&, )
		return , true
	}
	return nil, false
}

// pathToField returns the source-ordered field path from m to target. A nil
// result means target is outside m's subtree.
func ( *Map) ( *Field) []*Field {
	var  []*Field
	for  := ;  != nil; {
		 := ParentMap()
		if  == nil {
			return nil
		}
		 = append(, )
		if  ==  {
			 := make([]*Field, len())
			for  := range  {
				[len()-1-] = []
			}
			return 
		}
		 = ParentField()
	}
	return nil
}

func ( *Map) ( *Field) *Field {
	 := .pathToField()
	if len() == 0 {
		return nil
	}
	return [0]
}

// multiGlobMatchesToward returns the fields in the changed top-level branch
// toward target that the existing recursive glob traversal would append. A
// whole branch is replayed (rather than only the target path) so reference and
// filter ordering remains identical within the affected branch.
func ( *Map) ( *Field,  []string,  func(*Field) bool) []*Field {
	 := .pathToField()
	if len() == 0 {
		return nil
	}
	var  []*Field
	if d2ast.IsDoubleGlob() {
		_doubleGlobField([0], &, )
		return 
	}
	if d2ast.IsTripleGlob() {
		_tripleGlobField([0], &, )
		return 
	}
	return nil
}

func _doubleGlobField( *Field,  *[]*Field,  func(*Field) bool) bool {
	if  == nil || .Name == nil {
		return true
	}
	if  != nil && !() {
		return false
	}
	 := .Name.ScalarString()
	if ,  := d2ast.ReservedKeywords[];  && .Name.IsUnquoted() {
		if skipDoubleGlobSubtree() {
			return true
		}
		if .Map() != nil {
			return .Map()._doubleGlob(, )
		}
		return true
	}
	if NodeBoardKind() == "" {
		* = append(*, )
	}
	if .Map() != nil {
		return .Map()._doubleGlob(, )
	}
	return true
}

func skipDoubleGlobSubtree( string) bool {
	if ,  := d2ast.BoardKeywords[];  {
		return true
	}
	// Classes and variables are definitions, not diagram objects. Applying
	// recursive globs inside either map can mutate definitions before use.
	return  == "classes" ||  == "vars"
}

func _tripleGlobField( *Field,  *[]*Field,  func(*Field) bool) bool {
	if  == nil || .Name == nil {
		return true
	}
	if  != nil && !() {
		return false
	}
	 := .Name.ScalarString()
	if ,  := d2ast.ReservedKeywords[];  && .Name.IsUnquoted() {
		if ,  := d2ast.BoardKeywords[]; ! {
			return true
		}
		if .Map() != nil {
			return .Map()._tripleGlob(, )
		}
		return true
	}
	if NodeBoardKind() == "" {
		* = append(*, )
	}
	if .Map() != nil {
		return .Map()._tripleGlob(, )
	}
	return true
}

func ( *Map) ( *[]*Field,  func(*Field) bool) bool {
	for ,  := range .Fields {
		if  != nil && !() {
			return false
		}
		if .Name == nil {
			continue
		}
		 := .Name.ScalarString()
		if ,  := d2ast.ReservedKeywords[];  && .Name.IsUnquoted() {
			if skipDoubleGlobSubtree() {
				continue
			}
			if .Map() != nil {
				if !.Map().(, ) {
					return false
				}
			}
			continue
		}
		if NodeBoardKind() == "" {
			* = append(*, )
		}
		if .Map() != nil {
			if !.Map().(, ) {
				return false
			}
		}
	}
	return true
}

func ( *Map) ( *[]*Field,  func(*Field) bool) bool {
	for ,  := range .Fields {
		if  != nil && !() {
			return false
		}
		if  == nil || .Name == nil {
			continue
		}
		if ,  := d2ast.ReservedKeywords[.Name.ScalarString()];  && .Name.IsUnquoted() {
			if ,  := d2ast.BoardKeywords[.Name.ScalarString()]; ! {
				continue
			}
			// We don't ever want to append layers, scenarios or steps directly.
			if .Map() != nil {
				if !.Map().(, ) {
					return false
				}
			}
			continue
		}
		if NodeBoardKind() == "" {
			* = append(*, )
		}
		if .Map() != nil {
			if !.Map().(, ) {
				return false
			}
		}
	}
	return true
}

func matchPattern( string,  []string) bool {
	if len() == 0 {
		return true
	}
	if ,  := d2ast.ReservedKeywords[];  {
		return false
	}

	for  := 0;  < len(); ++ {
		if [] == "*" {
			if  == len()-1 {
				return true
			}

			 := strings.ToLower([+1])
			 := strings.ToLower()
			if +1 == len()-1 {
				return strings.HasSuffix(, )
			}

			// Match the earliest occurrence so the remaining wildcards have the
			// largest possible suffix to search.
			 := strings.Index(, )
			if  == -1 {
				return false
			}
			 = [+len([+1]):]
			++
		} else {
			if !strings.HasPrefix(strings.ToLower(), strings.ToLower([])) {
				return false
			}
			 = [len([]):]
		}
	}
	return  == ""
}