package regexp2

import (
	
	
)

// Match is a single regex result match that contains groups and repeated captures
//
//		-Groups
//	   -Capture
type Match struct {
	Group //embeded group 0

	regex       *Regexp
	otherGroups []Group

	// input to the match
	textpos   int
	textstart int

	capcount   int
	caps       []int
	sparseCaps map[int]int

	// output from the match
	matches    [][]int
	matchcount []int

	// whether we've done any balancing with this match.  If we
	// have done balancing, we'll need to do extra work in Tidy().
	balancing bool
}

// Group is an explicit or implit (group 0) matched group within the pattern
type Group struct {
	Capture // the last capture of this group is embeded for ease of use

	Name     string    // group name
	Captures []Capture // captures of this group
}

// Capture is a single capture of text within the larger original string
type Capture struct {
	// the original string
	text []rune
	// Index is the position in the underlying rune slice where the first character of
	// captured substring was found. Even if you pass in a string this will be in Runes.
	Index int
	// Length is the number of runes in the captured substring.
	Length int
}

// String returns the captured text as a String
func ( *Capture) () string {
	return string(.text[.Index : .Index+.Length])
}

// Runes returns the captured text as a rune slice
func ( *Capture) () []rune {
	return .text[.Index : .Index+.Length]
}

func newMatch( *Regexp,  int,  []rune,  int) *Match {
	 := Match{
		regex:      ,
		matchcount: make([]int, ),
		matches:    make([][]int, ),
		textstart:  ,
		balancing:  false,
	}
	.Name = "0"
	.text = 
	.matches[0] = make([]int, 2)
	return &
}

func newMatchSparse( *Regexp,  map[int]int,  int,  []rune,  int) *Match {
	 := newMatch(, , , )
	.sparseCaps = 
	return 
}

func ( *Match) ( []rune,  int) {
	.text = 
	.textstart = 
	for  := 0;  < len(.matchcount); ++ {
		.matchcount[] = 0
	}
	.balancing = false
}

func ( *Match) ( int) {

	 := .matches[0]
	.Index = [0]
	.Length = [1]
	.textpos = 
	.capcount = .matchcount[0]
	//copy our root capture to the list
	.Group.Captures = []Capture{.Group.Capture}

	if .balancing {
		// The idea here is that we want to compact all of our unbalanced captures.  To do that we
		// use j basically as a count of how many unbalanced captures we have at any given time
		// (really j is an index, but j/2 is the count).  First we skip past all of the real captures
		// until we find a balance captures.  Then we check each subsequent entry.  If it's a balance
		// capture (it's negative), we decrement j.  If it's a real capture, we increment j and copy
		// it down to the last free position.
		for  := 0;  < len(.matchcount); ++ {
			 := .matchcount[] * 2
			 := .matches[]

			var ,  int

			for  = 0;  < ; ++ {
				if [] < 0 {
					break
				}
			}

			for  = ;  < ; ++ {
				if [] < 0 {
					// skip negative values
					--
				} else {
					// but if we find something positive (an actual capture), copy it back to the last
					// unbalanced position.
					if  !=  {
						[] = []
					}
					++
				}
			}

			.matchcount[] =  / 2
		}

		.balancing = false
	}
}

// isMatched tells if a group was matched by capnum
func ( *Match) ( int) bool {
	return  < len(.matchcount) && .matchcount[] > 0 && .matches[][.matchcount[]*2-1] != (-3+1)
}

// matchIndex returns the index of the last specified matched group by capnum
func ( *Match) ( int) int {
	 := .matches[][.matchcount[]*2-2]
	if  >= 0 {
		return 
	}

	return .matches[][-3-]
}

// matchLength returns the length of the last specified matched group by capnum
func ( *Match) ( int) int {
	 := .matches[][.matchcount[]*2-1]
	if  >= 0 {
		return 
	}

	return .matches[][-3-]
}

// Nonpublic builder: add a capture to the group specified by "c"
func ( *Match) (, ,  int) {

	if .matches[] == nil {
		.matches[] = make([]int, 2)
	}

	 := .matchcount[]

	if *2+2 > len(.matches[]) {
		 := .matches[]
		 := make([]int, *8)
		copy(, [:*2])
		.matches[] = 
	}

	.matches[][*2] = 
	.matches[][*2+1] = 
	.matchcount[] =  + 1
	//log.Printf("addMatch: c=%v, i=%v, l=%v ... matches: %v", c, start, l, m.matches)
}

// Nonpublic builder: Add a capture to balance the specified group.  This is used by the
//
//	balanced match construct. (?<foo-foo2>...)
//
// If there were no such thing as backtracking, this would be as simple as calling RemoveMatch(c).
// However, since we have backtracking, we need to keep track of everything.
func ( *Match) ( int) {
	.balancing = true

	// we'll look at the last capture first
	 := .matchcount[]
	 := *2 - 2

	// first see if it is negative, and therefore is a reference to the next available
	// capture group for balancing.  If it is, we'll reset target to point to that capture.
	if .matches[][] < 0 {
		 = -3 - .matches[][]
	}

	// move back to the previous capture
	 -= 2

	// if the previous capture is a reference, just copy that reference to the end.  Otherwise, point to it.
	if  >= 0 && .matches[][] < 0 {
		.addMatch(, .matches[][], .matches[][+1])
	} else {
		.addMatch(, -3-, -4- /* == -3 - (target + 1) */)
	}
}

// Nonpublic builder: removes a group match by capnum
func ( *Match) ( int) {
	.matchcount[]--
}

// GroupCount returns the number of groups this match has matched
func ( *Match) () int {
	return len(.matchcount)
}

// GroupByName returns a group based on the name of the group, or nil if the group name does not exist
func ( *Match) ( string) *Group {
	 := .regex.GroupNumberFromName()
	if  < 0 {
		return nil
	}
	return .GroupByNumber()
}

// GroupByNumber returns a group based on the number of the group, or nil if the group number does not exist
func ( *Match) ( int) *Group {
	// check our sparse map
	if .sparseCaps != nil {
		if ,  := .sparseCaps[];  {
			 = 
		}
	}
	if  >= len(.matchcount) ||  < 0 {
		return nil
	}

	if  == 0 {
		return &.Group
	}

	.populateOtherGroups()

	return &.otherGroups[-1]
}

// Groups returns all the capture groups, starting with group 0 (the full match)
func ( *Match) () []Group {
	.populateOtherGroups()
	 := make([]Group, len(.otherGroups)+1)
	[0] = .Group
	copy([1:], .otherGroups)
	return 
}

func ( *Match) () {
	// Construct all the Group objects first time called
	if .otherGroups == nil {
		.otherGroups = make([]Group, len(.matchcount)-1)
		for  := 0;  < len(.otherGroups); ++ {
			.otherGroups[] = newGroup(.regex.GroupNameFromNumber(+1), .text, .matches[+1], .matchcount[+1])
		}
	}
}

func ( *Match) ( int,  *bytes.Buffer) {
	 := .matchcount[]
	if  == 0 {
		return
	}

	 := .matches[]

	 := [(-1)*2]
	 :=  + [(*2)-1]

	for ;  < ; ++ {
		.WriteRune(.text[])
	}
}

func newGroup( string,  []rune,  []int,  int) Group {
	 := Group{}
	.text = 
	if  > 0 {
		.Index = [(-1)*2]
		.Length = [(*2)-1]
	}
	.Name = 
	.Captures = make([]Capture, )
	for  := 0;  < ; ++ {
		.Captures[] = Capture{
			text:   ,
			Index:  [*2],
			Length: [*2+1],
		}
	}
	//log.Printf("newGroup! capcount %v, %+v", capcount, g)

	return 
}

func ( *Match) () string {
	 := &bytes.Buffer{}
	.WriteRune('\n')
	if len(.sparseCaps) > 0 {
		for ,  := range .sparseCaps {
			fmt.Fprintf(, "Slot %v -> %v\n", , )
		}
	}

	for ,  := range .Groups() {
		fmt.Fprintf(, "Group %v (%v), %v caps:\n", , .Name, len(.Captures))

		for ,  := range .Captures {
			fmt.Fprintf(, "  (%v, %v) %v\n", .Index, .Length, .String())
		}
	}
	/*
		for i := 0; i < len(m.matchcount); i++ {
			fmt.Fprintf(buf, "\nGroup %v (%v):\n", i, m.regex.GroupNameFromNumber(i))

			for j := 0; j < m.matchcount[i]; j++ {
				text := ""

				if m.matches[i][j*2] >= 0 {
					start := m.matches[i][j*2]
					text = m.text[start : start+m.matches[i][j*2+1]]
				}

				fmt.Fprintf(buf, "  (%v, %v) %v\n", m.matches[i][j*2], m.matches[i][j*2+1], text)
			}
		}
	*/
	return .String()
}