package regexp2

import (
	
	

	
)

const (
	replaceSpecials     = 4
	replaceLeftPortion  = -1
	replaceRightPortion = -2
	replaceLastGroup    = -3
	replaceWholeString  = -4
)

// MatchEvaluator is a function that takes a match and returns a replacement string to be used
type MatchEvaluator func(Match) string

// Three very similar algorithms appear below: replace (pattern),
// replace (evaluator), and split.

// Replace Replaces all occurrences of the regex in the string with the
// replacement pattern.
//
// Note that the special case of no matches is handled on its own:
// with no matches, the input string is returned unchanged.
// The right-to-left case is split out because StringBuilder
// doesn't handle right-to-left string building directly very well.
func replace( *Regexp,  *syntax.ReplacerData,  MatchEvaluator,  string, ,  int) (string, error) {
	if  < -1 {
		return "", errors.New("Count too small")
	}
	if  == 0 {
		return "", nil
	}

	,  := .FindStringMatchStartingAt(, )

	if  != nil {
		return "", 
	}
	if  == nil {
		return , nil
	}

	 := &bytes.Buffer{}
	 := .text

	if !.RightToLeft() {
		 := 0
		for  != nil {
			if .Index !=  {
				.WriteString(string([:.Index]))
			}
			 = .Index + .Length
			if  == nil {
				replacementImpl(, , )
			} else {
				.WriteString((*))
			}

			--
			if  == 0 {
				break
			}
			,  = .FindNextMatch()
			if  != nil {
				return "", nil
			}
		}

		if  < len() {
			.WriteString(string([:]))
		}
	} else {
		 := len()
		var  []string

		for  != nil {
			if .Index+.Length !=  {
				 = append(, string([.Index+.Length:]))
			}
			 = .Index
			if  == nil {
				replacementImplRTL(, &, )
			} else {
				 = append(, (*))
			}

			--
			if  == 0 {
				break
			}
			,  = .FindNextMatch()
			if  != nil {
				return "", nil
			}
		}

		if  > 0 {
			.WriteString(string([:]))
		}

		for  := len() - 1;  >= 0; -- {
			.WriteString([])
		}
	}

	return .String(), nil
}

// Given a Match, emits into the StringBuilder the evaluated
// substitution pattern.
func replacementImpl( *syntax.ReplacerData,  *bytes.Buffer,  *Match) {
	for ,  := range .Rules {

		if  >= 0 { // string lookup
			.WriteString(.Strings[])
		} else if  < -replaceSpecials { // group lookup
			.groupValueAppendToBuf(-replaceSpecials-1-, )
		} else {
			switch -replaceSpecials - 1 -  { // special insertion patterns
			case replaceLeftPortion:
				for  := 0;  < .Index; ++ {
					.WriteRune(.text[])
				}
			case replaceRightPortion:
				for  := .Index + .Length;  < len(.text); ++ {
					.WriteRune(.text[])
				}
			case replaceLastGroup:
				.groupValueAppendToBuf(.GroupCount()-1, )
			case replaceWholeString:
				for  := 0;  < len(.text); ++ {
					.WriteRune(.text[])
				}
			}
		}
	}
}

func replacementImplRTL( *syntax.ReplacerData,  *[]string,  *Match) {
	 := *
	 := &bytes.Buffer{}

	for ,  := range .Rules {
		.Reset()
		if  >= 0 { // string lookup
			 = append(, .Strings[])
		} else if  < -replaceSpecials { // group lookup
			.groupValueAppendToBuf(-replaceSpecials-1-, )
			 = append(, .String())
		} else {
			switch -replaceSpecials - 1 -  { // special insertion patterns
			case replaceLeftPortion:
				for  := 0;  < .Index; ++ {
					.WriteRune(.text[])
				}
			case replaceRightPortion:
				for  := .Index + .Length;  < len(.text); ++ {
					.WriteRune(.text[])
				}
			case replaceLastGroup:
				.groupValueAppendToBuf(.GroupCount()-1, )
			case replaceWholeString:
				for  := 0;  < len(.text); ++ {
					.WriteRune(.text[])
				}
			}
			 = append(, .String())
		}
	}

	* = 
}