package textmeasure

import (
	
	
	
	

	
	
)

func ( string,  map[string]string) string {
	, ,  := ReplaceSubstitutionsMarkdownBounded(context.Background(), , , int64(^uint64(0)>>1))
	if  != nil {
		return 
	}
	return 
}

// ReplaceSubstitutionsMarkdownBounded replaces variables outside Markdown code
// spans and blocks while bounding candidate-match work and bytes inserted by
// replacements. It checks the bound before each allocating replacement.
func ( context.Context,  string,  map[string]string,  int64) (string, int64, error) {
	if  == nil {
		 = context.Background()
	}
	if  < 0 {
		return "", 0, errors.New("negative Markdown substitution expansion limit")
	}
	if  := .Err();  != nil {
		return "", 0, 
	}
	if len() == 0 || !strings.Contains(, "${") {
		return , 0, nil
	}
	,  := newMarkdownSubstitutionMatcher(, )
	if  != nil {
		return "", 0, 
	}
	 := []byte()
	 := text.NewReader()
	 := markdownRenderer.Parser().Parse()

	type  struct {
		  int
		   int
		 string
	}
	var  []
	var  int64
	var  error

	 = ast.Walk(, func( ast.Node,  bool) (ast.WalkStatus, error) {
		if  := .Err();  != nil {
			return ast.WalkStop, 
		}
		if ! {
			return ast.WalkContinue, nil
		}

		if isCodeNode() {
			return ast.WalkSkipChildren, nil
		}

		if ,  := .(*ast.Text);  {
			 := .Segment
			 := string(.Value())
			, ,  := .replaceBounded(, , -)
			if  != nil {
				 = 
				return ast.WalkStop, 
			}
			 += 

			if  !=  {
				 = append(, {
					:  .Start,
					:   .Stop,
					: ,
				})
			}
		}
		return ast.WalkContinue, nil
	})
	if  != nil {
		if  != nil {
			return "", 0, 
		}
		return "", 0, 
	}

	if len() == 0 {
		return , , nil
	}

	sort.Slice(, func(,  int) bool {
		return []. < [].
	})

	 := len()
	for ,  := range  {
		 += len(.) - (. - .)
	}
	var  strings.Builder
	.Grow()
	 := 0
	for ,  := range  {
		.Write([:.])
		.WriteString(.)
		 = .
	}
	.Write([:])

	return .String(), , nil
}

func isCodeNode( ast.Node) bool {
	switch .Kind() {
	case ast.KindCodeBlock, ast.KindFencedCodeBlock, ast.KindCodeSpan:
		return true
	}
	return false
}

type markdownSubstitutionState struct {
	next          map[byte]int
	fail          int
	outputLink    int
	terminal      bool
	patternLength int
	value         string
}

type markdownSubstitutionMatcher struct {
	states []markdownSubstitutionState
}

func newMarkdownSubstitutionMatcher( context.Context,  map[string]string) (*markdownSubstitutionMatcher, error) {
	if  == nil {
		 = context.Background()
	}
	if  := .Err();  != nil {
		return nil, 
	}
	 := &markdownSubstitutionMatcher{
		states: []markdownSubstitutionState{{outputLink: -1}},
	}
	// Build one byte-oriented Aho-Corasick matcher for the whole Markdown
	// document. Complete ${key} patterns are necessary because quoted D2
	// variable names may themselves contain a closing brace.
	 := .states
	for ,  := range  {
		if  := .Err();  != nil {
			return nil, 
		}
		 := "${" +  + "}"
		 := 0
		for  := 0;  < len(); ++ {
			if &1023 == 0 {
				if  := .Err();  != nil {
					return nil, 
				}
			}
			,  := [].next[[]]
			if ! {
				 = len()
				if [].next == nil {
					[].next = make(map[byte]int)
				}
				[].next[[]] = 
				 = append(, markdownSubstitutionState{outputLink: -1})
			}
			 = 
		}
		[].terminal = true
		[].patternLength = len()
		[].value = 
	}

	 := make([]int, 0, len()-1)
	for ,  := range [0].next {
		 = append(, )
	}
	for  := 0;  < len(); ++ {
		if  := .Err();  != nil {
			return nil, 
		}
		 := []
		for ,  := range [].next {
			 := [].fail
			for  != 0 {
				if ,  := [].next[];  {
					break
				}
				 = [].fail
			}
			if ,  := [].next[];  {
				[].fail = 
			}
			 = [].fail
			if [].terminal {
				[].outputLink = 
			} else {
				[].outputLink = [].outputLink
			}
			 = append(, )
		}
	}
	.states = 
	return , nil
}

func ( *markdownSubstitutionMatcher) ( context.Context,  string,  int64) (string, int64, error) {
	type  struct {
		 int
		  int
		 string
	}
	if  == nil {
		 = context.Background()
	}
	if  < 0 {
		return "", 0, errors.New("negative Markdown substitution expansion limit")
	}
	if  := .Err();  != nil {
		return "", 0, 
	}
	if len() == 0 ||  == nil || len(.states) == 0 {
		return , 0, nil
	}
	 := .states
	var  map[int]
	var  int64
	 := 0
	for  := 0;  < len(); ++ {
		if &1023 == 0 {
			if  := .Err();  != nil {
				return "", 0, 
			}
		}
		 := []
		for  != 0 {
			if ,  := [].next[];  {
				break
			}
			 = [].fail
		}
		if ,  := [].next[];  {
			 = 
		} else {
			 = 0
		}

		for  := ;  != -1;  = [].outputLink {
			 := []
			if !.terminal {
				continue
			}
			if  >=  {
				return "", 0, errors.New("Markdown substitution expansion limit exceeded")
			}
			++
			if &1023 == 0 {
				if  := .Err();  != nil {
					return "", 0, 
				}
			}
			 :=  + 1 - .patternLength
			if  < 0 {
				continue
			}
			 :=  + 1
			,  := []
			if ! || - > .-. {
				if  == nil {
					 = make(map[int])
				}
				[] = {: , : , : .value}
			}
		}
	}

	var  []
	for  := 0;  < len(); {
		if &1023 == 0 {
			if  := .Err();  != nil {
				return "", 0, 
			}
		}
		,  := []
		if ! {
			++
			continue
		}
		if int64(len(.)) > - {
			return "", 0, errors.New("Markdown substitution expansion limit exceeded")
		}
		 += int64(len(.))
		 = append(, )
		 = .
	}
	if len() == 0 {
		return , 0, nil
	}

	 := len()
	const  = int(^uint(0) >> 1)
	for ,  := range  {
		 := len(.) - (. - .)
		if  > 0 &&  > - {
			return "", 0, errors.New("Markdown substitution result is too large")
		}
		 += 
	}
	var  strings.Builder
	.Grow()
	 := 0
	for ,  := range  {
		if  := .Err();  != nil {
			return "", 0, 
		}
		.WriteString([:.])
		.WriteString(.)
		 = .
	}
	.WriteString([:])
	return .String(), , nil
}