// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.

package uritemplate

import (
	
	
	
)

type matcher struct {
	prog *prog

	list1   threadList
	list2   threadList
	matched bool
	cap     map[string][]int

	input string
}

func ( *matcher) ( int) (rune, int, bool) {
	if  := len(.input);  <  {
		 := .input[]
		if  < utf8.RuneSelf {
			return rune(), 1, +1 < 
		}
		,  := utf8.DecodeRuneInString(.input[:])
		return , , + < 
	}
	return -1, 0, false
}

func ( *matcher) ( *threadList,  uint32,  int,  bool,  map[string][]int) {
	if  := .sparse[];  < uint32(len(.dense)) && .dense[].pc ==  {
		return
	}

	 := len(.dense)
	.dense = .dense[:+1]
	.sparse[] = uint32()

	 := &.dense[]
	.pc = 
	.t = nil

	 := &.prog.op[]
	switch .code {
	default:
		panic("unhandled opcode")
	case opRune, opRuneClass, opEnd:
		.t = &thread{
			op:  &.prog.op[],
			cap: make(map[string][]int, len(.cap)),
		}
		for ,  := range  {
			.t.cap[] = make([]int, len())
			copy(.t.cap[], )
		}
	case opLineBegin:
		if  == 0 {
			.(, +1, , , )
		}
	case opLineEnd:
		if ! {
			.(, +1, , , )
		}
	case opCapStart, opCapEnd:
		 := make(map[string][]int, len(.cap))
		for ,  := range  {
			[] = make([]int, len())
			copy([], )
		}
		[.name] = append([.name], )
		.(, +1, , , )
	case opSplit:
		.(, +1, , , )
		.(, .i, , , )
	case opJmp:
		.(, .i, , , )
	case opJmpIfNotDefined:
		.(, +1, , , )
		.(, .i, , , )
	case opJmpIfNotFirst:
		.(, +1, , , )
		.(, .i, , , )
	case opJmpIfNotEmpty:
		.(, .i, , , )
		.(, +1, , , )
	case opNoop:
		.(, +1, , , )
	}
}

func ( *matcher) ( *threadList,  *threadList,  rune,  int,  int,  bool) {
	debug.Printf("===== %q =====", string())
	for  := 0;  < len(.dense); ++ {
		 := .dense[]
		if debug {
			var  bytes.Buffer
			dumpProg(&, .prog, .pc)
			debug.Printf("\n%s", .String())
		}
		if .t == nil {
			continue
		}

		 := .t
		 := .op
		switch .code {
		default:
			panic("unhandled opcode")
		case opRune:
			if .r ==  {
				.add(, .pc+1, , , .cap)
			}
		case opRuneClass:
			 := false
			if ! && .rc&runeClassU == runeClassU {
				 =  || unicode.Is(rangeUnreserved, )
			}
			if ! && .rc&runeClassR == runeClassR {
				 =  || unicode.Is(rangeReserved, )
			}
			if ! && .rc&runeClassPctE == runeClassPctE {
				 =  || unicode.Is(unicode.ASCII_Hex_Digit, )
			}
			if  {
				.add(, .pc+1, , , .cap)
			}
		case opEnd:
			.matched = true
			for ,  := range .cap {
				.cap[] = make([]int, len())
				copy(.cap[], )
			}
			.dense = .dense[:0]
		}
	}
	.dense = .dense[:0]
}

func ( *matcher) () bool {
	 := 0
	,  := &.list1, &.list2
	for {
		if len(.dense) == 0 && .matched {
			break
		}
		, ,  := .at()
		if !.matched {
			.add(, 0, , , .cap)
		}
		.step(, , , , +, )

		if  < 1 {
			break
		}
		 += 

		,  = , 
	}
	return .matched
}

func ( *Template) ( string) Values {
	.mu.Lock()
	if .prog == nil {
		 := compiler{}
		.init()
		.compile()
		.prog = .prog
	}
	 := .prog
	.mu.Unlock()

	 := len(.op)
	 := matcher{
		prog: ,
		list1: threadList{
			dense:  make([]threadEntry, 0, ),
			sparse: make([]uint32, ),
		},
		list2: threadList{
			dense:  make([]threadEntry, 0, ),
			sparse: make([]uint32, ),
		},
		cap:   make(map[string][]int, .numCap),
		input: ,
	}
	if !.match() {
		return nil
	}

	 := make(Values, len(.cap))
	for ,  := range .cap {
		 := Value{V: make([]string, len()/2)}
		for  := range .V {
			.V[] = pctDecode([[2*]:[2*+1]])
		}
		if len(.V) == 1 {
			.T = ValueTypeString
		} else {
			.T = ValueTypeList
		}
		[] = 
	}
	return 
}