package web

import "net/http"

type routeMachine struct {
	sm     stateMachine
	routes []route
}

func matchRoute(route route, m method, ms *method, r *http.Request, c *C) bool {
	if !route.pattern.Match(r, c) {
		return false
	}
	*ms |= route.method

	if route.method&m != 0 {
		route.pattern.Run(r, c)
		return true
	}
	return false
}

func (rm routeMachine) route(c *C, w http.ResponseWriter, r *http.Request) (method, *route) {
	m := httpMethod(r.Method)
	var methods method
	p := r.URL.Path

	if len(rm.sm) == 0 {
		return methods, nil
	}

	var i int
	for {
		sm := rm.sm[i].mode
		if sm&smSetCursor != 0 {
			si := rm.sm[i].i
			p = r.URL.Path[si:]
			i++
			continue
		}

		length := int(sm & smLengthMask)
		match := false
		if length <= len(p) {
			bs := rm.sm[i].bs
			switch length {
			case 3:
				if p[2] != bs[2] {
					break
				}
				fallthrough
			case 2:
				if p[1] != bs[1] {
					break
				}
				fallthrough
			case 1:
				if p[0] != bs[0] {
					break
				}
				fallthrough
			case 0:
				p = p[length:]
				match = true
			}
		}

		if match && sm&smRoute != 0 {
			si := rm.sm[i].i
			if matchRoute(rm.routes[si], m, &methods, r, c) {
				return 0, &rm.routes[si]
			}
			i++
		} else if match != (sm&smJumpOnMatch == 0) {
			if sm&smFail != 0 {
				return methods, nil
			}
			i = int(rm.sm[i].i)
		} else {
			i++
		}
	}
}
